数据绑定

Misaka10032模板数据绑定MVVM模型数据代理大约 9 分钟

模板

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

  1. 最好使用每条数据的唯一标识作为 key,比如 id、手机号、身份证号、学号等唯一值。
  2. 如果确定只是简单展示数据,用 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 实例对象。

MVVM模型
MVVM模型

总结:

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 的双向绑定。

真正定义:通过一个对象代理对另一个对象中属性的操作(读/写)

数据代理图示
数据代理图示