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.vue的title并显示出来,同时也嵌套了第三个组件grandson.vue并使用$parent.$parent.title获取title显示出来- 通过
$parent可以操作父组件的成员,它可以替换prop使用,prop是不允许修改的,通过$parent获取的成员可以直接修改。也就是在子组件中可以直接修改父组件中的成员,如果应用复杂的话会导致我们难以维护,而且嵌套过多使用也不方便
- 通过
src/03-child/:这里定义了三个组件,parent中使用了children1和children2两个组件,当点击按钮分别打印$children数组并分别获取对应索引的的组件,当拿到子组件后可以访问里面的title属性以及handle方法
- $refs
src.04-ref/:定义了两个组件parent和myinput,myinput中放了一个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>

如果设置了父组件中设置属性对应的prop
export default {
props: ['placeholder', 'style', 'class']
}

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

它告诉我们class和style是保留的属性,不能用在组件的prop中
现在我们希望从父组件中接收的placeholder属性能够正常的设置到input标签上
<template>
<input type="text" class="form-control" :placeholder="placeholder">
</template>
<script>
export default {
props: ['placeholder']
}
</script>

如果设置prop来接受父组件中传递的属性需要自己在标签上绑定相应的属性,另外prop不能使用style和class属性,如果不使用prop的话父组件默认传递过来的属性会绑定到template的根标签上。
如果input在div中包裹,此时会把父组件传递的属性设置给template的根元素,使用$attrs可以方便处理这种情况
<template>
<div>
<input type="text" class="form-control">
</div>
</template>
<script>
export default {
}
</script>

<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>

我们演示了$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>
我们希望父组件注册的事件能够被触发

现在假设我们给这个文本框注册的事件很多,这样写就很麻烦。所以接下来我们通过$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"

快速原型开发
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

快速原型开发 - ElementUI
我们除了可以从零开发组件外,还可以在第三方组件的基础上二次开发:比如在ElementUI的基础上开发自己的组件
安装 ElementUI
-
初始化 package.json
-
npm init -y
-
-
安装 ElementUI
-
vue add element
-
-
加载 ElementUI,使用 Vue.use() 安装插件
接下来我们使用 ElementUI 做一个登录的组件:

删除掉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)
})
vue serve

14.2 组件开发
组件分类
- 第三方组件:ElemenUI、iView
- 基础组件:文本框、按钮、表单
- 业务组件:结合特定的行业使用场景,可以根据用户的行为输出特定的界面
如果们要开发的应用对界面的要求不高,我们可以直接使用第三方组件;
如果对组件的样式有比较高的要求,
本文详细介绍了Vue.js组件开发的基础,包括CDD方法、处理组件边界情况、$attrs/$listeners、快速原型开发和使用ElementUI。进一步讨论了组件分类、步骤条和表单组件的开发,以及组件库管理,如Monorepo、Storybook和Lerna。此外,还涵盖了单元测试、Rollup打包和环境变量设置等关键点。
最低0.47元/天 解锁文章

1687

被折叠的 条评论
为什么被折叠?



