MVVM 是 web 前端一种非常流行的开发模式,利用 MVVM 可以使我们的代码更专注域处理业务逻辑而不用去关心 DOM 操作。
beforeCreate 在实例初始化之火,数据观测 data observer 和 event/watcher 事件配置之前被调用
created 在实例创建完成后被立即调用。在这一步,实例已经完成以下配置 data observer 属性和方法运算,watch/event 事件回调,但是挂载还没开始,$el 属性不可用
beforeMount 在挂载开始之前被调用,相关的 render 函数首次被调用
mounted el 被新创建的 vm. e l 替 换 , 并 挂 载 到 实 例 上 去 之 后 调 用 该 钩 子 , 如 果 r o o t 实 例 挂 载 了 一 个 文 档 内 元 素 , 当 m o u n t e d 被 调 用 时 v m . el 替换,并挂载到实例上去之后调用该钩子,如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm. el替换,并挂载到实例上去之后调用该钩子,如果root实例挂载了一个文档内元素,当mounted被调用时vm.el 也在文档内;注意 mounted 不会承诺所有的子组件一起挂载,如果希望在整个视图渲染完毕后,可以使用 vm.$nextTick
beforeUpdate 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM ,比如手动移除已经添加的事件监听器
updated 由于数据更改导致虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子;当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM的操作。注意不会承诺所有的子组件也一起被重绘,如果你希望等到整个视图都重绘完毕,可以用 vm.$nextTick
activated keep-alive 组件被激活时调用
deactived keep-active 组件停用时调用
beforeDestroy 实例销毁之前调用,在这一步,实例仍然完全可用
destroyed Vue 实例销毁后,调用后,Vue 实例都会解绑,所有的事件监听器会被移除
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, ‘dist’),
routes: [ ‘/’, ‘/about’, ‘/contact’ ],
renderer: new Renderer({
inject: {
foo: 'bar'
},
headless: true,
renderAfterDocumentEvent: 'render-event'
})
})
])
meta: ` `
}
renderer.renderToString(app, context, (err, html) => {
if (err) return res.status(500).end('Internal Server Error')
})
res.send(html)
})
server.listen(8080, () => console.log('8080 is on'))
*1 组件的生命周期在 ssr 时只有 beforeCreate 和 created 会执行
*2 指令尽量少用,或者抽象问组件层面并运行在虚拟 DOM 层面或者使用服务端渲染版本的指令
*3 避免状态单例即不能使用一个 Vue 实例,应该使用一个工厂函数创建 Vue 实例;同理 VueRouter 和 Vuex 使用相同处理,否则会出现交叉请求状态污染
*
使用 vuex 托管应用的状态以后,我们需要通过 computed 计算属性或者
this.$store.state.xxx
访问 store 中的状态;其内部调用了一下applyMixin方法,该方法主要作用就是在所有组件的beforeCreate生命周期注入了设置this.$store这样一个对象,把 vuex 的 state 初始化到组件的 data 中,其本质就是将我们传入的 state 作为一个隐藏的 vue 组件的 data,当我们通过提交 mutation 或者 dispatch action 时提交的 mutation 会修改数据,而数据修改会自动通知 vue 的更新机制;vuex 中的store 本质就是没有 template 的隐藏着的 vue 组件;
Vue.component('async-component', (resolve, reject) => {
setTimeout(() => {
resolve({
template: `这是异步组件模板`
})
}, 3000)
})
配合 webpack code-spliting
Vue.component(‘async-webpack-example’, function (resolve) {
// 这个特殊的 require
语法将会告诉 webpack
// 自动将你的构建代码切割成多个包,这些包
// 会通过 Ajax 请求加载
require([’./my-async-component’], resolve)
})
使用 import() 方法
Vue.component(
'async-webpack-example',
// 这个 `import` 函数会返回一个 `Promise` 对象。
() => import('./my-async-component')
)
Object.defineProperty(obj, prop, configObj)
;改善了之前的一些问题,例如数组 .length 的操作不能支持等;惰性监测,原有 2.x 是在应用启动时就对所有的数据进行观测,而 3.x 会默认只对应用中可见的数据进行监测;当动态组件频繁切换,如果不使用 keep-alive 组将将会重复的销毁和重新渲染会引发性能问题。此外,组件销毁,其中的状态也会随之销毁。所以,为了避免重复渲染的性能问题或者需要动态组件中的状态得以保存就需要使用 keep-alive
let str =
Real DOM
cannot update
- Item 1
- Item 2
- Item 3
Object.defineProperty
//observer:观察者
function observer(obj) {
if (obj && typeof obj === 'object') {
for (let key in obj) {
if (!obj.hasOwnProperty(key)) break;
defineReactive(obj, key, obj[key]);
}
}
}
function defineReactive(obj, key, value) {
observer(value);
Object.defineProperty(obj, key, {
get() {
return value;
},
set(newValue) {
observer(newValue);
if (value === newValue) return;
value = newValue;
}
});
}
function $set(data, key, value) {
defineReactive(data, key, value);
}
Object.defineProperty()
对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。组件的特点是:
在任何组件中可以直接使用(不需要引入,直接在组件模板中调用即可)
Vue.component(componentName,options)
<my-component>
<template v-slot:xxx 或者 #xxx>
永怀善意
</template>
</my-component>
{
templete:`
`
}
<my-component aa='zhangzhang' :bb='xxx'></my-component>
Vue.component('my-component',{
props:['aa','bb'],
...
})
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:
每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。有两种常见的试图改变一个 prop 的情形 :
<my-component @func='xxx'></my-component>
new Vue({
methods:{
xxx(value){
//=>value是this.$emit时候传递的第二个参数值
}
}
});
{
methods:{
xxx(){
this.$emit('func',10);
}
}
}
let eventBus=new Vue; //=>创建事件总线
//A组件
eventBus.$on('xxxA',this.func);
//B组件
eventBus.$emit('xxxA');
{
provide:{ //=>对象或者返回对象的函数都可以(属性值如果是data中的数据,则必须使用函数的方法进行处理)
name:'zhangzhang',
year:10
},
...
}
{
inject:['name'],
methods:{
func(){
let name=this.name;
}
}
}
enter-active-class=“animated xxx” leave-active-class=“animated xxx”