一、组件封装涉及的知识点
- vue基础语法
- 组件基础语法
- 组件通信(sync、provide、inject)
- 插槽的使用
- props校验
- 过渡与动画处理
- 计算属性和监听属性
- v-model语法糖
- vue插件机制
- npm发布
二、组件封装实践收获
- 掌握组件封装的语法和技巧
- 学会造轮子,了解element-ui组件库的实现原理
- 搭建和积累自己的组件库
三、创建自己的组件封装项目
1、使用vue-cli创建组件封装项目
vue create hhz-components
复制代码
2、项目创建完成以后,将components文件夹下的自带的组件HelloWorld.vue组件删除,将asset文件夹下面静态资源删除,最后将App.vue中的helloworld组件引用、使用和样式都删除,(别忘记了components下面的组件注册也删除)这样一个干净的项目就准备好了,下面开启组件封装的旅程吧!
想验证一下,项目清理的是否干净。
cd hhz-components
npm run serve
//如果项目正常启动,说明一个干净的项目准备工作也完成了。
复制代码
四、封装第一个自己的组件—button
1、在components文件夹面创建一个button文件夹,在该文件夹创建一个hhzbutton.vue文件,写入下面组件代码进行测试:
<template>
<div>
我是魂魂张的button组件
</div>
</template>
<script>
export default {
name: 'hhzbutton'
}
</script>
<style scoped>
</style>
复制代码
2、在main.js配置文件中将自己封装的组件注册为全局组件
//先导入组件
import hhzbutton from './components/hhzbutton/hhzbutton.vue'
//全局注册组件,第一个参数注册为全局组件所定义的名字,第二个是组件结构,其实就是
//你上面导入的那个组件
Vue.component(hhzbutton.name,hhzbutton)
复制代码
3、在App.vue中去使用组件
<template>
<div id="app">
//在这里使用组件
<hhzbutton>hhz的button</hhzbutton>
</div>
</template>
<script>
//引入组件
import hhzbutton from './components/hhzbutton/hhzbutton.vue'
export default {
components: {
hhzbutton //在这里注册组件
},
}
</script>
<style>
</style>
复制代码
4、运行项目,如果运行成功且显示我是魂魂张的button组件
,说明组件封装的第一步,也是关键的一步,已经成功了,下面就正式开启组件封装的旅程了!
经验告诉我们在开发的时候一定要关闭
eslint
检查!!!或者安装Prettier ESLint
插件帮助我们检查和自己格式化,千万不要选择standard,你会后悔的!!!
5、基本理解了封装组件和引用组件的步骤之后,下面我们就开始在前面的基础上去封装一个真正的button组件。将button.vue 文件写入如下代码:
<template>
<div>
<button class="hhz-button">
<span>
<slot></slot>
</span>
</button>
</div>
</template>
<script>
export default {
name: 'hhzbutton'
}
</script>
<style lang="scss" scoped>
.hhz-button{
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #ffffff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: 0.1s;
font-weight: 500;
-moz-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
&:hover,
&:hover{
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
}
</style>
复制代码
整个组件中,包括了template标签的HTML部分,还有script中的js部分(组件逻辑代码),最后是组件的样式部分。这时候去查看,你就会看你到组件具有了样式,真的就像是组件库中的组件一样了,当然样式可以根据自己的喜好,去自我定义。
6、为button组件添加type属性,使其根据在使用hhzbutton组件的时候给予其不同的类名来自我选择不同的样式进而去改变样式。这是一种同一类型组件,绑定多个属性,然后可以根据使用者的不同选择来得到想要样式的组件。
想要实现根据组件的不同的type来得到不通样式的组件,需要指导怎么样进行组件通信,还有知道怎样去props校验来提高安全性。
- props校验
//封装组件的时候通常会对props进行校验约束,提高器安全性
// props: ['type']
props:{
type: {
type: String,
default: 'default'
}
},
复制代码
- 父子组件通信
父子组件通信时通过在子组件定义props属性,然后,在使用父组件使用子组件的地方使用这个变量作为属性,这样在子组件就可以获取到父组件传递过来的属性值了。
//父组件使用这个变量作为属性,并设置属性值
<hhzbutton type="info">hhz按钮</hhzbutton>
<hhzbutton type="danger">hhz按钮</hhzbutton>
//子组件可以接受到父组件传递过来的数据了,也就可以去使用了。
<button class="hhz-button" :class="[`hhz-button-${type}`]">
<span>
<slot></slot>
</span>
</button>
复制代码
- 子组件取值变属性
根据父组件传递过来的属性值,子组件获取属性值以后绑定到动态class属性上面去,然后再组件文件的下面设置好对应的css属性,就可以根据使用者的设置来改变button的样式了。
.hhz-button-primary{
color:#fff;
background-color: #409eff;
border-color: #409eff;
&:hover,
&:focus{
background: #66b1ff;
background-color: #66b1ff;
color: #fff;
}
}
.hhz-button-success{
color:#fff;
background-color: #67c23a;
border-color: #67c23a;
&:hover,
&:focus{
background: #85ce61;
background-color: #85ce61;
color: #fff;
}
}
.hhz-button-info{
color:#fff;
background-color: #909399;
border-color: #909399;
&:hover,
&:focus{
background: #a6a9ad;
background-color: #a6a9ad;
color: #fff;
}
}
.hhz-button-warning{
color:#fff;
background-color: #e6a23c;
border-color: #e6a23c;
&:hover,
&:focus{
background: #ebb563;
background-color: #ebb563;
color: #fff;
}
}
.hhz-button-danger{
color:#fff;
background-color: #f56c6c;
border-color: #f56c6c;
&:hover,
&:focus{
background: #f78989;
background-color: #f78989;
color: #fff;
}
}
复制代码
7、朴素类型封装,意思是将一个组件在父组件中使用的时候,使用一个plain
属性的时候,所有的按钮就都变成朴素样式的。原因同理,在组件封装的时候,先定义好样式,根据父组件传回的布尔值,来判断是true还是false,来决定是否启用朴素样式。子组件在接收到plain时候,也是将其绑定到类名上,因为传回的是布尔值,所以类名绑定上使用对象。最后在props中定义plain数据。
- 朴素按钮样式的定义
// 朴素样式定义
.hhz-button.is-plain{
&:hover,
&:focus{
background: #fff;
border-color: #489eff;
color: #409eff;
}
}
.hhz-button-primary.is-plain{
color: #409eff;
background: #ecf5ff;
&:hover,
&:focus{
background: #409eff;
border-color: #409eff;
color: #fff;
}
}
.hhz-button-success.is-plain{
color: #67c23a;
background: #c2e7b0;
&:hover,
&:focus{
background: #67c23a;
border-color: #67c23a;
color: #fff;
}
}
.hhz-button-info.is-plain{
color: #909399;
background: #d3d4d6;
&:hover,
&:focus{
background: #909399;
border-color: #909399;
color: #fff;
}
}
.hhz-button-warning.is-plain{
color: #e6a23c;
background: #f5dab1;
&:hover,
&:focus{
background: #e6a23c;
border-color: #e6a23c;
color: #fff;
}
}
.hhz-button-danger.is-plain{
color: #f56c6c;
background: #fbc4c4;
&:hover,
&:focus{
background: #f56c6c;
border-color: #f56c6c;
color: #fff;
}
}
复制代码
- 子组件props中加入变量plain
props:{ plain:{ type: Boolean, default: false } }, 复制代码
- 父子组件绑定plain属性
//父组件 <hhzbutton plain class="hhzbutton" type="info">hhz按钮</hhzbutton> <hhzbutton plain class="hhzbutton" type="danger">hhz按钮</hhzbutton> <hhzbutton plain class="hhzbutton" type="success">hhz按钮</hhzbutton> <hhzbutton plain class="hhzbutton" type="primary">hhz按钮</hhzbutton> //子组件 <button class="hhz-button" :class="[`hhz-button-${type}`,{ 'is-plain':plain }]"> 复制代码
- 按钮事件绑定
在父组件中使用子组件,并在使用的子组件上绑定了一个事件,如果不去处理子组件,为子组件绑定事件,则父组件的事件无效,所以总结来说,在使用一个组件的时候,想让这个组件拥有可以绑定事件的能力,就需要对这个组件本身绑定事件的处理。以点击事件为准,当在父组件中点击这个组件,这个时候,子组件中回接收到被点击的信号,但是子组件本身是没有处理点击事件的能力的,就需要在子组件中绑定点击事件,并在methods中书写事件函数,这个事件函数很关键,因为它需要将这个事件返回给父组件,这时候,就会执行父组件中定义的处理函数逻辑!
//父组件
<hhzbutton @click="printABC" class="hhzbutton" type="info">hhz按钮</hhzbutton>
methods:{
printABC(){
console.log(132);
}
}
//子组件
<button class="hhz-button" :class="[`hhz-button-${type}`,{
'is-plain':plain
}]"
@click="handleClick"
>
methods:{
// 当父组件注册一个点击事件,点击了,会触发子组件的点击事件,子组件只需要
//将点击事件告诉并传回父组件,这样父组件就会拥有点击事件,并执行自己定义的点击事件
handleClick(e){
this.$emit('click',e);
}
},
复制代码
- disabled属性封装
disabled属性的封装和前面的plain属性封装几乎是差不多的,都是采用了父组件传值,子组件中先定义该默认属性值为false,然后定义后disabled属性样式,最后在子组件中为其绑定动态class!只要在父组件中使用了该属性,子组件获取值了,就可以为其加上这个属性。
//html
<button class="hhz-button" :class="[`hhz-button-${type}`,{
'is-plain':plain,
'is-disabled': disabled
}
]"
:disabled="disabled"
@click="handleClick"
>
//js
props:{
type: {
type: String,
default: 'default'
},
plain:{
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
},
//父组件
<!-- disabled -->
<hhzbutton @click="printABC" class="hhzbutton" type="info" disabled>hhz按钮</hhzbutton>
<hhzbutton class="hhzbutton" type="danger" disabled>hhz按钮</hhzbutton>
<hhzbutton class="hhzbutton" type="success" disabled>hhz按钮</hhzbutton>
<hhzbutton class="hhzbutton" type="primary" disabled>hhz按钮</hhzbutton>
复制代码