Vue的'奇技淫巧'

11,180 阅读5分钟

引言


在Vue的单页面的应用中我们已经习惯了使用了模板语法、js代码、以及样式的三部曲实现,这样的普适的写法已经能够满足大部分的开发需求,Vue在官网中还提供了许多灵活的高效的语法、API来提供给开发者使用,我们下面来看看这些好用有趣的。

正文

一、混入(mixin)

混入 (mixin) 提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。一个混入对象可以包含任意组件选项即生命周期、基础数据、实例方法、当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。当我们在每个单页面中都需要使用到数据、方法都可以在一个外部的对象中定义然后导入到对应的实例中。就是可以认为是实例的加强。

// 单页面组件
<template>
   <div class=''>
       {{mixinData}} // '我是混入的数据'(可以引入到混入的对象的data)
   </div>
</template>
<script>
import mixin from'./mixin'
export default {
  mixins:[mixin],
  data () {
    return {
      innerData:'我是单页面本身的数据'
    };
  },
  methods: {
    mixins(){
      alert('我是单页面的方法')
    }
  },
  created() {
    alert('我是单页面本身created的生命周期')
    this.mixins()  // 
  },
}

// 混入的对象mixin
export default {
    created(){
        alert('我是mixin内部的created的生命周期')
    },
    data(){
        return {
            mixinData:'我是混入的数据'
        }
    }, 
    methods: {
        mixins(){
          alert('我是mixin内部的方法')
        }
    },
}

输出的结果:我是mixin内部的created的生命周期 -> 我是单页面本身created的生命周期 -> 我是单页面的方法
总结注意敲黑板

  • 同名钩子函数(created,mounted等)将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
  • 值为对象的选项,例如methods、components和directives等将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对一切以组件优先
  • 数据对象data在发生冲突时以组件数据优先

二、渲染函数

VUE在模板文件中使用的还是html js css 分离的模板语法来构建单页面的应用,但是笔者感觉对html的标签的控制略显不足,对于根据数据的不同展示不一样的标签可能会出现支持不够的情况,或者说需要完全遍历所有的可能的情况。这样无疑是冗余的也是低效的。

这边我们引入官方的实例来更好的解释。

<template>
   <div class=''>    // 根绝参数来渲染出不同的行标签你会发现下面的代码是冗余的,不但代码冗长,而且在每一个级别的标题中重复书写了 <slot></slot>
      <h1 v-if="type === 1">
        <slot></slot>
      </h1>
      <h2 v-else-if="type === 2">
        <slot></slot>
      </h2>
      <h3 v-else-if="type === 3">
        <slot></slot>
      </h3>
   </div>
</template>
<script>
export default {
   props: {
    type: {
      type: Number, // 引入了一个父组件传入的参数
      default: 1
    },
  },
}
</script>
<style lang='less' scoped>
</style>

如果需要更多的行标签那么template中的又会逐渐增多,同时会增加判断语句的反复执行。这样既费力又不讨好的事情我们应该避免。于是我们会引入render()来进行渲染。也就是使用render函数来代替template标签中关于标签的渲染。

子组件
import Vue from 'vue'
Vue.component('Heading',{
    render:function(createElement){
         return createElement(`h${this.type}`,this.$slots.default) // 这行代码完成了模板渲染中的关于h标签的选择部分
    },
    props: {
       type: {
            type: Number,
            default: 1
        },
    },
})

<!--父组件-->
<Heading :type="2">123</Heading>  // 渲染结果 <h2>123</h2>

createElement是渲染函数可接受的参数,使用createElement可以构建出可供渲染的树结构。第一个参数为标签、第二个为标签对应属性值,第三个个可以嵌套的createElement数组也就是子标签的数组。数组内部的createElement选项也可以嵌套。详细的解决方案以及实例可以查看官方文档,这里是提供一种思路。

import Vue from 'vue'
Vue.component('Heading',{
    render:function(createElement){
         return createElement(`div`,[createElement('h1','h1的内容'),createElement('h2','h2的内容')])
    },
})
上述的渲染函数出来的dom等同于:
<div>
    <h1>h1的内容</h1>
    <h2>h2的内容</h2>
</div>

三、函数式组件

函数式组件区别于一般组件的是没有生命周期、响应式数据、计算属性等,也就是说函数式组件可以理解为它是一个没有vue实例的组件,他只接受一个props的传参,这个也为他带来了渲染快速的特点。

个人的使用场景:我会使用在多同级组件的封装。例如我这边有个展示的需求,我想要通过卡片、列表等可选择的展示方式展示同一份数据源。如果我们将这些代码都写在一个组件中解耦度低,如果我们将展示都写成组件,全部引入父组件这样代码又出现了冗余。于是我们可以提供一个组件来分发符合条件的组件。既可以单独使用各个展示组件,又可以使用同一封装的组件。

// 父组件
<template>
   <div class='father'>
        <card-component v-if="type===card"></card-component>  // 不同组件我们需要都引入到父组件中
        <list-component v-if="type===list"></list-component>
        <circle-component v-if="type===circle"></circle-component>
   </div>
</template>
<script>
export default {
  data () {
    return {
      type:'card'
    };
  },
}
</script>


//重写父组件
<template>
   <div class='father'>
        <function-component :type="type"></function-component>  // 函数组件分发
   </div>
</template>

//函数组件
<template functional>    // functional是标记模板语法这个组件是函数式组件,如果不使用模板就应该设置functional:true
   <div class='father'>
        <card-component v-if="prop.type===card"></card-component>  // 不同组件我们引入函数组件
        <list-component v-if="prop.type===list"></list-component>
        <circle-component v-if="prop.type===circle"></circle-component>
   </div>
</template>

结束

如果有新的还是会持续更新的哟。