vue3 Composition API vs vue2插槽

373 阅读1分钟

vue3 Composition API

vue3目前已经被广泛看到了,其中取代vue2中mixin功能的Composition API,算是比较大的改进,其优点在于合理提取公共模块,并且无侵入的引用,具体看如下示例

//useCounter.js
import { ref, computed } from "vue";

export default function () {
  const count = ref(0);
  const double = computed(() => count * 2)
  function increment() {
    count.value++;
  }
  return {
    count,
    double,
    increment
  }
}

以上封装了一个包含变量和让变量响应式变化的一个功能函数,如下式对该功能的引用

<template>
  <div>
    <span>当前值:{{count}}</span>
    <span>两倍值:{{double}}</span>
    <button @click="increment">增加</button>
  </div>
</template>

<script>
import useCounter from "./useCounter.js";

export default {
  setup() {
    const { count, double, increment } = useCounter();
    return {
      count,
      double,
      increment
    }
  }
}  
</script>

以上可以看出vue3 Composition API确实很聪明的解决了功能函数重复利用的问题,并且避免了mixin中导致的命名空间冲突,增加了重复功能编写的灵活性


vue2 函数组件

vue2的函数组件渲染和插槽,能实现个类似vue3中composition Api的功能,don't say so much,先上代码

<script>
export default {
  props: {
    depth: { type: Number, default: () => 1 },
    data: { type: Array, default: () => [] }
  },
  data () {
    return {
      activeMap: {}
    }
  },
  render: function (createElement) {
    const depth = 1
    const res = []
    const activeMap = this.activeMap
    const pushMenu = (data, depth) => {
      if (!data || data.length <= 0) return res
      const active = activeMap[depth] || data[0]
      activeMap[depth] = active

      const tem = this.$scopedSlots.default({
        data,
        depth,
        active,
        click: (item, depth) => {
          activeMap[depth] = item
          activeMap[depth + 1] = null
          activeMap[depth + 2] = null
          this.$forceUpdate()
        }
      })

      res.push(tem)
      const subMenu = active._child
      if (subMenu && subMenu.length) {
        pushMenu(subMenu, depth + 1)
      }
    }
    pushMenu(this.data, depth)

    return createElement('div', [
      ...res
    ])
  }
}
</script>

// 组件使用部分
<menu-slot :data="datas">
  <div
    slot-scope="{ data, depth, active, click }"
    class="wrap"
  >
    <div class="menu-wrap">
      <div
        v-for="item in data"
        :key="item.id"
        :class="`menu-item menu-${depth} ${active.id == item.id ? 'acitve' : ''}`"
        @click="click(item, depth)"
      >
        <span class="title">{{ item.name }}</span>
      </div>
    </div>
  </div>
</menu-slot>

上面代码在menu-slot函数式渲染组件中只包含了业务逻辑部分,利用this.$scopedSlots.default将各个变量传递到插槽node中, 而组件使用部分则是利用slot-scope对{ data, depth, active, click }几个参数进行了逻辑引入,最终实现功能

有没有发现这样的逻辑提取,类似于vue3的composition Api,值得好好体会下。。。

总结

vue3的到来,typescript的到来,前端代码会越来越具有像java一样的低耦合特性,这样也就需要我们前端人员在编写代码中要有更好的低耦合设计模式思维。


以上可能会有欠缺考虑的部分,望提出交流。