Vue基础
# Vue基础、试图
# 1.VUE框架介绍
# 1.1 VUE官网
VUE 的官网网站地址是 https://cn.VUEjs.org/ (opens new window)
一个用于构建 Web 用户界面的平易近人、高性能且通用的框架。
建立在标准 HTML、CSS 和 JavaScript 之上,具有直观的 API 和世界级的文档。
# 1.2 前端MVC框架
- 前端 MVC 框架 Angular、VUE、React(2015~至今)
- 其实说是 2015 年是不太准确的,主要是在 2015 年之前像 Angular 也是叫 AngularJS,真正的 Angular2 发布是 2016 年五月正式发布。
- 与此同时,VUE 也在 2015 年迎来爆发。 现在很多框架也叫 MVVM 框架(它是 Model-View-ViewModel 的简写),它 其实就是 MVC 框架的改进版
近几年在前端框架上应该不会有太大的改进,更多的是在现有 MVVM 框架做 改进和完善,当前前端框架已趋于稳定,基本上是 Angular
、VUE
、React
三分天 下的局面。
但是,当下前端的辅助工具,如打包工具、运维工具还是没有完备体系,像 Java 早期手工编译到现在各类很成熟的开发工具,几乎需要 15 年的时间沉淀。 相信在未来 5 年时间内,前端需要大量的时间来完善编译类的工具和框架。
# 1.3 VUE的发展历史
VUE.js 是一套构建用户界面的渐进式框架。
与其他重量级框架不同的是,VUE 采用自底向上增量开发的设计。VUE 的核心库只关注视图层,并且非常容易学习, 非常容易与其它库或已有项目整合。另一方面,VUE 完全有能力驱动采用单文件 组件和 VUE 生态系统支持的库开发的复杂单页应用。
VUE.js 自身不是一个全能框架——它只聚焦于视图层。
因此它非常容易学 习,非常容易与其它库或已有项目整合。另一方面,在与相关工具和支持库一起 使用时,VUE.js 也能完美地驱动复杂的单页应用。
尤雨溪在谷歌创意实验室(Google Creative Lab)工作期间,在使用 Angular 的过程中发现 Angular 是一个好东西,于是便开始从 Angular 中抽离一些他平日 工作中用到的一些库,封装方便自己使用,开发出了一款轻量框架,最初命名为 Seed。
- 2013 年 12 月,这粒种子发芽了,更名为 VUE,版本号是 0.6.0。
- 2014.01.24,VUE 正式对外发布,版本号是 0.8.0。
- 2014.02.25 发布 0.9.0 版本,有了自己的代号:Animatrix,这个名字来自 动画版的《骇客帝国》,此后,重要的版本都会有自己的代号。
- 2015.06.13 发布 0.12.0 版本,代号 Dragon Ball(龙珠),这一年,VUE 迎来了大爆发。
- 同年 VUE 发布了几个核心的库,VUE-router(2015-08-18)、VUEx (2015-11-28)、VUE-cli(2015-12-27),标志着 VUE 从一个视图层库发展为 一个渐进式框架。很多前端同学也是从这个版本开始成为 VUE 的用户。
- VUE 的 2.0.0 版本 Ghost in the Shell(攻壳机动队)是第二个重要的里 程碑,它吸收了 React 的 Virtual Dom 方案,还支持服务端渲染。 就在不久前,VUE 发布了 2.6.0 Macross(超时空要塞),这是一个承前启 后的版本。
# 1.4 第一个VUE示例
为了方便快速入门,在 VUE 使用路由之前的示例中,都是直接<script>
引用, VUE.js 这个文件可以到官网下载。
- 下载 vue.js 文件,并放到项目中
- 创建 HTML 页面,并引入 vue.js
- vue.js 所放入的目录是:
/js/vue.js
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
第一个HTML页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01-初识vue.html</title>
<!-- 0、导入vue.js -->
<script src="../js/vue.js"></script>
</head>
<body>
<!-- 1、定义一个容器 -->
<div id="app">
<h3> 第一个vue程序,并使用插值表达式取得值为:{{name}} </h3>
</div>
</body>
<script>
// 去除浏览器控制台中的错误信息
Vue.config.productionTip = false;
// 2、初始化Vue容器
new Vue({
el: "#app",
data: {
name: "张三",
age: "18"
}
})
</script>
</html>
el和data的两种写法
1、el
- (1)、new Vue时配置el选项
- (2)、先创建Vue实例,然后再通过vm.this.$mount( '#app' ) 来指定el的值
2、data
- (1)、对象式
- (2)、函数式
- 如何选择哪种用法:目前都可以,但是后续会玩组件,则:必须用函数式,而且不可以用兰姆达表达式( 即:上面的data:()=>{},否则:会出错 )
3、一个原则
:
- 由Vue管理的函数,一定不要写箭头函数,就上面的兰姆达表达式,否则就会导致this不再是Vue实例了( 这个this有大用处,在"new Vue中"用了this就是指的当前的Vue实例,后续可以通过这个this玩很多东西 )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>04-vue的el和data的两种写法</title>
</head>
<body>
<!-- 被 vm 实例所控制的区域 -->
<div id="app"></div>
<script>
// 创建 vm 实例对象
const vm = new Vue({
//指定控制的区域
// el:'#app', // el 常规写法
// data:{}, // data 常规写法 ———— 这种也叫对象式写法
// data 函数式写法,这种写法后续经常见
data () { // 这里使用data:function(){}也可以,但是:绝对不能写成data:()=>{}
// 因为这种写法变质了,成为Window对象了,这样后续用this指向时,这个this所指代的就不Vue实例了
return {
}
}
});
// el 另外的写法
vm.this.$mount('#app') // 此种写法需要记住,后续组件化开发还会见到
</script>
</body>
</html>
初识Vue小结
- Vue容器中的代码一样符合html规范,只不过是混入了一些Vue的特殊用法而已,这个容器中的代码被称为:
Vue模板
- Vue实例( new Vue处 )和 Vue容器是一 一对应的( 即:一个Vue实例只能对应一个Vue容器 )
- 当然:真实开发中只有一个Vue实例,后续会见到
中的
xxx
要写js
表达式(即为插值表达式,就是取
data
中的东西而已 ),且xxx
可以自动读取到data中的所有属性
# 1.5 VUE的声明周期
beforeCreate
: 实例初始化之后,this 指向创建的实例,不能访问到 data、computed、watch、 methods 上的方法和数据。常用于初始化非响应式变量。Created
: 实例创建完成,可访问 data、computed、watch、methods 上的方法和数据, 未挂载到 DOM,不能访问到$el
属性,$ref
属性内容为空数组。常用于简单的 ajax 请求,页面的初始化。beforeMount
: 在挂载开始之前被调用,beforeMount 之前,会找到对应的 tempiate,并编 译成 render 函数。mounted
: 实例挂载到 DOM 上,此时可以通过 DOM API 获取到 DOM 节点,$ref
属性可以 访问。beforeUpdate
: 响应式数据更新时调用,发生在虚拟 DOM 打补丁之前。适合在更新之前访问 现有的 DOM,比如手动移除已添加的事件监听器。Updated
: 虚拟 DOM 重新渲染和打补丁之后调用,组件 DOM 已经更新,可执行依赖于 DOM 的操作,避免在这个钩子函数中操作数据,可能陷入死循环。beforeDestroy
: 实例销毁之前调用,这一步实例仍然完全可用,this 仍然能获取到实例。常 用于销毁定时器、解绑全局事件、销毁插件对象等操作。Destroyed
: 实例销毁后调用,调用后,VUE 实例指示的所有东西都会解绑定,所有的时 间监听器会被移除,所有的子实例也会被销毁。 另外,还有几个重要的参数:methods
:事件方法定义 watch:监听一个值的变化,然后执行相对应的函数。computed
:计算属性,也就是依赖其它的属性计算所得出最后的值。activated
、deactivated
: 当组件在 keep-alive 内被切换时组件的 activated、deactivated 这两个生 命周期钩子函数会被执行(注意:如果没有引用 keep-alive 标签,这两个函数 不起作用)。
VUE 实例参数完整写法
<head>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<span>{{msg}}{{price | RMPPrice}}</span>
</div>
<script>
//花括号内是 VUE 实例的参数(不常用的不写) 过滤器定义的地方
Vue.filter("RMPPrice",value => {
value = value.toFixed(2);
return value+"元";
});
let vue = new Vue({
el: "#app",
data: {
price: 5985200.65500,
msg: "人民币:"
},
//实例创建完成,一般数据的初始化在这里
created() {
this.show();
},
// 实例挂载完成,一般访问 DOM 可以在这里操作.如 $ref 访问属性
mounted(){
},
//定义方法的地方
methods: {
show() {
console.log('这是 show 函数.')
}
},
//计算属性定义的地方
computed:{
},
//监听定义的地方
watch :{
}
});
</script>
</body>
# 2.VUE数据绑定
# 2.1.VUE模板
数据绑定的第一中方式,两个花括号,用花括号可以绑定任何 VUE。
<div id="app">
<div>普通信息:{{msg}}</div>
<hr>
<div>水果:{{arr}}</div>
<div>水果 1:{{arr[0]}}</div>
<div>水果 2:{{arr[1]}}</div>
<div>水果 3:{{arr[2]}}</div>
<hr>
<div>用户:{{user}}</div>
<div>编号:{{user.id}}</div>
<div>姓名:{{user.name}}</div>
</div>
<script>
new Vue({
el:"#app",
data:{
//普通消息、数组
msg:"普通信息",
arr:["苹果","梨","芒果"],
//对象
user:{
id:1,
name:"张三",
age:23
}
}
});
</script>
# 2.2.v-once
数据改变后绑定的不变 v-once
<div id="app">
<span v-once>v-once 绑定数据,无法改变:{{msg}}</span>
<hr>
<span>没有 v-once 绑定数据,可以改变:{{msg}}</span>
</div>
<script>
let vue = new Vue({
el: "#app",
data: {
msg: "这是 vue 绑定的数据。"
}
});
</script>
# 2.3.表达式
在用花括号绑数据时,在花括号内还可以做数学运算、调用数据的函数。
<div id="app">
<span>num1+num2={{num1+num2}}</span>
<hr>
<span>(num1+num2) * 500 ={{(num1+num2)*500}}</span>
<hr>
<div>{{msg.split(";")}}</div>
</div>
<script>
let vue = new Vue({
el: "#app",
data: {
num1: 10,
num2: 15,
msg: "苹果;香蕉;梨"
}
});
</script>
# 2.4.原始输出 v-html
v-html 是绑定出原始的 HTM
<div id="app">
<span v-html="htmlStr"></span>
</div>
<script>
let vue = new Vue({
el: "#app",
data: {
htmlStr: `<div style="border-style: solid;
width: 300px;
height: 80px;
line-height: 80px;
text-align: center;
border-width: thick;
border-color: #90C9FF;
background-color: aliceblue;">
这是一个 HTML 标签的信息。
</div>`
}
});
</script>
# 2.5. v-bind单向绑定
v-bind(简写:
)是动态绑定属性值,如:id、name、class、等等.
<style>
.red{ color: red;}
.blue{ color: blue;}
</style>
<div id="app">
<div v-bind:id="id">用户 ID:{{id}}</div>
<!--也可以写成如下-->
<!--<div :id="id">用户 ID</div>-->
<hr>
<div :class="redStyle">样式效果:红</div>
<!--同等于-->
<div v-bind:class="blueStyle">样式效果:蓝</div>
</div>
<script>
let vue = new Vue({
el: "#app",
data: {
id:"userID",
redStyle:"red",
blueStyle:"blue"
}
});
</script>
# 2.6.v-model双向绑定
v-model指令可以在表单 input、textarea以及select元素上创建双向数据绑定
它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖,它负责监听 (opens new window)用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>03-v-model</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 单向绑定:绑的是属性 -->
单向绑定:<input type="text" :value="name"> <br/>
<!-- 双向绑定:绑的是值 -->
双向绑定:<input type="text" :myName="name" v-model:value="username"> <br/>
<!-- 双向绑定的简写 因为:model绑的就是值,因此:value可以省掉 -->
双向绑定:<input type="text" :myName="name" v-model="username">
</div>
</body>
<script>
Vue.config.productionTip = false;
new Vue({
el: "#app",
data: {
name: "紫邪情",
username: "邪公子"
}
})
</script>
</html>
# 2.7.class属性绑定
:class
可以动态的控制class的属性。
<style>
.class1{ color: blue; }
.class2{ font-size: 20px; }
.class3{ background-color: #d5e8d0; }
</style>
<div id="app">
<hr>绑数组——属性有多个值的,可以绑数组:
<div class="class1 class2 class3">固定的样式名称</div>
<hr>
<div :class="['class1','class2','class3']">通过 VUE 动态的设置样式
</div>
<hr>绑数组——给样式绑定的数组可以判断其中一个是否显示:
<div :class="[{'class1': action},'class2','class3']">你好,VUE。
</div>
<hr>绑对象——还可以决定哪个样式显示(显示 1,2 的样式):
<div :class="{class1: isStyles[0], class2:isStyles[1],class3:isStyles[2]}">你好VUE。</div>
</div>
<script>
let vue = new Vue({
el: "#app",
data: {
isStyles:[true,true,false],
action:false
}
});
</script>
# 2.8.style属性绑定
以下是对 style 设置对象类型,当然也可以设
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<style>
.basic{
width: 400px;
height: 100px;
border: 1px solid black;
}
.normal{
border: 1px solid black;
background-color: aqua;
}
.happy{
border: 1px solid yellow;
background-color: red;
}
.sad{
border: 1px black solid;
background-color: green;
}
</style>
</head>
<body>
<div id="root">
<div class="basic" :class="mood" @click="changMood">{{name}}</div>
<div class="basic" :style="styleObj">{{name}}</div>
</div>
<script type="text/javascript">
new Vue({
el: '#root',
data:function(){
return {
name: "尚硅谷",
mood: "normal",
styleObj:{
fontSize: '40px',
color: 'red',
}
}
},
methods: {
changMood(){
// 随机绑定样式
const arr = ['happy','sad','normal']
const index = Math.floor(Math.random()*3)
this.mood = arr[index]
}
},
})
</script>
</body>
</html>
# 2.9.条件渲染
条件渲染 v-if、v-else-if、v-else
<div id="app">
<div v-if="flag"><B> {{msg}}</B></div>
条件渲染 v-if、v-else-if、v-else
<hr>
当前分数:{{score}}
<div v-if="score<60">不及格</div>
<div v-else-if="score>=60 && score<70">良好</div>
<div v-else-if="score>=70 && score<90">优秀</div>
<div v-else>优异</div>
</div>
<script>
let vue = new Vue({
el: "#app",
data: {
score : 50,
flag : true,
msg : '信息显示'
}
});
</script>
# 2.10.v-for列表渲染
V-for 和程序中的 for、while 功能一样
遍历对象取值有 3 种方式:
简单遍历,格式:
1. v-for = “value in object “
2. Value、key 都遍历,格式:v-for = “(value, key) in object”
3. Value、key、index 都遍历,格式:v-for = “(value, key, index)
注意:
- 设置了 key 关键字能使 Dom 的每个节点有唯一标识符;
- 数组、对象都可以用 key 关键字;
- 尽可能在使用 v-for 时提供 key 值,除非遍历输出的 DOM 内容非常简单;
- 不要使用 index 作为
<body>
<div id="root">
<button @click="addUser">添加数据</button>
<ul>
<!--这里是使用p.id的方式遍历也是可以的-->
<!--li v-for="p in persons" :key="p.id"-->
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
persons: [
{id:'001',name:'张三',age:18},
{id:'003',name:'李四',age:19},
{id:'003',name:'王五',age:20}
]
},
methods: {
addUser(){
const p = {id:'004',name:'老刘',age:23}
this.persons.push(p)
}
},
})
</script>
</body>
</html>
# 2.11.v-show
v-show 的功能和 HTML
<div id="app">
<div v-show="flag">这是要显示的内容</div>
</div>
<script>
let vue = new Vue({
22
el: "#app",
data: {
flag : true
}
});
</script>
# 3.数据代理
CSDN原创地址: 😻😻 (opens new window)
# 3.1 defineProperty方法
在Vue中,有很多地方使用到了Object.defineProperty
方法,例如数据劫持、数据代理、计算属性等。Object.defineProperty
方法用来给一个对象添加属性,或者修改一个对象上的属性。
它的语法如下:
Object.defineProperty(obj, prop, descriptor)
// obj:要定义属性的对象
// prop:要定义或修改的属性名称或Symbol
// descriptor:要定义或修改的属性描述符
// 返回值:该对象
在默认情况下,使用Object.defineProperty
添加的属性不可以执行枚举、修改等操作,因此需要在descriptor
中添加响应的配置项,配置项具体如下:
配置项 | 描述 |
---|---|
value | 该属性对应的值,可以是任何有效的JavaScript 值(数值,对象,函数等),默认为undefined |
enumerable | 表示该属性是否可以枚举,true为可枚举,默认为false不可枚举 |
writable | 控制属性是否可以被修改,true为可以修改,默认为false |
configurable | 控制属性是否可以被删除,true为可以被删除,默认为false |
get(){} | 属性的getter函数,当访问该属性时,会调用此函数,该函数的返回值会被用作属性的值 |
set(){} | 属性的setter函数,当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),默认为undefined |
示例:使用Object.defineProperty()
方法为person
对象添加一个新属性
let person = {};
Object.defineProperty(person, "name", {
value: "橘猫吃不胖", // name属性值为橘猫吃不胖
enumerable: true, // 属性可以枚举
})
console.log(person) // { name: '橘猫吃不胖' }
person.name = "张三"; // 修改name属性值为张三,结果不能修改
console.log(person) // { name: '橘猫吃不胖' }
delete person.name; // 删除该属性,结果不能删除
console.log(person) // { name: '橘猫吃不胖' }
示例:自定义setter和getter
let person = {};
let str = "橘猫吃不胖";
Object.defineProperty(person, "name", {
get() { // 返回一个字符串
return str;
},
set(value) {
str = value; // 将字符串的值改为最新的值
}
})
console.log(person.name); // 橘猫吃不胖
person.name = "张三";
console.log(person.name); // 张三
# 3.2 什么是数据代理
数据代理就是通过一个对象代理对另一个对象中属性的操作(读/写)。
比如说,有两个对象obj1和obj2,其中obj1中有一个属性x,但是在obj2中可以读取和修改obj1中的属性x,这样就达到了一个数据代理的效果,代码如下:
let obj1 = { x: 100 };
let obj2 = { y: 200 };
// 通过Object.defineProperty()方法为obj2添加属性x
Object.defineProperty(obj2, "x", {
get() { // 读取时返回obj1的x值
return obj1.x;
},
set(value) { // 修改时更改obj1的x值
obj1.x = value;
}
})
以上代码就是最简单的一个数据代理,我们可以通过obj2访问并修改obj1中的x的值,示例如下:
console.log(obj2.x); // 100
console.log(obj1.x); // 100
obj2.x = 150; // 通过obj2修改x的值为150
console.log(obj2.x); // 150
console.log(obj1.x); // 150
# 3.3 Vue中的数据代理
下面一段代码中,我们在data
中定义了name
和age
,然后在页面上使用双大括号{{}}
进行了数据显示。其中,Vue实例vm
的身上会出现name
和age
两个属性。
<div id="app">
<h3>姓名:{{name}}</h3>
<h3>年龄:{{age}}</h3>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
name: "橘猫吃不胖",
age: "2岁"
}
})
</script>
我们在控制台输出一下vm实例,可以看到name和age两个属性,当我们将鼠标悬停在(...)上时,显示了Invoke property getter。通过对Object.defineProperty()方法的了解,我们可以知道name和age两个属性都是通过Object.defineProperty()方法添加上来的。
当访问name
时,是getter在工作,当修改name
时,是setter在工作,因此,在vm
中,我们也可以看到它们的getter和setter方法。
那么我们通过vm
读取与修改name
都是通过读取与修改data
中的name
,这就是一个数据代理。
# 4.补充
# 4.1 Methods
在开发中,我们经常需要用到函数, 通过将一些需要复用的逻辑封装在函数里,多次调用这个函数来达到逻辑代码复用的目的.
在vue中,函数被定义成为方法来使用,这些方法定义在methods属性中,然后就可以在vue 表达式中调用函数
# 4.1 定义方法
vue 选项对象中有一个叫methods的属性.这个属性里面专门来存放一些函数,用来给别人调用
const vm = new Vue({
el: "#app",
data: {
status: 2
},
methods: {
// 这里面是用来存放函数,这里面的函数会自动成为vue实例的方法
statusDoing(id){
var doing = ["睡觉","吃饭","学习Vue"];
return doing[id]
}
}
})
# 4.2 方法的调用
之前有起到过Mastache语法中可以使用JavaScript
表达式,所以我们可以在Mastache语法中调用函数
<div id="app">
{{ statusDoing(status) }}
</div>
# 4.3 方法中的指向
在方法中,this指向该方法所属的实例,可以使用this访问data中的属性或者其他方法
<div id="app">
{{ statusDoing() }}
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
status: 2
},
methods: {
statusDoing(){
var doing = ["睡觉","吃饭","学习Vue"]
// 通过this 获取到实例对象,来拿到data中的数据
return doing[this.status]
}
}
})
</script>
注意, 方法不能使用箭头函数,因为箭头函数的this不是Vue实例, 未来我们在方法中可能会大量使用到Vue实例对象中的属性. 比如获取数据,或者调用其他方法, 如果我们使用了箭头函数就会丢失this,只能通过Vue实例对象来获取
# 4.4 关于方法的响应
使用方法对数据进行过滤
<div id="app">
<!-- 原数组 -->
<h2>原数组</h2>
{{numbers}}
<h2>使用方法过滤后的数组</h2>
{{ filterNum() }}
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
numbers: [10,20,-12,15,-10,22]
},
methods: {
filterNum(){
// 过滤数组函数
return this.numbers.filter((number) => {
return number >= 15
})
}
}
})
</script>