0、提醒*注意!
- 一旦 data 里数据改了,vue 会重新解析模板,和该数据相关的模板、方法都会更新
- 对象里的key是字符串,但是 new vue 实例的时候,经常把 key 简写,还经常把函数简写
- Vue 在配置对象里写的所有东西都可以在 vm.$options 里获取得到
- Form 里的标签取值,可以用 v-bind/v-model 绑在 <> 标签里
- Form 外的标签取值,标签属性仍然可以用 v-bind/v-model 绑在<>标签里,非标签属性则需要用 {{}} 取值
- 读取 data 中某个对象不存在的属性时,返回 undefine,vue 不会显示 undefine,因此最终页面上为空
1、概念简介
特点- 渐进式构建数据页面的JS框架
- 组件化 - 模板
-
在 HTML 中准备一个容器 <div id="roo"></div>
- id/class 都可以
-
在 JS 中 new 一个 vue 实例,内部只传一个参数,即为配置对象 options
-
配置对象 options
*kv形式
el
el: '',
- 第一种写法:el:'#root'
- 第二种写法:vue.$mount('#root')
data
data() { return { // content } }
- 对象式写法:数据很多,采用对象的形式;
-
函数式写法:后续使用组件,必须用函数的形式,返回对象
组件里定义的变量,如果不用函数式写法会污染全局变量,这是闭包原理 一个组件的
data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
methods
methods: { <方法名>(参数) { // content } }
computed
计算属性也是属性,里面的属性是对象的形式/函数
原理:底层用的就是 Object.defineproperty 定义:属性原本不存在,需要通过已有属性计算得来 优势:能够缓存,复用计算结果,效率高,调试方便computed: { <计算属性>: { // 初次读取时调用 // 对应数据发生变化时调用 get(){ // content }, // 涉及到该属性的修改时调用,并且要更新依赖的相关属性,几乎不太用 set(){} } }
// 简写-默认为 getter,此时只考虑读取,不考虑修改 // fullName:function() {} computed: { <计算属性>() { // content } }
watch
watch: { data/computed 中的属性:{ // 配置对象 immediate: false/true, deep: false/true, handler(){ // content }, } }
-
Immediate - 页面初始化时立即执行一次
- 默认值是 false,在第一次进入页面时,如果没有发生数据变化,watch并不会立即监听
-
handler(新值, 旧值)
- 值在更改时被调用,不传参时可以调用 event
-
Deep - 深度监视
- 默认值是 false,不监测对象内部数据的改变
Watch 和 computed 的区别:// 简写-当只配置handler,而不需要其他配置项的时候 // isHot:{ handler(){} } watch: { <监视属性>(newVal, oldVal) { // content } }
- Computed 能完成的功能,watch 都能完成
- Watch 能完成的功能,computed 不一定能完成,例如异步操作
- 所有被 vue 管理的函数,最好写成普通函数,这样 this 指向才是 vm 或者组件实例对象
- 所有不被 vue 管理的函数(如定时器的回调函数,ajax的回调函数等),最好写成箭头函数,这样 this 指向才是 vm 或者组件实例对象
Filters
filters: { <过滤器函数>() { // 内容 } }
管道 | 左侧的 time 作为参数传入右侧的过滤器 timeFormater 然后其返回值直接替代整个 {{}} 内部内容,在页面中显示
作用域-
局部过滤器
new Vue{filters:{}}
-
全局过滤器
Vue.filter('<过滤器函数>', function() {})
Directives
自定义指令可以收到两个参数:// html - 使用自定义指令 v-big <div v-big="n"></div> // js - 配置自定义指令 big new Vue({ directives:{ big(element, binding){ // content } } })
-
Element : 该指令所在的标签(html 元素)
- element.innerText
- element.value
-
Binding:将 html 标签与 自定义指令绑定
- binding.value
- 指令与元素成功绑定时(初始
- 指令所在的模板被重新解析时
作用域// 特定的函数在特定的时间点调用 directives: { fbind: { // 指令与元素成功绑定时(初始 bind(element, binding){} // 指令所在元素被插入页面时 inserted(element, binding){} // 指令所在的模板被重新解析时 update(element, binding){} } }
-
局部过滤器
new Vue{directives:{}}
-
全局过滤器
// 复杂写法,自定义指令的内容是配置对象 Vue.directive('<自定义指令>', {}) // 简单写法,自定义指令的内容是函数 Vue.directive('<自定义指令>', function(element, binding){})
- 自定义指令里的 this 是 window
Template
相当于把 html 里 template 的内容放在 vue 实例里进行配置
*注意内容物只能有一个根节点// 第一种方式 没有 :x="n" 了 <div id="root" :x="n"> </div> new Vue({ el:'#root', template:` <div> <h1>{{msg}}</h1> <h2>kk</h2> </div> ` })
// 第二种方式 :x="1" <div id="root" :x="n"> <h1>{{msg}}</h1> <h2>kk</h2> </div> new Vue({ el:'#root', })
两种方式的差别在于
- 第一种方式中 div 被 template 完全替代
- 第二种方式中 div 作为根节点被渲染解析,:x="1"
Components
在 vue.extend 中需要注册组件时使用
4、基础语法 - 指令
语法 *在F12页面中调试,需要用DOM去操作- HTML 标签中绑定
两种使用方法
- 标签<>里头,用 :
- 标签外头,用 {{}}
- 表格数据(用 vue 插件调试)
- 默认与 表单 -> 输入标签 -> value值 进行双向绑定
- v-model:value 可简写为 v-model
-
.number
- 原生的
-
.lazy
- HTML 标签中绑定事件,比如 click 事件
DOM 里的 event 对象类似于 function 里的 arguments
-
函数后头的 () 加不加都行
- 用插值语法 {{}} 去调用函数,约等于把函数返回值插入模板
- 不管函数需不需要传参,都得带 ()。否则会输出整个函数体,而不是执行函数
<span>{{function()}}</span>
事件修饰符能连着写,如 @click.stop.prevent="function",有先后顺序
键盘事件- @keyup 事件
- @keydown 事件
<input @keyup.enter="function"> <input @keydown.delete="function">
- 自定义按键别名,注意用 kebab-case 方式命名
vue.config.keyCodes.自定义键名 = 键码
按键修饰符也能连着写,如 @keyup.ctrl.y="function"
V-show
V-show 的底层实现就是 V-show 和 v-if 如果标签需要切换的频率较高,建议使用 v-show让 DOM 元素不显示的方式有: display:none visibility:hidden opacity:0
- 节点存在,只是动态控制是否显示
- v-if 需要在 dom 树中进行增删
v-else-if
特殊情况-1 当 v-if 与 v-else-if 的判断条件写得相同时,会跳过 v-else-if 判断条件的执行 第二条的 n===1 会被跳过不执行 特殊情况-2 当一组 v-if v-else-if 没有一个判断条件为 true 时,会直接返回最后一条 v-else-if / v-else 的内容 最后一条判断的 n===4 没有任何作用- 几个 if if if 并列
- 用 if else-if else-if 并列
V-for
遍历
// 语法 <li v-for="item in/of arr" :key="item.id"></li> // 遍历数组 // 第一个值是 item 数据 // 第二个值是 index 索引 <li v-for="(item, index) in arr"></li> // 遍历对象 // 第一个参数是 value // 第二个参数是 key <li v-for="(value, key) of car" :key="key"></li> // 遍历字符串 // 第一个参数是 字符 char // 第二个参数是 对应的索引 index <li v-for="(char, index) of str" :key="index"></li>
key值
Key 值- 可以绑定 item 对象中的 id 字段
- 可以绑定 index 值
- 也可以不绑定
Diff 对比算法
key 的内部原理
- 虚拟 DOM 中 key 的作用:
-
对比规则
-
旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
- 若虚拟 DOM 中内容没变,直接使用之前的真实 DOM
- 若虚拟 DOM 中内容变了,则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM
-
旧虚拟 DOM 中未找到与新虚拟 DOM 相同的 key
- 创建新的真实 DOM,随后渲染到页面
-
旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
-
用 index 作为 key 可能会引发的问题
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实 DOM 更新(界面效果没问题,但效率低)
- 如果结构中还包含输入类的 DOM:会产生错误 DOM 更新(界面有问题)
-
开发中如何选择 key
- 最好使用每条数据的唯一标识作为 key
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用 index 作为 key 是没有问题的
列表过滤
用 JS 中的 filter 和 indexOf 方法内置指令
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 解决网速慢时页面展示出 {{}} 的问题
// css [cloak]{ display: none; } // html <div v-cloak>{{msg}}</div>
网络加载时,v-cloak 属性存在 当网络加载完毕,vue实例挂载到容器上后,v-cloak 属性被去掉了
V-once
- 特点:v-once 所在节点在初次动态渲染后,就视为静态内容了
- 以后数据的改变不会引起 v-once 所在结构的更新,可以用于优化性能
V-pre
- 作用:跳过所在节点的编译过程
- 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
自定义指令
- 使用 vue 中的配置项 directives
- 涉及自定义指令名很长时,需要 小写+杠
// html <div v-big-number></div> //js 复杂写法 new Vue({ directives:{ 'big-number': function(element, binding){ // content } } }) //js 简写 new Vue({ directives:{ 'big-number'(element, binding){ // content } } })
5、进阶内容
vue对象
vue原型
MVVM模型
- model 中 data 里所有的属性,最后都会通过数据代理,出现在 vm 实例中
- 本质上说:模板 view 里可以调用所有 vm 身上的所有属性及其原型上所有的属性
Object.defineProperty
- 数据属性
- [[Configurable]]:删除
- [[Enumerable]]:枚举
- [[Writable]]:修改
- [[Value]]:值
- 访问器属性
- [[Configurable]]:删除
- [[Enumerable]]:枚举
给 methods 加数据代理没有任何意义,方法只是用于调用,而不是被更改的
简而言之:数据代理就是 vm实例上有属性了,但是属性值不给你,是动态更新的数据劫持
数据代理图片中,_data里有数据劫持,也就是说,Vm 在拿到 data 中的数据时,做了两部分工作:-
加工 data
- 目的:vue 的响应式(当页面改变时,数据也发生改变)
- 方式:为每个数据加一个 getter 和 setter
- vm._data = data
这是简单的 data 数据劫持逻辑,vue 比我们考虑的更多:
- 既可以通过
数据监视更新的原理
-
vue 如何监测对象里数据改变:
-
为每个数据添加 getter 和 setter
- 更改对象内容:可以直接用=修改
- 添加新的响应式属性:可以用vue.set
-
为每个数据添加 getter 和 setter
-
vue 如何监测数组里数据改变:
- Vue 并不会为数组里的每个数据添加 getter/setter
-
也就是说,当通过索引值改变数组内容时,不会触发页面的响应式更新
- 更改对象内容:不可以用=修改,需要用7种改变数组的方法修改
- 添加新的响应式值:得用7种改变数组的方法修改
数据监测
对象更新时的问题 两种 data 中对象更新的方法:- 用.的方式取数组对象中的属性,用=赋值
- 直接用=对数组中的对象进行赋值
无法正常显示的原因: 后续通过=为vm._data中的数据添加属性和属性值时,vue不会为这种属性配备 getter/setter,因此该属性不是响应式数据,读取时不调用 setter,自然不会引起模板解析,也就不会显示到页面上了
解决办法: vue.set
局限性 数组更新时的问题// 第一种:调用 vue 上的 set 方法 vue.set(<对象>,<属性>,<属性值>) vue.set(vm._data.student,'sex','男') // 例子 vue.set(vm.student,'sex','男') // 例子,用了数据代理 // 第二种:调用 vm 实例上的 $set 方法 vm.$set(<对象>,<属性>,<属性值>) this.$set() // 在 vm 实例中
- 当通过索引值改变数组内容时,不会触发页面的响应式更新
-
Vue 能够进行响应式监测的数组方法有7个:
- Push
- Pop
- Shift
- Unshift
- Splice
- Sort
- Reverse
Vue 监测数据的原理vue.set(<数组>,<索引值>,<更改后的值>)
- Vue 会监测 data 中所有层次的数据
-
如何监测对象中的数据?
-
通过 setter 实现监视,且要在 new vue 时就传入要监测的数据
- 对象中后追加的属性,vue 默认不做响应式处理
-
如需给后添加的属性做响应式,请使用如下 API:
- vue.set() 或 vm.$set()
-
通过 setter 实现监视,且要在 new vue 时就传入要监测的数据
-
如何监测数组中的数据?
-
通过包裹数组更新元素的方法实现,本质就是做了两件事:
- 调用原生对应的方法对数组进行更新
- 重新解析模板,进而更新页面
-
通过包裹数组更新元素的方法实现,本质就是做了两件事:
-
在 vue 修改数组中某个元素,一定要用到如下方法:
- 使用 api:push/pop/shift/unshift/splice/sort/reverse
- vue.set() 或 vm.$set()
- 特别注意:vue.set() 和 vm.$set() 不能给 vm 或 vm的根数据对象 添加属性
生命周期
如果在 methods 里面开定时器,并且在内部改变 data 中的值,那么会导致定时器个数成指数倍增长的情况。 Methods 里面只写回调函数 生命周期里的 this 都是 vue 实例
created- 数据监测和数据代理都开了
- 可以访问 data 和 methods
- 但页面中还没有显示解析好的内容,vue 没有解析模板,没有生成虚拟 dom
- 虚拟 dom 转为真实 dom 插入页面了
- 页面中呈现已经编译好的 dom
- 在此时可以 开启定时器、订阅消息、绑定自定义事件等初始化操作
- 数据是新的,页面也是新的,完成 model->view 的更新
- 涉及新旧 DOM 元素对比
- 所有配置项都处于可用状态,但是所有对数据的修改不会触发 更新/模板解析 了,所以不建议使用
- 在此时可以 关闭定时器、取消订阅、解绑自定义事件等收尾操作
6、业务需要
绑定样式
css
// :class="xxx" v-bind:class="xxx"
- 不确定是否使用样式时,动态切换样式,vue 绑定 boolean 数据实现
- 适用于:样式
- 不确定用几个样式时,动态切换样式的个数,vue 绑定数组实现
- 适用于要绑定的样式
-
- 在标签内写js表达式时,带引号与不带引号意义不同
- 带引号:表示引号内是值
- 不带引号:表示该参数是一个变量,需要找其对应的值
<div :class="['at1', 'at2', 'at3']"></div> // data <div :class="[at1, at2, at3]"></div>
style
- 当需要绑定行内样式时,用对象的形式
- 1.css 里的 font-size 对应 js 里的 fontSize
<div :style="{fontSize: fsize+'px'}"></div> // data fsize: 40
- 2.对象的形式
<div :style="styleObj"></div> // data styleObj: { fontSize: '40px' }
- 3.数据的写法
<div :style="[styleObj, styleObj2]"></div> // data styleObj: { fontSize: '40px', color: 'red' } styleObj2: { backgroundColor: 'orange' }
过滤器
显示格式化后的时间
- 推荐开源库 moment.js / day.js
代码折叠
使用 region 包裹需要折叠的代码,这样无论发生什么,该段代码都可以正常折叠#region ... #endregion
-
-
vue 如何监测对象里数据改变:
-
配置对象 options
*kv形式