Vue2 第二弹 —— 数据劫持、生命周期、组件、props
常见问题:react、vue 中的 key 有什么作用?(key的内部原理)
虚拟 DOM 中 key 的作用
key 是虚拟 DOM 对象的标识,当数据发生变化时,Vue 会根据【新数据】生成【新的虚拟 DOM】
随后 Vue 进行【新虚拟 DOM】和【旧虚拟 DOM】的差异比较,比较规则如下:
对比规则:
旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
1. 若虚拟 DOM 内容没变,直接使用之前的真实 DOM!
2. 若虚拟 DOM 中内容变了,则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM。
旧虚拟 DOM 中未找到与新虚拟 DOM 相同的 key
创建新的真实 DOM,随后渲染到页面。
用 index 作为 key 可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实 DOM 更新 ==> 界面效果没问题,但效率低。
- 如果结构中还包含输入类 DOM:会产生错误 DOM 更新 ==> 界面有问题。
开发中如何选择 key?
- 最好使用每条数据的唯一标识作为 key,比如 id、手机号、身份证号、学号等唯一值。
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用 index 作为 key 是没有问题的。
常见问题:Vue 监视数据的原理
Vue 会监视 data 中所有层次的数据。
如何监测对象中的数据?
通过 setter 实现监视,且在 new Vue 时就传入要监测的数据。
- 对象中后追加的属性,Vue 默认不做响应式处理。
- 如需给后追加的属性做响应式,请使用如下 API:
1 | Vue.set(target, propertyName/index, value) 或 vm.$set(target, propertyName/index, value) |
如何监测数组中的数据?
使用 vue 封装的变异方法检测数组数据
原理:通过包裹更新元素的方法实现,本质就是做了两件事:
- 调用原生对应的方法对数组进行更新。
- 重新解析模板,进而更新页面。
在 Vue 中修改数组中的某个元素一定要用如下方法:
- 变异方法: push()、pop()、shift()、unshift()、splice()、sort()、reverse()
- 替换数组:split()、filter()、sort()
- Vue.set(array,index,value) 或 vm.$set(array,index,value)
014 —— 过滤器
定义: 对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
语法:
1. 注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
2. 使用过滤器:`{{ xxx | 过滤器名 }}` 或 v-bind:属性 = "xxx | 过滤器名"
015 —— 内置指令
我们学过的指令
- v-bind:单向绑定解析表达式,可简写成 :xxx
- v-model:双向数据绑定
- v-for:遍历数组/对象/字符串
- v-on:绑定事件监听,可简写成 @xxx
- v-if:条件渲染(动态控制节点是否存在)
- v-else:条件渲染(动态控制节点是否存在)
- v-show:条件渲染(动态控制节点是否显示)
v-text 指令
- 作用:向其所在节点中渲染文本内容。
- 与插值语法的区别:v-text 会替换掉节点中的内容, 则不会。
v-html 指令
- 作用:向指定节点中渲染包含 html 结构的内容。
- 与插值语法的区别:
- v-html 会替换掉节点中所有内容, 则不会。
- v-html 可以识别 html 结构。
- 严重注意:v-html 有安全性问题!!!
- 在网站上动态渲染任意 HTML 是非常危险的,容易导致 XSS 攻击。
- 一定要在可信的内容上使用 v-html,永不要用在用户提交的内容上!
v-cloak 指令(没有值)
- 本质是一个特殊属性,Vue 实例创建完毕并接管容器后,会删掉 v-cloak 属性。
- 使用 css 属性选择器配合 v-cloak 可以解决网速慢时页面展示出 等未解析模板的问题。
v-once 指令
- v-once 所在节点在初次动态渲染后,就视为静态内容了。
- 以后数据的改变不会引起 v-once 所在结构的更新,可以用于优化性能。
v-pre 指令
- 跳过其所在节点的编译过程。
- 可利用它跳过没有使用指令语法、没有使用插值语法的节点,会加快编译。
016 —— 自定义指令
局部指令:
1 | new Vue({ |
全局指令
1 | Vue.directive(指令名,配置对象) |
配置对象中常用的的 3 个回调:
- bind:指令与元素成功绑定时调用。
- insert:指令所在元素被插入页面时调用。
- update:指令所在模板被重新解析时调用。
备注:
- 指令定义时不加 v- 但使用时要加 v-
- 指令名如果是多个单词,要使用 kebab-case 命名方式,不要用 camelCase 命名。
017 —— 生命周期
生命周期:
- 生命周期是 Vue 在关键时刻帮我们调用的一些特殊名称的函数。
- 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
- 生命周期函数的 this 指向的是 vm 或组件实例对象。
常用的生命周期钩子:
- mounted:发送 ajax 请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
- beforeDestroy:清除定时器、解绑自定义事件、取消订阅信息等【收尾工作】
关于销毁 Vue 实例
- 销毁后借助 Vue 开发者工具看不到任何信息。
- 销毁后自定义事件会失效,但原生 DOM 事件依然有效。
- 一般不会在 beforeDestroy 操作数据,因为即使操作数据,也不会再触发更新流程了。
018 —— 组件
Vue 中使用组件的三大步骤:
1. 定义组件(创建组件)
2. 注册组件
3. 使用组件(写组件标签)
一、如何定义一个组件?
使用 Vue.extend(options) 创建
其中的 options 和 new Vue(options) 时传入的 options 几乎一样,但也有点区别:
区别如下:
1. el 不要写,为什么? —— 最终所有组件都要经过一个 vm 的管理,由 vm 的 el 决定服务哪个容器。
2. data 必须写成函数,为什么? —— 避免组件被复用时,数据存在引用关系。
二、如何注册组件?
- 局部注册:靠 new Vue 的时候传入 components 选项
- 全局注册:靠 Vue.component(‘组件名’,组件)
三、编写组件标签
1 | <school></school> |
几个注意点:
1. 关于组件名:
一个单词组成(首字母小写):school
多个单词组成(CamelCase命名):MySchool
2. 关于组件标签
一个单词组成:<school></school>
多个单词组成(kebab-case命名):<my-school></my-school>
3. 注册组件的简写方式:
const school = Vue.extend(options) 可简写为:const school = options
Vue-CLI 脚手架
脚手架文件结构
├─node_modules
├─public
│ ├─favicon.ico:页签图标
│ └─index.html:主页面
├─src
│ ├─assets:存放静态资源
│ │ └─logo.png
│ ├─components:存放组件
│ │ └─HelloWorld.vue
│ ├─App.vue:汇总所有组件
│ └─main.js:入口文件
├─.gitignore:git版本管制忽略的配置
├─babel.config.js:babel的配置文件
├─package.json:应用包配置文件
├─README.md:应用描述文件
└─package-lock.json:包版本控制文件
关于不同版本的 Vue 说明
vue.js 和 vue.runtime.xxx.js 的区别:
- vue.js 是完整版的 Vue,包含:核心功能 + 模板解析器。
- vue.runtime.xxx.js 是运行版的 Vue,只包含核心功能,没有模板解析器。
vue.config.js 配置文件
- 使用 vue inspect > output.js 可以查看到 Vue 脚手架的默认配置。
- 使用 vue.config.js 可以对脚手架进行个性化定制,详情见 https://cli.vuejs.org/zh
ref 属性
概念: 被用来给元素或子组件注册引用信息(id的替代者)
应用在 html 标签上获取的是真实 DOM 元素,应用在组件标签上是组件实例对象(vc)
使用方式:
1
2
3<h1 ref="xxx">...</h1>
或
<School ref="xxx"></School>
获取: this.$refs.xxx
配置项 props
功能:让组件接收外部传进来的数据。
传递数据: 通过在组件标签上添加 key - value 属性
1 | <Demo name="xxx"/> |
接收数据:
1 | 只接收: |
1 | 限制类型: |
1 | 第三种方式(限制类型、限制必要性、指定默认值): |
Vue2 第三弹 —— 事件总线、插槽