Vue.js高级用法

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; 
}
Vue.js高级用法

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 })
}

Vue.js高级用法

上一篇:js 判断用户是否联网


下一篇:elementUI i中的 el-upload上传音频文件获取音频时间长度