最重要:
1、data:
1)不渲染视图、不双向绑定的数据不放进data,在created中this.XXX = 定义即可;
2)data中的对象和数组的改变:
a、改变对象:
data() { return { kk: { a: 1 } } }, methods: { change() { this.kk.b = 2; //通过直接赋值改变对象,不是响应式 this.$set(this.kk, 'b', 2); //用$set方法改变,是响应式 } }
b、改变数组:
data() { return { ooo: [0, 1] } }, methods: { change() { this.ooo[2] = 2; //通过数组下标改变数组,不是响应式 this.ooo.push(2); //用push、splice等方法改变,是响应式(vue重写了这几种方法) } }
2、.vue文件中this指向的内容:
1)$attrs:是props的合集,只有自定义的属性才能取到 (透传,由上往下传递)
index.vue:
<hello :tt="1234" msg="123"></hello>
hello.vue:
<template> <div>111</div> </template> <script> export default { mounted() { console.log(this.$attrs); //{ ttt: '1234', msg: '123' } } } </script>
2)$createElement:相当于render函数的h函数
3)$el:当前div的DOM
4)$refs:ref绑原生标签---->DOM,ref绑组件---->组件实例
index.vue:
<hello v-for="v in 10" :key="v" ref="ddd"></hello> this.$refs.ddd --->[10] //10个hello组件,循环时可直接批量修改 this.$refs.ddd.forEach(x => { x.msg = 'hello'; });
hello.vue:
<template> <div>{{ msg }}</div> //循环10个hello </template> data() { return { msg: '111' } }
5)$parent:父级元素的实例(一般不用,也不要用)
6)$listeners:与$attrs相对应,都是透传,是从下往上传递。eg:
index.vue: <div> {{ abc }} //默认显示1,点击hel.vue的button,改为888 <hello :abc="abc" @click="_change"></hello> </div> data() { return { abc: 1 } }, methods: { _change(val) { this.abc = val; } } hello.vue: <hel v-bind="$attrs" v-on="$listeners"> </hel> hel.vue: <div> <span>{{ $attrs.abc }}</span> //默认显示1,点击button后变为888 <button @click="_click"></button> </div> created() { console.log(this.$attrs); //{ abc: '1'} console.log(this.$listeners); //{ click: f } index.vue的click事件 }, methods: { _click() { this.$emit('click', 888); //点击调用index.vue的click事件 } }
3、$nextTick:解决mounted时,DOM没有完全渲染完的时间差(16ms)
mounted() { this.$nextTick().then(() => { ...//代码片段 }); }
4、计算属性、方法、watch比较:
1)计算属性(computed):对数据的计算和过滤等一些简单的操作,有缓存(依赖没变、结果没变),可按照使用场景优先使用
使用场景:多个params绑定,修改单个用computed
coputed: { params: { page: this.page, pageSize: this.pageSize } } //一个改,整个计算
2)methods:不缓存,每次都运行
3)watch:数据改变后,要调接口和进一步的操作
使用场景:a、可以监听路由跳转的参数
watch: { $route(val) { ...//代码片段 } }
b、监听嵌套对象深层的某个值:
data() { return { kk: { a: { b: { c: 1 } } } } }, watch: { 'kk.a.b.c': funtion(val) { ...//代码片段 } }
5、key:为了更高效的复用
vDOM:用js对象表达DOM,配合diff算法生成DOM
1)包在中间的子节点复用,值会改变。eg:<span>3</span> ------> 5
2)包在属性中的子节点复用,不会改变。eg:<img src="1.jpg" /> ------>不会改变,因为已经渲染了。
6、注册组件:
(1)动态注册组件:
(1) import hello from './hello'; components: { hello } (2) this.components('hello'); (3) table.config.js: import hello from 'hello'; render(h) { return h('hello', { ... }) }
(2)全局注册:
Vue.component('hello');
7、props:父组件传递给子组件的数值
(1)传递变量时前面需要加":",否则一律按字符串处理
<hello msg="true"></hello> ----->msg为字符串"true" <hello :msg="true"></hello> ----->msg为布尔型数值true
(2)布尔型的数值传递true值,可直接省略写:
<hello msg></hello> ----->msg为布尔型数值true
(3)props的值不允许直接修改,在子组件中需要修改,则需要重新定义一个变量去修改。
(4)对一个 prop 进行“双向绑定”:加.sync修饰符。即在子组件也可以修改父组件prop传递的值
index.vue: <hello :msg.sync="123"></hello> hello.vue: this.$emit('update:msg', '222');
较重要:
1、模块化:精简、复用(按需调用)、防止变量污染
2、AMD、CMD、commonJS、esModule(es6):
1)AMD:define(modules, callback):依赖前置、异步定义
2)CMD:define():依赖就近,即用即返
3)commonJS:require()引入(图片src引入或判断引入),exports导出、运行时加载。例:
index.js:
var bar = require('./bar.js'); function foo() { return bar.bar(); }
bar.js:
exports.bar = function() { console.log('1111'); }
4)ES Module:在script头部用import引入,export导出、编译时加载。例:
index.js:
'use strict' import bar, {foo} from './bar.js'; bar(); // 11 foo(); // 112
bar.js:
'use strict'; export default function bar () { console.log('11'); }; export function foo () { console.log('112'); }
3、vue.js包括编译和运行两部分:
1)编译:将template代码片段转成AST(抽象语法树)---->优化AST(标记静态部分不再渲染)---->AST生成render函数。
2)运行:render函数 ----> vDOM ----> DOM
mark:由于webpack的vue-loader做了预编译,因此不需要vue.js做编译,因此用vue.runtime.js(仅运行版本的vue.js)。需要做的几处改变:
1)main.js中new Vue({});中的template: '<App />', components: {App}需要改变成render: h => (App) 。
2)this.$Message没法调用,将iview源码中注册组件的components改成render函数即可。
4、data、props、methods都可代理到实例上,通过this.XXX直接调用,不通过this.$data.XXX等。this.$data---->拿到所有data中定义的数据
5、_uid是每个组件唯一的标识
6、@hook:监听子组件生命周期加载完成:
<hello @hook:mounted="kk" @hook:created="qq"></hello> kk() { //监听子组件hello的生命周期mounted完成 console.log('hello mounted done'); } qq() { //监听子组件hello的生命周期created完成 console.log('hello created done'); }
7、{{}}等同于v-text,用于存放DOM中的变量值,一般用{{}},有可能会出现不解析的情况,用指令v-cloak(等编译完才显示)解决即可
2)v-html可以解析html语句,可转义,但是可能会遭到XSS攻击,因此要慎用
8、动态值的优先级更高:
<input value="22" :value="77" /> -----> value: 77
9、$event:需要添加自己的参数时的占位符
1)正常情况下的子组件调用父组件的方法以及传参:
index.vue: <hello @click="kii"></hello> kii(data) { console.log(data); //22 } hello.vue: <div @click="aaa">emit click</div> click() { this.$emit('click', 22); }
2)父组件需要在该组件中传递自己的参数时,需要$event来占位保留子组件传递的值:
index.vue: <hello @click="kii($event, 33)"></hello> kii(data, val) { //$event只能识别第一位参数,因此子组件需要传递多个参数时,用对象包起来传递整个对象即可 console.log(data, val); //22 33 } hello.vue: <div @click="aaa">emit click</div> click() { this.$emit('click', 22); }
10、插槽:
(1)插槽的用法:
1)父组件插槽占位,引入不同的子组件:
index.vue: <hello> <slot></slot> </hello> hello.vue: <div> <span>{{msg}}</span> </div> data() { return { msg: '111' } }
2)具名插槽:
index.vue: <hello> <template v-slot:header> <p>This is header slot!!</p> </template> <template> <p>This is main slot!!</p> </template> <template v-slot:footer> <p>This is footer slot!!</p> </template> </hello> hello.vue: <div> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
(2)用子组件的数据:
index.vue: <hello v-slot="uu"> <span>{{uu.aa}}</span> <span>{{uu.bb}}</span> </hello> hello.vue: <div> <slot :aa="msg" :bb="msg2"></slot> </div> data() { return { msg: '111', msg2: '222' } }
11、动态组件:
(1)keep-alive:缓存。使用场景:1)不要求实时性;2)步骤条(保存当前操作)。
1)include、exclude根据name值去匹配包括还是去掉该路由的缓存;max则表示最大缓存的组件实例数:
<!-- 逗号分隔字符串 --> <keep-alive include="a,b"> <component :is="view"></component> </keep-alive> <!-- 最大缓存组件实例数,超过则最久没访问的组件实例会被销毁 --> <keep-alive :max="10"> <component :is="view"></component> </keep-alive>
2)当组件在 <keep-alive>
内被切换,它的 activated
(进)和 deactivated
(出)这两个生命周期钩子函数将会被对应执行。使用场景:
(A)、页面不刷新;
(B)、同一个组件,不同的调用,导致不渲染,解决方法:
a)监听路由变化:
watch: { $route(val) { //代码片段 } }
b)beforeUpdateRoute
(2)动态组件:使用场景:1)判断条件加载两个不同组件;2)加载动态表单
<!-- 自定义属性可任意加 --> <component :is="data.length > 300 ? 'hello' : 'div'" :size="30"> </component>
(3)异步组件:(性能优化)
1)代码覆盖率:加载的文件都只为展示当前的页面,覆盖率越高,性能越好;
2)跟首屏无关;
3)按需加载.
<!-- 需要加载hello组件时,会加载hello.js --> const Hello = () => import (/* webChunkName: 'hello' */ '@/views/hello');
(4)混入(mixin):全局/局部注册,解决复用问题(很多页面都需要有这些)
1)mixin中生命周期和组件的合并,其他的则会覆盖组件的;
2)坏处:看不见定义及处理,因此要少用。
(5)inject和provide:解决跨级暴露并接收
12、函数式组件:简单用于展示类的组件,无响应式,性能更好:
<template functional> <!-- 组件内容 --> </template>
13、插件:在new Vue()之前通过全局方法 Vue.use()
使用插件。
14、过滤器:对数据的过滤。适用于v-bind和{{}}。主要场景是多个地方都用到的情况下,用过滤器,也可以全局注册:
<!-- 在双花括号中 --> {{ message | capitalize }} <!-- 在 `v-bind` 中 --> <div v-bind:id="rawId | formatId"></div>
//在实例中定义过滤器 filters: { capitalize: function (value) { if (!value) return ''; value = value.toString(); return value.charAt(0).toUpperCase() + value.slice(1); } } //全局注册过滤器 Vue.filter('capitalize', function (value) { if (!value) return ''; value = value.toString(); return value.charAt(0).toUpperCase() + value.slice(1); }) new Vue({ // ... })
15、自定义组件的v-model:
index.vue: <div> {{abc}} //点击hello组件的按钮后,该变量变为233333 <hello v-model="abc"></hello> </div> data() { return { abc: 1 } } hello.vue: <button @click="changeA">Click!</button> props: ['abc'], model: { event: 'change', prop: 'abc' }, methods: { chngeA() { this.$emit('change', 233333); } }
16、生命周期钩子(常用):
1)created:调接口,加载loading状态,定义不渲染视图不双向绑定的数据等;
2)mounted:之后才能渲染DOM,注意DOM渲染时间差,用nextTick解决;
3)destroyed:组件销毁时的操作;
4)activated:在keep-alive时才有该生命周期,组件激活时调用,在服务器端渲染期间不被调用;
5)deactivated:在keep-alive时才有该生命周期,组件停用时调用,在服务器端渲染期间不被调用。
17、API:
1)Vue.extend(options):创建构造器,并创建实例,挂载在页面元素上
// 创建构造器 var Profile = Vue.extend({ template: '<p>{{firstName}}</p>', data: function () { return { firstName: 'Walter', } } }) // 创建 Profile 实例,并挂载到body元素上。 new Profile().$mount('body')
2)Vue.compile:在 render 函数中编译模板字符串。只在独立构建时有效。
3)<pre>:不编译,直接显示写入的代码片段。
18、vm.$watch:添加动态监听,需要手动销毁:
<div> <button @click="change">Click!!</div> <hello :abc="abc"></hello> </div> data() { return { abc: 1 } }, methods: { change() { this.abc++; } } hello.vue: <span>{{ abc }}</span> props: ['abc'], mounted() { //添加动态监听 this.$watch('abc', function(val)) { console.log('val', val); //每次点击都会走监听 }); //添加回调内销毁的监听 let unwatch = this.$watch('abc', function(val)) { console.log('val', val); //只有第一次改变会走监听 unwatch(); }); }