数据绑定
模板
html 中包含了一些 JS 语法代码,语法分为两种,分别为:
插值语法(双大括号表达式)
指令(以 v-开头)
插值语法
1.功能: 用于解析标签体内容
2.语法: {{xxx}}
,xxx 会作为 js 表达式 解析(注意区分 js 代码、表达式、vue 实例对象)
注意:
el 用于指定当前 Vue 实例为哪个容器服务,值通常为 css 选择器字符串。
data 中用于存储数据,数据供 el 所制定的容器去使用。
root 容器里的代码被称为 Vue 模板。
容器与 Vue 实例为一对一关系。
真实开发中只有一个 Vue 实例,并且会配合组件一起使用。
一旦 data 中的数据发生改变,那么模板中用到该数据的地方也会自动更新。
指令语法
功能: 解析标签属性、解析标签体内容、绑定事件
举例:v-bind:href = 'xxxx' ,xxxx 会作为 js 表达式被解析
数据绑定
单向绑定
1.v-bind:href ="xxx" 或简写为 :href
2.数据只能从 data 流向页面
双向绑定
1.语法:v-model:value="xxx" 或简写为 v-model="xxx"
2.特点:数据不仅能从 data 流向页面,还能从页面流向 data
注意:v-model 只能用于表单类元素(输入类元素)
写法示例
<body>
<div id="app">
<p>{{ name }}</p>
<input v-model="age" >
</div>
<script>
const app = new Vue({
data: function () {
return {
name: "Hello",
age: 18
}
}
});
app.$mount("#app")
</script>
</body>
计算与监视属性
computed
1.要显示的数据不存在,要通过计算的来。
2.在 computed 对象中定义计算属性。
3.在页面中使用{{方法名}}
来显示计算结果。
原理:底层借助了 Object.defineProperty 方法提供的 getter 和 setter。
get 函数执行时机:初次读取时会执行一次;当依赖的数据发生改变时会被再次调用。
优势:与 methods 实现相比,内部有缓存机制(复用),效率更高,调试方便。
备注:
1.计算属性最终会出现在 vm 上,直接读取使用即可。
2.如果计算属性要被修改,那必须写 set 函数去响应修改,切 set 中要引起计算时依赖的数据发生改变。
与 methods 对比
1.computed 调用属性,methods 调用函数。
2.computed 具备缓存功能,依赖改变的 data 不变时 computed 属性多次调用内部不会多次执行;methods 不具备缓存功能,调用几次 methods 内部就执行多少次。
watch
1.通过通过 vm 对象的$watch()或 watch 配置来监视指定的属性(data 和 computed 皆可)
2.当属性变化时,handler 回调函数自动调用, 在函数内部进行计算
3.handler 两个参数,newValue 和 oldValue,表示监视 data 修改前后的值
4.immediate 方法,初始化时能让 handler 调用一次
深度监视
1.Vue 中的 watch 默认不监视对象内部值的改变(一层)。
2.配置 deep: true 可以监视对象内部值改变(多层)。
3.Vue 自身可以监视对象内部值的改变,但 Vue 提供的 watch 默认不可以。
4.使用 watch 时根据数据的具体结构,决定是否采用深度监视。
监视简写
不需要 immediate,不需要 deep,仅需要 handler 呈递值改变,可以直接简写。
对象监听时 newValue 和 oldValue 相同的解决方案
原因:因为 newValue 和 oldValue 的栈地址都指向同一个对象,所以 newValue 和 oldValue 在 handler 函数中的值内容是相同的
方案:创建该 data 的 computed 属性,JSON 转译一次之后再监听
<script>
export default {
data: () => ({
obj: { name: "1", age: 12 },
}),
computed: {
watchObj() {
return JSON.parse(JSON.stringify(this.obj));
},
},
watch: {
watchObj: {
deep: true,
handler(newValue, oldValue) {
// 修改obj中的name或age值,触发watchObj的handler执行,newValue和oldValue可以正常显示
console.log("newValue", newValue);
console.log("oldValue", oldValue);
},
},
},
};
</script>
计算与监视对比
1.computed 能完成的功能,watch 都可以完成。
2.操作一个由多个 data 属性集成的属性时,computed 一个函数即可实现,watch 需要对多个属性同时监听才行。
3.watch 能完成的功能,computed 不一定能完成,例如:watch 可以异步操作。
两个重要原则:
1.所有被 Vue 管理的函数,最好写成普通函数,这样在 this 的指向才是 vm 或组件实例对象。
2.所有不被 Vue 管理的函数(定时器的回调函数、ajax 登录回调),最好写成箭头函数,这样 this 的指向才是 vm 或组件实例对象。
样式绑定
class 绑定
1.字符串写法,适用于:样式的类名不确定,需要动态指定。
<div id="app">
<div :class="addObj"></div>
</div>
<script>
new Vue({
el: "#app",
data: {
addObj: "div1",
},
});
Vue.prototype.productionTip = false;
</script>
2.数组写法,适用于:要绑定的样式个数不确定、名字也不确定。
<body>
<div id="app">
<div :class="arrObj"></div>
</div>
<script>
new Vue({
el: "#app",
data: {
arrObj: ["div1","div2","div3"]
},
});
Vue.prototype.productionTip = false;
</script>
</body>
3.对象写法, 适用于:要绑定的样式个数确定、名字也确定,但要动态决定用还是不用
<body>
<div id="app">
<div :class="classObj"></div>
</div>
<script>
new Vue({
el: "#app",
data: {
classObj: {
div1: true,
},
},
});
Vue.prototype.productionTip = false;
</script>
</body>
style 绑定
style 同样有三种写法,但需要注意:
1.:style = "{fontSize: xxx }"
其中 xxx 是动态 data 值。
2.:style = "[a,b]"
其中 a、b 应是样式对象。
3.样式名驼峰命名法
4.对象写法与 class 不同,不支持动态切换,仅在对象中以 key-value 显示样式。
条件渲染
条件渲染指令
1.v-if 与 v-else
(1)v-if="表达式"
(2)v-else-if="表达式"
(3)v-else="表达式"
适用于:切换频率较低的场景。
特点:不展示的 DOM 元素直接被移除。
注意:v-if 可以和 v-else-if、v-else 一起使用,但要求结构不能被“打断”。
v-if 可以搭配<template>
标签使用,template 仅仅用于条件判断来切换内部元素,不破坏 DOM 结构。
2.v-show
写法:v-show="表达式"
适用于:切换频率较高的场景。
特点:不展示的 DOM 元素未被移除,仅仅是使用样式隐藏掉。
3.备注:使用 v-if 的时候,元素可能无法获取到,而是用 v-show 一定可以获取到。
比较 v-if 与 v-show
1.如果需要频繁切换 v-show 较好
2.当条件不成立时, v-if 的所有子节点不会解析(项目中使用)
列表渲染
列表显示指令
遍历数组: v-for / index
遍历对象: v-for / key
特点:
1.用于展示列表数据
2.语法:v-for="(item, index) in xxx" :key="yyy"
3.可遍历:数组、对象、字符串(很少用)、指定次数(很少用)
key 原理
key 的作用
简单地说,key 是虚拟 DOM 对象的标识符,在更新显示时 key 起着极其重要的作用
详细地说,当状态中的数据发生变化时,Vue 会根据【新数据】生成【新的虚拟 DOM】, 随后 Vue 进行【新虚拟 DOM】与【旧虚拟 DOM】的 diff 比较,比较规则如下:
a.旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
(1)若虚拟 DOM 中内容没变,直接使用之前的真实 DOM
(2)若虚拟 DOM 中内容变了,则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM
用 index 作为 key 可能会引发的问题
1.若对数据进行:逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实 DOM 更新,界面效果没问题,但效率低。
2.如果结构中还包含输入类的 DOM:会产生错误 DOM 更新,界面有问题。
3.注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用 index 作为 key 是没有问题的。
开发中如何选择 key
- 最好使用每条数据的唯一标识作为 key,比如 id、手机号、身份证号、学号等唯一值。
- 如果确定只是简单展示数据,用 index 也是可以的。
收集表单数据
text
v-model 收集的是 value 值,用户输入的就是 value 值。
radio
v-model 收集的是 value 值,且要给标签配置 value 值。
checkbox
1.没有配置 input 的 value 属性,那么收集的是 checked(勾选 or 未勾选,布尔值)
2.配置 input 的 value 属性:
(1)v-model 的初始值是非数组,那么收集的是 checked
(2)v-model 的初始值是数组,那么收集的是 value 组成的数组
备注:v-model 三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
过滤器(Vue3 已删除)
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
语法:
1.注册过滤器:Vue.filter(name, callback) 或 new Vue(filters: {})
2.使用过滤器:{{ xxx | 过滤器名 }}
备注:
1.过滤器也可以接收额外参数、多个过滤器也可以串联。
2.并没有改变原本的数据,是产生新的对应数据。
3.功能:对要显示的数据进行特定格式化后
4.注意:并没有改变原本的数据,是产生新的对应数据。
MVVM 模型
M:Model:模型,对应 data 中的数据
V:View:视图,模板
VM:ViewModel:视图模型,Vue 实例对象。

总结:
1.data 中所有的属性,最后都出现在 vm(Vue 实例)身上。
2.vm 身上所有的属性及 Vue 原型上所有属性,在 Vue 模板上都可以直接使用。
数据代理
核心 API:Object.defineProperty(obj, key, value)
声明默认不可枚举、不可修改、不可删除的属性
let sex = "male";
let obj = {
name: "zhangsan",
age: 18,
};
Object.defineProperty(obj, "gender", {
get() {
return sex;
},
set(value) {
sex = value;
},
});
上述示例完成了 sex 变量和 obj.gender 的双向绑定。
真正定义:通过一个对象代理对另一个对象中属性的操作(读/写)
