mixin
? 它主要就是用来抽离公共的逻辑,有两种方式使用,全局和局部,会跟自己组件中的代码进行合并,当然也有一个明显的缺点就是数据来源不明确,比如我组件里调用了个this.test()
方法,都不知道是哪里来的
// 全局混入
Vue.mixin({
created: function () {}
})
// 局部混入
mixins: [myMixin]
在elementUI中的应用
<el-form :model="form"></el-form>
? 可以看到它应用在了form表单中,当我们在input输入值后,这个值会映射到那个model里面,其实按道理来说的话组件的传值应该是一层层的调用的,但是我们不知道使用组件的人内部嵌套了多少层,所以使用了mixin的方式封装了传递数据的方式
// 使用mixin定义了broadcast公共方法
broadcast(componentName, eventName, params) {
broadcast.call(this, componentName, eventName, params);
}
// 组件中使用这个方法,实际就是个广播
// 通过一个dispatch方法一层一次的找componentName(通过组件内部的name)
updatePopper() {
this.broadcast(‘ElSelectDropdown‘, ‘updatePopper‘);
this.broadcast(‘ElDropdownMenu‘, ‘updatePopper‘);
},
? broadcast是从祖先放下找,dispatch是从子孙往上找
合并策略
- 数据对象,在内部会进?递归合并,并在发?冲突时以组件数据优先
- 钩?函数将合并为?个数组,先调用Mixin的钩?
- 值为对象的选项,例如 methods、components 和 directives,将被合并为同?个对象。两个对象键 名冲突时,取组件对象的键值对。
插槽
匿名插槽
// 封装的一个通用组件,内部使用插槽
<div>
<slot></slot>
</div>
// 使用这个组件,假设叫CqModal
<CqModal>
<div>content</div>
<CqModal>
具名插槽
<div>
<slot name="title"></slot>
<slot></slot>
</div>
<CqModal>
<h1 v-slot:"title">title</h1>
<div>content</div>
<CqModal>
作用域插槽
? 以上在使用组件CqModal中,数据都是写在使用这个CqModal的组件中的,假设我把数据写在了CqModal这个通用组件里面,在子组件中如何获取这个数据呢
<div>
<slot :title="title"></slot>
<slot></slot>
</div>
...
data() {
return {
title: "一个标题"
}
}
<CqModal>
<h1 v-slot="slotData">{{ slotData.title }}</h1>
<div>content</div>
<CqModal>
? slotData
这个名称无所谓,可以随便写,也即是说我只要定义v-slot=xxx
,就可以从xxx
上面拿到slot
标签上面挂的属性
插槽的编译
? ?级模板?的所有内容都是在?级作?域中编译的;?模板?的所有内容都是在?作?域中编译的(编译就是把template转为render函数,渲染就是只把render函数变为虚拟dom的过程)
插件
? 插件通常?来为 Vue 添加全局功能,?如vue-router vuex,编写插件需要暴露一个install方法,调用Vue.use会执?插件的install?法
实现element-ui中的message插件
import Message from ‘./plugin/message‘
Vue.use(Message)
// 通过插件调用
showMsgByPlugin() {
this.$message.info({
message: ‘插件消息‘,
duration: 4000,
})
}
// 普通方法调用
showMsg() {
Message.info({
message: ‘消息‘,
duration: 3000
})
}
// 导出install方法
export default {
install(Vue) {
Vue.prototype.$message = {
info: Message.info
}
}
}
<!-- Message组件 -->
<template>
<div class="el-messages">
<div v-for="m in messages" :key="m.id">{{m.message}}</div>
</div>
</template>
<script>
export default {
data() {
return {messages: []}
},
mounted() {
this.id = 0; // 当前消息组件的id
},
methods: {
add(options) {
const id = this.id++;
const layer = {...options, id}
this.messages.push(layer)
setTimeout(() => {
this.remove(layer)
}, options.duration)
},
remove(layer) {
this.messages = this.messages.filter(message => message.id !== layer.id)
}
}
}
</script>
// message.js 使用插件
import Vue from ‘vue‘
import MessageComponent from ‘./Message.vue‘
let vm = null
const getInstance = function() {
if(!vm) {
// 单例模式
vm = new Vue({
render: h => h(MessageComponent)
}).$mount()
document.body.appendChild(vm.$el)
}
return vm.$children[0];
}
const Message = {
info(options) {
getInstance().add(options)
}
}
export {
Message,
}
export default {
install(Vue) {
Vue.prototype.$message = {
info: Message.info
}
}
}
过滤器
? 分为全局过滤器和局部过滤器
Vue.filter
filters: {
timeFormat(val, formatter) {
return moment(val).format(formatter)
}
}
响应式原理
? defineProperty
使用defineProperty的问题
对象
? vue?法监测对象的添加,比如this.info.a = 10,如在data里没有定义a就不行,解决方法是
? this.$set(this.someObject, ‘b‘ ,2)
数组
? defineProperty
?法监听数组索引值的变化,?如 this.a[0] = 44
,解决方式this.$set(this.a, 0, 44)
,或者this.a.splice(0, 1, 44)
,此外数组?度的变化也?法监听,可以这么解决this.a.splice(newLength)
其他
? 递归的循环data中的属性(可能会导致性能问题)
? 对于?些数据获取后不更改,仅仅?来展示的数据(?如说省、市)可以使?Object.freeze来优化性能 this.city = Object.freeze(data.city)
Vue的动画
基本动画
<template>
<transition name="fade">
<div></div>
</transition>
</template>
? 这样将来里面这个div会自动加一个类名,以fade开头
// 进入之前的状态 非常短暂 一帧 enter消失之后会立刻迎来enter-active
.fade-enter {
opacity: 0;
}
// 过渡的过程中,就是进入的过程中
.fade-enter-active {
transition: opacity .5s;
}
// 离开的最后一帧
.fade-leave-to {
opacity: 0;
}
// 离开的过程中
.fade-leave-active {
transition: opacity .5s;
}
Animate.css 动画库
? 它的动画类名跟Vue的是不一样的,Vue给我们提供了一些属性可以自定义动画类名,而且它的优先级较高,会覆盖Vue默认生成的类的,比如enter-active-class
? Animate给添加动画一般要添加两个名称,一个是animated,一个是动画名称如bounceIn
<transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut">
<div></div>
</transition>
JS动画钩子
<transition @before-enter="beforeEnter">
<div></div>
</transition>
beforeEnter(el) { // el就是div
el.style.opacity = 0
}
enter(el, done) {
// 触发回流激活动画
document.body.offsetHeight;
el.style.opacity = 1;
el.addEventListener(‘transitionend‘, done)
}
// 再配合之前的css即可
纯JS方案
? 比如可以引入velocity.js 就连过度的css也不需要了
enter(el, done) {
Velocity(el, { opacity: 1 }, { duration: 1500, complete: done })
}