Vue组件的tsx写法

简述

组件(Component) 是vue框架中最核心的概念,所有逻辑都围绕组件展开,得组件者,得天下。

这里我主要想说一下几种不同的组件写法,并阐明不同的写法的优缺点以及适用场景。

场景

这里通过一个简单的场景:统计Button点击次数,来展示不同的写法。

click-demo.gif

经典的三段式写法

<template>
  <div>
    You clicked: {{ count }} times
    <button @click="handleClick">
      Click me
    </button>
  </div>
</template>

<script lang="javascript">
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    handleClick() {
      this.count++
    }
  }
}
</script>

这里,用template申明了表现层,data()返回组件所需的数据,methods申明了处理逻辑。

在简单的场景下,把表现层,数据,处理逻辑申明在同一个文件问题并不大,可读性也能接受。

但假设,在上面的基础上还需要增加新的需求:1秒内多次点击的情况下,只统计1次

这种情况下,我们就需要把组件改成如下:

<template>
  <div>
    You clicked: {{ count }} times
    <button @click="handleClick">
      Click me
    </button>
  </div>
</template>

<script lang="javascript">
export default {
  data() {
    return {
      count: 0,
      // 增加一个标志位,控制是否进行点击统计
      shouldCount: true
    }
  },
  methods: {
    handleClick() {
      // 如果标志为 false,则说明还在上一次点击的1秒以内,则不统计
      if (!this.shouldCount) return
      // 否则进行统计, 并立即把标志位设定为false
      this.count++
      this.shouldCount = false
      // 1秒之后,重新激活标志位
      setTimeout(() => {
        this.shouldCount = true
      }, 1000)
    }
  }
}
</script>

改造之后,整个组件的逻辑部分开始膨胀。之前那种一目了然的感觉没有了。

数据部分data()多返回了一个shouldCount标志位,handleClick也结合标志位进行了相应控制。

这里把数据处理,转换,以及展示都混在一起了,造成了理解成本增加。

组合式写法(composition)

借助@vue/composition-api,使用组合式写法,组件可以简单如下:

<template>
  <div>
    You clicked: {{ count }} times
    <button @click="handleClick">
      Click me
    </button>
  </div>
</template>

<script lang="javascript">
// 数据,以及处理逻辑抽离到另外一个文件
import { useCounter } from 'path/to/counter-hook'

export default {
  setup() {
    const { count, increment } = useCounter({ initialValue: 0, delay: 1000 })
    return { count, increment }
  }
}

另一个文件counter-hook

import { ref } from '@vue/composition-api'
export const useCounter = ({intialValue = 0, delay = 1000}) => {
  const count = ref(intialValue)
  const increment = () => { count.value++ }
  return {
    count,
    increment: throttle(increment, delay)
  }
}

function throttle(cb, duration) {
  let shouldCall = true
  return function(...args) => {
    if (!shouldCall) return
    const context = this
    cb.apply(context, args)
    shouldCall = false
    setTimeout(() => {
      shouldCall = true
    }, duration)
  }
}

这种写法,把数据 和 展现层进行解耦。对于逻辑复杂的情况下,还可以将数据逻辑拆分到好几个文件,进一步分解数据处理逻辑。

另外,展现层独立于数据操作的情况下,团队成员可以分开并行开发UI和业务逻辑。同时,遵循了封装变化的原则。

组合式写法进阶版(tsx)

这种方式,对于熟悉tsx的开发者,可以获得更精细的展现层控制,以及类型推断带来的效率提升和bug率降低

// 注意,这里必须引入`h`,后续tsx语法依赖
import { defineComponent, h } from '@vue/composition-api'
// 数据,以及处理逻辑抽离到另外一个文件
import { useCounter } from 'path/to/counter'
export default defineComponent({
  setup() {![click-demo.gif](https://upload-images.jianshu.io/upload_images/11213662-443cdec75b5608c3.gif?imageMogr2/auto-orient/strip)

    const { count, increment } = useCounter({ initialValue: 0, delay: 1000 })
    return () => (
      <div>
        You clicked: { count } times
        <button onClick={increment}>
          Click me
        </button>
      </div>
    )
  }
})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容