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 可能会引发的问题:

  1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实 DOM 更新 ==> 界面效果没问题,但效率低。
  2. 如果结构中还包含输入类 DOM:会产生错误 DOM 更新 ==> 界面有问题。

开发中如何选择 key?

  1. 最好使用每条数据的唯一标识作为 key,比如 id、手机号、身份证号、学号等唯一值。
  2. 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用 index 作为 key 是没有问题的。

常见问题:Vue 监视数据的原理

Vue 会监视 data 中所有层次的数据。

如何监测对象中的数据?
通过 setter 实现监视,且在 new Vue 时就传入要监测的数据。

  1. 对象中后追加的属性,Vue 默认不做响应式处理。
  2. 如需给后追加的属性做响应式,请使用如下 API:
1
Vue.set(target, propertyName/index, value) 或 vm.$set(target, propertyName/index, value)

如何监测数组中的数据?
使用 vue 封装的变异方法检测数组数据
原理:通过包裹更新元素的方法实现,本质就是做了两件事:

  1. 调用原生对应的方法对数组进行更新。
  2. 重新解析模板,进而更新页面。

在 Vue 中修改数组中的某个元素一定要用如下方法:

  1. 变异方法: push()、pop()、shift()、unshift()、splice()、sort()、reverse()
  2. 替换数组:split()、filter()、sort()
  3. Vue.set(array,index,value) 或 vm.$set(array,index,value)

特别注意:Vue.set() 或 vm.$set() 不能给 vm 或 vm 的根数据对象添加属性!!!

014 —— 过滤器

定义: 对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)

语法:

 1. 注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
 2. 使用过滤器:`{{ xxx | 过滤器名 }}` 或 v-bind:属性 = "xxx | 过滤器名"

备注:

  1. 过滤器也可以接收额外的参数、多个过滤器也可以串联。
  2. 并没有改变原本的数据,是产生新的对应的数据。

015 —— 内置指令

我们学过的指令

  1. v-bind:单向绑定解析表达式,可简写成 :xxx
  2. v-model:双向数据绑定
  3. v-for:遍历数组/对象/字符串
  4. v-on:绑定事件监听,可简写成 @xxx
  5. v-if:条件渲染(动态控制节点是否存在)
  6. v-else:条件渲染(动态控制节点是否存在)
  7. v-show:条件渲染(动态控制节点是否显示)

v-text 指令

  1. 作用:向其所在节点中渲染文本内容。
  2. 与插值语法的区别:v-text 会替换掉节点中的内容, 则不会。

v-html 指令

  1. 作用:向指定节点中渲染包含 html 结构的内容。
  2. 与插值语法的区别:
    1. v-html 会替换掉节点中所有内容, 则不会。
    2. v-html 可以识别 html 结构。
  3. 严重注意:v-html 有安全性问题!!!
    1. 在网站上动态渲染任意 HTML 是非常危险的,容易导致 XSS 攻击。
    2. 一定要在可信的内容上使用 v-html,永不要用在用户提交的内容上!

v-cloak 指令(没有值)

  1. 本质是一个特殊属性,Vue 实例创建完毕并接管容器后,会删掉 v-cloak 属性。
  2. 使用 css 属性选择器配合 v-cloak 可以解决网速慢时页面展示出 等未解析模板的问题。

v-once 指令

  1. v-once 所在节点在初次动态渲染后,就视为静态内容了。
  2. 以后数据的改变不会引起 v-once 所在结构的更新,可以用于优化性能。

v-pre 指令

  1. 跳过其所在节点的编译过程。
  2. 可利用它跳过没有使用指令语法、没有使用插值语法的节点,会加快编译。

016 —— 自定义指令

局部指令:

1
2
3
4
5
new Vue({
directives:{指令名:配置对象}
})

new Vue({directives:{指令名:回调函数}})

全局指令

1
2
3
Vue.directive(指令名,配置对象)

Vue.directive(指令名,回调函数)

配置对象中常用的的 3 个回调:

  1. bind:指令与元素成功绑定时调用。
  2. insert:指令所在元素被插入页面时调用。
  3. update:指令所在模板被重新解析时调用。

备注:

  1. 指令定义时不加 v- 但使用时要加 v-
  2. 指令名如果是多个单词,要使用 kebab-case 命名方式,不要用 camelCase 命名。

017 —— 生命周期

生命周期:

  1. 生命周期是 Vue 在关键时刻帮我们调用的一些特殊名称的函数。
  2. 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
  3. 生命周期函数的 this 指向的是 vm 或组件实例对象。

常用的生命周期钩子

  1. mounted:发送 ajax 请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
  2. beforeDestroy:清除定时器、解绑自定义事件、取消订阅信息等【收尾工作】

关于销毁 Vue 实例

  1. 销毁后借助 Vue 开发者工具看不到任何信息。
  2. 销毁后自定义事件会失效,但原生 DOM 事件依然有效。
  3. 一般不会在 beforeDestroy 操作数据,因为即使操作数据,也不会再触发更新流程了。

018 —— 组件

Vue 中使用组件的三大步骤:

  1. 定义组件(创建组件)
  2. 注册组件
  3. 使用组件(写组件标签)

一、如何定义一个组件?
使用 Vue.extend(options) 创建
其中的 options 和 new Vue(options) 时传入的 options 几乎一样,但也有点区别:
区别如下:

  1. el 不要写,为什么? —— 最终所有组件都要经过一个 vm 的管理,由 vm 的 el 决定服务哪个容器。
  2. data 必须写成函数,为什么? —— 避免组件被复用时,数据存在引用关系。

备注:使用 template 可以配置组件结构。

二、如何注册组件?

  1. 局部注册:靠 new Vue 的时候传入 components 选项
  2. 全局注册:靠 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 的区别:

  1. vue.js 是完整版的 Vue,包含:核心功能 + 模板解析器。
  2. vue.runtime.xxx.js 是运行版的 Vue,只包含核心功能,没有模板解析器。

因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容。

vue.config.js 配置文件

  1. 使用 vue inspect > output.js 可以查看到 Vue 脚手架的默认配置。
  2. 使用 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
2
只接收:
props:['name']
1
2
3
4
限制类型:
props:{
name:String
}
1
2
3
4
5
6
7
8
第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String,//类型
required:true,//必要性
default:'老王'//默认值
}
}

备注:
props只是只读,Vue 底层会检测你对 props 的修改,如果进行了修改,就会发出警告;
若业务需求确实需要修改,那么请复制 props 的内容到 data 中一份,然后去修改 data 中的数据。

Vue2 第一弹 —— 声明式渲染
Vue2 第三弹 —— 事件总线、插槽