Vue.js 框架源码与进阶 - 封装 Vue.js 组件库

本文详细介绍了Vue.js组件开发的基础,包括CDD方法、处理组件边界情况、$attrs/$listeners、快速原型开发和使用ElementUI。进一步讨论了组件分类、步骤条和表单组件的开发,以及组件库管理,如Monorepo、Storybook和Lerna。此外,还涵盖了单元测试、Rollup打包和环境变量设置等关键点。
摘要由CSDN通过智能技术生成

14.1 组件开发基础

CDD 基础

  • CDD(Component-Driven Development)
    • 自上而下
    • 从组件级别开始,到页面级别结束
      • 先从相对完的的设计中抽象出来组件,先隔离开发组件然后再开发页面

CDD的好处

  • 组件在最大程度被重用
  • 并行开发
    • 对单个组件的开发使用CDD可以让以页面级开发无法实现的方式在不同团队之间共享任务:开发相对隔离的组件
  • 可视化测试
    • 通过一些工具可以直接浏览一些组件,而不需要到业务系统中再测试组件,可以对不同组件的状态进行测试

处理组件的边界情况

样例代码

src/main.js:在 Vue 的根实例中设置了title属性,在下面设置了handle方法打印了title的值

  • $root
    • src/01-root/:使用插着表达式把$root.title打印了出来,点击第一个按钮调用$root.handle获取title的值并打印到控制台,点击第二个按钮改变title 查看其是否为响应式的
      • 建议在组件比较少的小型项目中使用,实际开发中如果状态较多会难以维护
  • $parent / $children
    • src/02-parent/:创建了三个嵌套组件,在chile.vue中使用$parent.title获取parent.vuetitle并显示出来,同时也嵌套了第三个组件grandson.vue并使用$parent.$parent.title获取title显示出来
      • 通过$parent可以操作父组件的成员,它可以替换prop使用,prop是不允许修改的,通过$parent获取的成员可以直接修改。也就是在子组件中可以直接修改父组件中的成员,如果应用复杂的话会导致我们难以维护,而且嵌套过多使用也不方便
    • src/03-child/:这里定义了三个组件,parent中使用了children1children2两个组件,当点击按钮分别打印$children数组并分别获取对应索引的的组件,当拿到子组件后可以访问里面的title属性以及handle方法
  • $refs
    • src.04-ref/:定义了两个组件parentmyinputmyinput中放了一个input标签,通过v-model绑定了value属性,同时设置了ref="txt"。我们希望点击按钮时让子组件的input获取焦点,我们定义了focus方法this.$refs.txt.focus()来获取input标签,此处获取的为DOM对象。在parent组件中使用了myinput并设置ref="mytxt",当点击按钮通过this.$refs.mytxt.focus()获取自定义组件调用其focus方法
      • $refs可以用在两个地方:如果用在普通html标签上,通过$refs获取到的就是普通DOM对象;如果用在子组件上获取到的就是对应的子组件对象。需要注意的是我们需要等待组件渲染完毕之后在通过$refs获取子组件
  • 依赖注入 provide / inject
    • src/05-provide&inject:里面有三个组件和02-parent中的三个组件一致,我们希望在子组件中访问parent中的一些成员可以通过provide先在父组件中提供,再从子组件中通过inject注入,然后就可以在子组件中通过插值表达式展示
      • 需要注意的是:应该避免修改indect进来的成员,它不是响应式的。可以把依赖注入看做大范围的prop,父组件的成员在所有子组件、多层嵌套的子组件中都可以使用。依赖注入带来的负面影响是组件之间的耦合变高,子组件依赖父组件使重构变得更加困难

$attrs / $listeners

如果你需要开发自定义组件的话,你会用到这两个属性

  • $ attrs
    • 把父组件中非 prop 属性绑定到内部组件
  • $ liteners
    • 把组件中的 都没DOM对象的原生事件绑定到内部组件
  • src/06-attrs&listener:有两个组件,子组件myinput以及父组件parent

parent:

<template>
  <div>
    <myinput
      required
      placeholder="Enter your username"
      class="theme-dark"
      data-test="test">
    </myinput>
  </div>
</template>

<script>
import myinput from './02-myinput'
export default {
   
  components: {
   
    myinput
  }
}
</script>

myinput:

<template>
  <!--
    1. 从父组件传给自定义子组件的属性,如果没有 prop 接收
       会自动设置到子组件内部的最外层标签上
       如果是 class 和 style 的话,会合并最外层标签的 class 和 style 
  -->
  <input type="text" class="form-control">
</template>

<script>
export default {
   
}
</script>

image.png

如果设置了父组件中设置属性对应的prop

export default {
   
  props: ['placeholder', 'style', 'class']
}

image.png

我们可以发现此时placeholder没有设置成功,但是class却设置成功了,而且报了两个错误

image.png

它告诉我们classstyle是保留的属性,不能用在组件的prop

现在我们希望从父组件中接收的placeholder属性能够正常的设置到input标签上

<template>
  <input type="text" class="form-control" :placeholder="placeholder">
</template>

<script>
export default {
   
  props: ['placeholder']
}
</script>

image.png

如果设置prop来接受父组件中传递的属性需要自己在标签上绑定相应的属性,另外prop不能使用styleclass属性,如果不使用prop的话父组件默认传递过来的属性会绑定到template的根标签上。

如果inputdiv中包裹,此时会把父组件传递的属性设置给template的根元素,使用$attrs可以方便处理这种情况

<template>
  <div>
    <input type="text" class="form-control">
  </div>
</template>  

<script>
export default {
   
}
</script>

image.png

<template>
  <!--
    2. 如果子组件中不想继承父组件传入的非 prop 属性,可以使用 inheritAttrs 禁用继承
       然后通过 v-bind="$attrs" 把外部传入的非 prop 属性设置给希望的标签上

       但是这不会改变 class 和 style
  -->
  <div>
    <input type="text" v-bind="$attrs" class="form-control">
  </div>
</template>  

<script>
export default {
   
  inheritAttrs: false
}
</script>

image.png

我们演示了$attrs的使用,它可以让我们在子组件中更方便得控制父组件传过来的属性。

接下来来掩饰父组件给子组件传递事件:

parent.vue:

<template>
  <div>
    <myinput
      required
      placeholder="Enter your username"
      class="theme-dark"
      @focus="onFocus"
      @input="onInput"
      data-test="test">
    </myinput>
    <button @click="handle">按钮</button>
  </div>
</template>

<script>
import myinput from './02-myinput'
export default {
   
  components: {
   
    myinput
  },
  methods: {
   
    handle () {
   
      console.log(this.value)
    },
    onFocus (e) {
   
      console.log(e)
    },
    onInput (e) {
   
      console.log(e.target.value)
    }
  }
}
</script>

myinput.vue:

<template>
  <!--
    3. 注册事件
  -->
  <div>
    <input
      type="text"
      v-bind="$attrs"
      class="form-control"
      @focus="$emit('focus', $event)"
      @input="$emit('input', $event)"
    >
  </div>
</template>

<script>
export default {
   
  inheritAttrs: false
}
</script>

我们希望父组件注册的事件能够被触发

image.png

现在假设我们给这个文本框注册的事件很多,这样写就很麻烦。所以接下来我们通过$listeners来简化这件事

<template>
  <!--
    4. $listeners
  -->
  <div>
    <input
      type="text"
      v-bind="$attrs"
      class="form-control"
      v-on="$listeners"
    >
  </div>
</template>

<script>
export default {
   
  inheritAttrs: false
}
</script>

这里把注册文本框本身的事件和触发自定义事件换成了v-on="$listeners"
image.png

快速原型开发

Vue/cli 提供了快速原型开发的工具,它可以让我们很方便地运行一个单文件组件而不需要关心额外的配置

  • VueCLI 中提供了一个插件可以进行快速原型开发

  • 需要先额外安装一个全局的扩展

npm install -g @vue/cli-service-global
  • 使用 vue serve 快速查看组件运行效果

vue serve

  • vue serve 如果不指定参数默认会在当前目录找到以下的入口文件
    • main.js、index.js、App.vue、app.vue
  • 可以指定要加载的组件
    • vue serve ./src/login.vue
<template>
  <div>
    Hello Vue
  </div>
</template>

<script>
export default {
   

}
</script>

<style>

</style>
vue serve

image.png

快速原型开发 - ElementUI

我们除了可以从零开发组件外,还可以在第三方组件的基础上二次开发:比如在ElementUI的基础上开发自己的组件

安装 ElementUI

  • 初始化 package.json

    • npm init -y
      
  • 安装 ElementUI

    • vue add element
      
  • 加载 ElementUI,使用 Vue.use() 安装插件

接下来我们使用 ElementUI 做一个登录的组件:

image.png

删除掉src下多余的文件,此处不需要

在使用 ElementUI 之前,首先导入 ElementUI 注册插件

创建入口文件 main.js

import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import Login from './src/Login.vue'

Vue.use(ElementUI)

new Vue({
   
  el: '#app',
  render: h => h(Login)
})

Login.vue 组件

vue serve

image.png

14.2 组件开发

组件分类

  • 第三方组件:ElemenUI、iView
  • 基础组件:文本框、按钮、表单
  • 业务组件:结合特定的行业使用场景,可以根据用户的行为输出特定的界面

如果们要开发的应用对界面的要求不高,我们可以直接使用第三方组件;

如果对组件的样式有比较高的要求,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值