vue3写作指南

前言

Vue 3 Core已经处于测试阶段两个多月了,喜欢新技术的我,尝试了vue3发现vue3对程序员的要求比以前高了很多,同时对ts的支持也提高了很多,本人经历了几个月的实践,总结了一些写vue3的技巧,和在写作过程中遇到的很多坑。

关于jsx

vue3 支持jsx写法,本来有一个编辑器项目,为了追求逼格,所以打算使用jsx来组织代码。随着项目的推进,发现jsx真的比模板语法差了很多,第一对代码的可维护性上没有html模板更加直观,同时写法难度很大,第二jsx 的render需要包含很多逻辑,对指令的支持非常不友好。推荐还是使用模板语法开发vue3组件。

关于ts

vue3 对TS的支持明显好了很多,不像以前还需要装饰器等等东西,现在的代码完全函数式,对代码的压缩优化都有了很大的提高,所以推荐vue3使用ts做开发语言

组件代码组织

通过文件夹的方式区分不同组件

推荐的组织方式

├── src/    ----- 代码目录
│   ├── components/        ----- 组件目录 
│   │   └── Wkbtn/         ----- 单个组件 
|   │   │   └── index.vue  ----- 组件入口文件
|   │   │   └── btn.d.ts  -----  定义各种接口
|   │   │   └── usebtn.ts  ----- 组件代码的抽离文件(可选)
|   │   │   └── usestate.vue  ----- 组件代码抽离的数据文件(可选)
...其他文件夹

关于组件代码是否需要抽离出去,我觉得根据组件的复杂度来衡量,没有一定的标准。开发过程应该是先写在一个文件,然后根据组件的抽离难度,来决定是否抽离,虽然不抽离index.vue的setup函数的代码量会非常多,但抽离也不是那么容易的,尤其在配合其他第三方库时候抽离有时候难度非常大,所以是否抽离需要根据实际情况.

vue3代码写作技巧

props定义优化

场景我有一个props里面需要判断给定的值,例如只能是success,或者info

export default defineComponent({
  props: {
    type: {
      type: String as PropType<'success' | 'info'>,
      default: 'info',
    },
  }
}

PropType 还支持传各种类型,例如函数

export default defineComponent({
  props: {
  	Tooltip: {
 		 type: Function as PropType<(val: number) => number | string>
	}
 }
}

PropType 还支持传各种类型,例如数组

export default defineComponent({
  props: {
  	numdata: {
 		 type:Array as PropType<Array<number>>
   }
 }
}

给组件声明事件

export default defineComponent({
 emits: ['click'],
}

除了系统默认事件,其他事件应该单独定义一个枚举文件。

//constant.ts文件
export const UPDATE_MODEL_EVENT = 'update:modelValue'   

//组件文件
import {UPDATE_MODEL_EVENT} from "constant"
export default defineComponent({
 emits: [UPDATE_MODEL_EVENT],
}

属性的传递

有时候做自定义组件的时候属性传递是很重要的,没必要每次一层层手动传递 有了 inheritAttrs: false 和 $attrs,你就可以手动决定这些 attribute 会被赋予哪个元。

<template>
  <div class="autocomplete">
    <wk-input ref="inputRef"  v-bind="$attrs"></wk-input>
  </div>
</template>
export default defineComponent({
  name: 'WkAutocomplete',
  inheritAttrs: false,
  props: {
  valueKey: {
    type: String,
    default: 'value',
  },
  modelValue: {
    type: [String, Number],
    default: '',
  },
  debounce: {
    type: Number,
    default: 300,
  },
  //..其他属性
  }
}

props相关

//在xx.d.ts 定义接口

 interface IElBacktopProps {
  visibilityHeight: number
  target: string
  right: number
  bottom: number
}
export default defineComponent({
 setup(props: IElBacktopProps,ctx){
   //其他代码
 }
}

默认props的数据类型不是响应式的所以如果需要响应式需要做一层转换

 const newProps=...toRefs(props)

provide的使用

provide 不支持异步注入,所以你再onMounted等生命周期里注入子孙组件是得不到值的,所以不要试图异步注入。而且provide只支持有层级关系的组件,2个兄弟组件是没办法通过provide和,inject得到值的。 provide和inject的最常见作用是开发嵌套组件,子孙组件得到上级组件的注入属性,例如 el-form,el-form-item,el-button,el-button-group。

vue3中路由的使用

vue3中路由不在绑定到this对象上,vue3不存在this,所以路由的写法有改变

import { useRouter } from 'vue-router'

const router = useRouter()

router.replace({name:"home"})//替换
router.push({name:"home"})//追加

说说ref

 const CarouselItem=ref<CarouselItem[]>=[]  //第一种情况
 const itemView=ref<Nullable<HTMLElement>>(null) //第二种情况
 const background = ref<Nullable<string>>(null) //第三种情况
 const openTimer = ref<TimeoutHandle>(null) //第四种情况

通过这几种组合可以让你的代码维护性,可读性,健壮性提升一个档次

再谈h函数

   import { h } from 'vue'

有时候我们的组件还需要支持命令式调用,这个时候h函数就非常有用,他可以命令式的创建各种组件。

 h(
      Transition,
      {
        name: 'dialog-fade',
        onAfterEnter: this.afterEnter,
        onAfterLeave: this.afterLeave,
      },
      {
        default: () => overlay,
      },
    )

vue3新组件teleport

用途: 可以控制HTML片段指定在某一父节点下呈现/渲染,而不必诉诸全局状态或将其拆分为两个组件,我觉得最大的功能就是入弹窗等组件,让他加入到body最后。或者有一些特殊的嵌套组件,指定加载在嵌套组件的末尾

<teleport to="body">
   <div v-if="modalOpen" class="modal">
     <div>
       I'm a teleported modal! 
       (My parent is "body")
       <button @click="modalOpen = false">
          Close
        </button>
    </div>
  </div>
</teleport>

谈谈reactive

谈谈reactive定义与refs的区别,我觉得refs定义多为基础类型,reactive多为符合类型。

 const data = reactive<{
    activeIndex: number
    containerWidth: number
    timer: null | ReturnType<typeof setInterval>
    hover: boolean
  }>({
    activeIndex: -1,
    containerWidth: 0,
    timer: null,
    hover: false,
  })

谈谈eventbus和组件实例

vue3 不再支持 on 和 off 所以使用 mitt 来替代 mitt是一个微型的库,实现了基本的 off on emit三个核心方法,所以又遇到需要使用eventbus的时候,使用这个库就可以了

vue3 组件不再有this,访问组件实例通getCurrentInstance方法


import { getCurrentInstance } from 'vue'
setup(){
   const { ctx } = getCurrentInstance()
   console.log(ctx.$router.currentRoute.value)
}