Vue生命周期(8个)
每个生命周期都由钩子函数调用(callHook)
created()
mounted()
updated()
destroy()
keep-alive(LRU算法)
activated
deactivated
include/exclude
父组件监听子组件mounted
child
mounted () { this.$emit(“mounted”) }
parent
<child @hook:mounted=”dosomething”><child>
js
vm.$on('hooks:created', cb) ;
父子组件生命周期顺序
- 渲染
父beforeCreate created beforeMount
子beforeCreate created beforeMount mounted
父mounted - 子更新
父beforeUpdate
子beforeUpdate updated
父updated - 销毁
父beforeDestory
子beforeDestory destroyed
父destroyed
Vue组件通信(单向数据流)
props
emit
parent $children
eventBus跨组件
provide inject 插件 父供子消费
Vue公共逻辑抽离(Vue.mixin)
mergeOptions(data,生命周期等)
- 全局
Vue.mixin(mixin) - 局部
import mixin from ‘...’ export default { mixins: [mixin], data () { return {} } }
多个组件中的引用相同mixin,mixin是独立的,不互相影响
调用时,先生成mixin,same options时组件会覆盖mixin的
异步组件 (Vue2.0一定是函数)
components: {
AddComp: (resolve) => import('../components/Confirm.vue')
}
动态组件
<component :is="settingTabs[currentTab].component"></component>
currentTab: 0,
settingTabs: [{ title: '基本设置', component: 'basic-setting' }]
插槽
- slot:作用域为父组件
my-component
父组件调用my-component<modal> <slot name="content"></slot> </modal><ConfirmEle> <template #content 或者 slot=“content”></template> </ConfirmEle> - slot-scope 作用域子组件
computed watch method区别
- 方法m:
c、w原理都是watcher实现
计算c:缓存,依赖变化才更新视图 - 监视w:
1
2
Vuex
- 基础属性
import Vuex from 'vuex';
Vue.use(Vuex);
new Vuex.Store({
state: {
name: ‘’
},
mutations: {
setName (state, name) {
state.name = name
}
},
actions: {
login({ commit }, res) {
commit('setName', res.data.name);
localStorage.setItem('userName', res.data.name)
// axios.defaults.headers.common.Authorization = token;
},
logout({ commit }) {
return new Promise((resolve) => {
localStorage.clear();
sessionStorage.clear();
// axios.defaults.headers.common.Authorization = '';
resolve();
});
},
},
modules: {
user,
setting
}
})
- vuex引用
computed: {
...mapState('module1', ['state1', 'state2'])
},
methods: {
...mapMutations('module2', ['mutations1', 'mutations2']),
}
this.$store.dispatch('user/login', res).then(() => {
this.$router.push({ name: 'workSpace' });
});
this.$stroe.commit()
computed: {
audioStatus: {
get () {
return this.$store.state.setting.audioStatus;
},
set (val) {
this.$store.state.setting.audioStatus = val;
}
}
}
自定义指令
钩子函数bind inserted update 全局
Vue.directive('image-preview', function (el, binding, vnode) {})
局部
export defaults {
directives: {
focus: {
inserted: function (el) { el.focus() }
}
}
}
Vue.directive('has', {
// 当被绑定的元素插入到 DOM 中时
inserted: function(el, binding) {
var role = store.state.user.role
if (!role) return false
let auth = role.some(e => {
return e.id === 1
})
!auth ? el.style.display = 'none' : el.style.display = 'inline-block'
}
})
vue双向绑定原理(响应式)
数据劫持+发布订阅模式
递归遍历整个data,Object.defineProperty()劫持各个属性的setter和getter方法;
数据get时添加订阅者到订阅中心,set时通知订阅中心,依赖收集Watcher,稍后Dep.notify通知watcher,异步渲染更新)
- initData()
- Observer(监听者,劫持并监听)
- Dep 依赖
- Watcher订阅者
- Compile编译解析
vue-template-complier // 将模板解析成vue的浏览器语法
VueTemplateComplier.compile(`<div v-if=”true”></div>`)
‘with(this){
return
}’
data采用工厂函数
new Vue({ data:{} }) new Vue()只一次,创建一个根实例 data: {}
data () { return {} } 工厂函数
组件数据间独立,防止组件VueComponent多次new实例化时data复用,污染数据
data() => ( return obj: {name: ‘123’ }) 引用时 vc.$options.data()
var Component1 = function() {
this.data = this.data()
}
Component1.prototype.data = function() {
return {
a: 1,
b: 2
}
}
var Component2 = function() {
this.data = this.data()
}
Component2.prototype.data = () => {
return {
a: 1,
b: 2
}
}
var Component3 = function() {}
Component3.prototype.data = {
a: 1,
b: 2
}
var c1 = new Component1()
var c2 = new Component2()
var c3 = new Component3()
// 改变组件
component1.data.b = 3
component2.data.b // 2
Vue采用异步渲染
页面中N条数据,等N条数据全update后,再异步更新视图
nextTick(清空watcher队列)
nextTick()
保证当前视图渲染完成(更新图标echarts)
nextTick(系统的异步更新 、直接调用$nextTick)
把这些更新全放到 callback=[] 数组中
之后异步微任务 timerFunc=(Promise.resolve().then(依次执行callback))
(根据浏览器支不支持,依次使用promise.then、setImmediate、setTimeout)
Vue模板编译原理 (parse解析、optimize优化、generate生成)
将template模板转为 ast(抽象语法)树(用Object描述JS语法),生成render函数
render( _c() ),转成虚拟dom
虚拟dom(用Object描述dom)
- Vue实例渲染权重
let vue = new Vue({ el: '#app', data() { return { a: 1, b: [1] } }, render(h) { return h('div', { id: 'hhh' }, 'hello') }, template: `<div id='hhh' style="aa:1;bb:2"><a>{{xxx}}{{ccc}}</a></div>` }).$mount('#app') console.log(vue) // 渲染根节点 // 有el直接取, 没有调用$mount() // 渲染模板 // 有render优先执行 // 有template: 解析, 调用render渲染 // 无template: 解析el根节点的outerHTML, 调用render渲染 - 组件渲染
用Vue.extend() 构建子组件构造函数
调用子组件时实例化,$mount()挂载组件到vm.$el上,添加子组件的watcherVue.use(MyPlugin) MyPlugin.install = function (Vue, options) { // 1. 添加全局方法或属性 Vue.myGlobalMethod = function () {} // 2. 添加全局资源 Vue.directive('my-directive', { bind (el, binding, vnode, oldVnode) {} }) // 3. 注入组件选项 Vue.mixin({ created: function () {} }) // 4. 添加实例方法 Vue.prototype.$myMethod = function (methodOptions) {} } var MyCompontent = Vue.extend({template: ‘<div></div>’}) Vue.component(‘my-component’, MyCompontent) new MyCompontent().$mount(‘#app’) / new MyCompontent({el:‘#app’}) - 模板下只能有一个根节点(diff算法只允许一个·根节点)
patchVnode()
diff 先比同级,再比子节点
判断有没有子节点
比较都有子节点
递归比较同级子节点
git 前端提交规范
commitizen(vue+commitlint+husky)
npm install --save-dev
"@commitlint/cli": "^8.2.0"
"@commitlint/config-conventional": "^8.2.0"
npm install husky --save-dev
新建commitlint.config.js
后端文件流返回时有哪些字段
header: {},
data: {},
config: {}