暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Vite+Vue3+TS组件库开发实战

村长学前端 2021-11-24
2276

反馈粉丝抽奖活动


前言

不少前端小伙伴问过我,说业务代码写了2、3年了,应该如何再进一步?

村长的回答中大多数会提到两个关键点:加强工程化实践能力底层原理源码知识

这里面尤其工程化实践能力对于小伙伴们在工作中解决问题的能力有直接影响,这也就影响了大家在团队内部的技术影响力、架构能力。说的更直白一点就是,如果你想成为小组的核心程序员,拿更高的职位和薪资,能够给大家搭架子,解决问题,重难点突破是非常关键的几个考察点。

那么我们如何快速提升工程化实践能力哪?

理论知识必不可少,大家可以看到公司中一些技术核心往往以下能力很强:

  • 他们有很强的组件抽象能力
  • 能够搭建公司的前端基础设施
  • 能够编写健壮、可维护的代码

实践中,我们如何刻意提升自己这方面的能力,我觉得给公司搭建一套组件库就很好。在这个过程中大家需要解决不少工程问题,比如:

  • 如何构建一个敏捷的开发、发布环境
  • 如何实现组件库文档系统
  • 引入jsx/tsx
  • 组件的设计与编写
  • 代码质量:eslint、单测等
  • 风格化、国际化等
  • ......

这些任务对于日常和业务打交道的同学来说当然很有挑战性,11月25日,村长特意准备了一节公开课《vue3+ts组件库开发实战》,准备给小伙伴们实战一下vue3组件设计和开发,并系统阐述组件库开发的一些知识

你将学习如下知识

  1. 构建一个敏捷的开发环境

  2. 如何设计组件通讯策略

  3. 组件内容分发机制

  4. 使用composition api合理构建组件逻辑

  5. 利用ts编写高可维护性代码

  6. 搭建规范的开源组件库工程

报名链接

vue3组件化知识

为了能够上好这节课,我们还要提前准备一些vue3组件化开发的基础知识:

组件通信

组件通信常⽤⽅式,vue3中有很多变化:

  • props:除了props选项

    {
     props: { msg: String }
    }

    vue3.2还出了script setup的新写法

    defineProps({
      model: { typeObject, required: true }
    });

  • $emit:

    现在只剩下派发事件的emit方法

    this.$emit('add', good)

    vue3.2还出了script setup的新写法

    const emit = defineEmits<{
      (e: "update:model-value", value: string): void;
      (e: "validate"): void;
    }>();
    emit("update:model-value", inp.value);被移除了!

    $on, $once, $off 被移除!上述3个⽅法被认为不应该由vue提供,因此被移除了,可以使⽤其他库实现等效功能。

  • import mitt from 'mitt'

    const emitter = mitt()

    // 发送事件
    emitter.emit('foo''foooooooo')

    // 监听事件
    emitter.on('foo', msg => console.log(msg))

  • event bus

    vue2
    时代我们常常使用一个vue实例来做事件总线,现在不行了:

    // vue2时代,现在因为没有$on不行了
    Vue.prototype.$bus = new Vue()

    // 组件里面
    this.$bus.$emit('xxx')

    // 其他组件
    this.$bus.$on('xxx', () => {})

    所以我们就使用上面的mitt
    方案来代替就好了!

  • vuex

    我们着重说vuex 4.x中的composition api写法:

    const store = useStore()
    store.commit('add')
    store.dispatch('add')

  • root

    兄弟组件之间通信可通过共同祖辈搭桥,root。

    // brother1
    this.$parent.$on('foo', handle)
    // brother2
    this.$parent.$emit('foo')

  • $children

    vue3中移除了该选项,官方建议我们访问子组件时使用$refs

  • $refs

    获取指定元素或组件

    // parent<HelloWorld ref="hw"/>mounted() {this.$refs.hw.xx = 'xxx'}

  • provide/inject

    能够实现祖先和后代之间传值

    // ancestorprovide() { return {foo: 'foo'} }// descendantinject: ['foo']

    在composition中有对应的api

    import {provide, inject} from vue// 提供数据provide(key, value)// 注入数据inject(key)

  • ⾮prop特性:

    非属性特性包含了⽗作⽤域中不作为 prop 被识别 (且获取) 的特性绑定 ( class 和 style 除外)。当⼀个组件没有声明任何 prop 时,这⾥会包含所有⽗作⽤域的绑定 ( class 和 style 除外)。在vue3中移除了attrs,这样用起来更简单了。

    // child:并未在props中声明foo<p>{{$attrs.foo}}</p>// parent<HelloWorld foo="foo"/>

    通过 v-bind="$attrs" 透传到内部组件——在创建⾼级别的组件时⾮常有⽤:

    // 给Grandson隔代传值,parent.vue<Child2 msg="lalala" @some-event="onSomeEvent"></Child2>// Child做展开<Grandson v-bind="$attrs"></Grandson>// Grandson使⽤<div @click="$emit('some-event', 'msg from grandson')"> {{msg}}</div>

插槽

插槽语法是Vue 实现的内容分发 API,⽤于复合组件开发。该技术在通⽤组件库开发中有⼤量应⽤。

匿名插槽

slot称为匿名插槽,作为占位符存在,将来被替换为传入内容。

// comp1<div>   <slot></slot></div>// parent<comp>hello</comp>

具名插槽

slot加上name就称为具名插槽,可以将内容分发到⼦组件指定位置

// comp2<div> <slot></slot> <slot name="content"></slot></div>// parent<Comp2><!-- 默认插槽⽤default做参数 --><template v-slot:default>具名插槽</template><!-- 具名插槽⽤插槽名做参数 --><template v-slot:content>内容...</template></Comp2>

作⽤域插槽

分发内容要⽤到⼦组件中的数据

// comp3<div> <slot :foo="foo"></slot></div>// parent<Comp3><!-- 把v-slot的值指定为作⽤域上下⽂对象 --><template v-slot:default="slotProps">来⾃⼦组件数据:{{slotProps.foo}}</template></Comp3>

Vue3中组件相关API变化总结

global-api改为实例⽅法

全局静态⽅法引发⼀些问题,vue3将global-api改为app实例⽅法

// vue2中// Vue.component()// vue3中const app = createApp({}) .component('comp', {template: '<div>i am comp</div>'}) .mount('#app')

移除.sync,统⼀为v-model

以前.sync和v-model功能有重叠,容易混淆,vue3做了统⼀。

<div id="app">  <comp v-model="data"></comp></div>

app.component('comp', {  template`    <div @click="$emit('update:modelValue', 'new value')">     i am comp, {{modelValue}}    </div>  `,  props: ['modelValue'],})

渲染函数api修改

不再传⼊h函数,需要我们⼿动导⼊;拍平的props结构。scopedSlots删掉了,统⼀到slots

import {h} from 'vue'export default {  render() {    const emit = this.$emit    const onclick = this.onclick    return h('div', [     h('div', { onClick(){ emit('update:modelValue''new value')} },         `i am comp, ${this.modelValue}`),     h('button', { onClick(){ onclick() }}, 'buy it!')    ])  },}

组件emits选项

该选项⽤于标注⾃定义事件及其校验等。

createApp({}).component("comp", {  template`...`,  // emits标明组件对外事件  emits: ['buy', '...']  // 还能对事件进行校验  emits: {    'update:modelValue': null, // 不做校验    buy(p) { // 校验buy事件      if (p === 'nothing') {        console.warn('参数⾮法');        return false      } else {        return true      }    }  },})


村长公开课

最后欢迎小伙伴们来参加11月25日村长公开课,又将是收获满满的一天!

文章转载自村长学前端,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论