elementui源码学习之仿写一个el-divider组件
正文
本篇文章记录仿写一个el-divider组件细节,从而有助于大家更好理解饿了么ui对应组件具体工作细节。本文是elementui源码学习仿写系列的又一篇文章,后续空闲了会不断更新并仿写其他组件。源码在github上,大家可以拉下来,npm start运行跑起来,结合注释有助于更好的理解。
github仓库地址如下:github.com/shuirongshu…
组件需求分析
关于分割线的组件,一般使用的场景有:
- 分割线之水平分割(如:段落与段落之间分隔)
- 水平分割线加上文字描述(文字描述位置一般是位于分割线的左侧、居中、右侧)
- 分割类型之垂直分割(横向的行内文字与文字之间的分割)
- 分割线样式类型(solid分割线或dashed分割线或dotted分割线)
因为垂直分割距离不够,所以垂直分割没有文字描述
组件中用到的知识点
函数式组件
我们知道,一个函数,其实就是一个加工流水线,我们入参,经过函数的加工以后,得到return加工后的结果。
对于组件而言,其实也可以当做一个函数(函数式组件),我们传递参数,组件props接收,然后组件再根据传参的不同,渲染出对应的样式效果。
这种方式和原来的我们使用组件的方式其实差不多,只不过更加精简,毕竟只考虑接收参数,没有生命周期、this实例之类的。所以函数式组件的渲染效率会比普通组件高。
所以有些情况下,使用函数式组件效率会更高
函数式组件的两种定义方式
比如,通过传参方式去渲染文字,可以有以下两种方式
方式一:render函数定义
<script>
export default {
functional: true, // 一定要指明是函数式组件
props: {
bookName: {
type: String,
default: "斗破苍穹",
},
},
// context上下文,有点像this的意思。但不一样
render: function (createElement, context) {
// 创建一个h3标签,标签内容是上下文对象中的props中的bookName字段
return createElement("h3", {}, context.props.bookName);
},
};
</script>
方式二:template定义
<!-- 模板标签上加上functional关键字表明是函数式组件 -->
<template functional>
<div>
<h3>{{ props.bookName }}</h3>
</div>
</template>
<script>
export default {
props: {
bookName: {
type: String,
default: "斗破苍穹",
},
},
}
</script>
关于函数式组件的具体细节,详情见官方文档:cn.vuejs.org/v2/guide/re…
这里为什么要提到函数式组件呢?因为el-divider
组件就是使用函数式组件进行封装的(因为组件只是做分割线条的展示,所以不需要有this实例,生命周期之类的)
故:为了提升渲染效率,这里使用函数式组件
使用函数式组件的情况大致有以下:
- 只做展示的组件,毕竟没啥逻辑操作相关
- 高阶组件的操作
- 循环中也可以考虑使用
- 整体来说,函数式组件还是比较灵活的
解决一像素太粗的问题
先看一下问题图
只需要给对应dom元素稍微缩放一下即可:
transform: scaleY(0.95);
或 transform: scaleX(0.95);
组件封装
el-divider
组件整体还是比较简单的,主要是函数式组件的参数使用细节
组件封装的效果图
组件封装的代码
使用的代码
<template>
<div class="wrap">
<h3>实线solid靠左</h3>
<my-divider class="staticClass_must_hava" content-position="left"
>早上好</my-divider
>
<h3>实线solid居中</h3>
<my-divider content-position="center">中午好</my-divider>
<h3>实线solid靠右</h3>
<my-divider content-position="right">下午好</my-divider>
<h3>虚线dashed靠左</h3>
<my-divider lineType="dashed" content-position="left">早上好</my-divider>
<h3>虚线dashed居中</h3>
<my-divider lineType="dashed" content-position="center">中午好</my-divider>
<h3>虚线dashed靠右</h3>
<my-divider lineType="dashed" content-position="right">下午好</my-divider>
<h3>圆点dotted靠左</h3>
<my-divider lineType="dotted" content-position="left">早上好</my-divider>
<h3>圆点dotted居中</h3>
<my-divider lineType="dotted" content-position="center">中午好</my-divider>
<h3>圆点dotted靠右</h3>
<my-divider lineType="dotted" content-position="right">下午好</my-divider>
<h3>竖向分割线</h3>
<span>早上好</span>
<my-divider direction="vertical"></my-divider>
<span>中午好</span>
<my-divider direction="vertical"></my-divider>
<span>下午好</span>
</div>
</template>
<script>
import myDivider from "./myDivider.vue";
export default {
components: { myDivider },
};
</script>
<style>
.wrap { padding: 24px; }
.staticClass_must_hava { border-bottom: 1px solid #baf !important; }
</style>
封装的代码
<template functional>
<!-- functional关键字加上后,即代表为函数式组件,就没有生命周期、this实例等了,故渲染更快,性能更高 -->
<!-- v-bind和v-on这里不加也行。毕竟函数式组件个人愚见简洁建议一些,attrs存放传递来的数据,listeners传递任何事件监听器 -->
<!-- data.staticClass需要加上,否则外层给组件加的class属性在审查元素的时候不会出现的,相当于没加 -->
<div
v-bind="data.attrs"
v-on="listeners"
:class="[data.staticClass, `${props.direction}`, `${props.lineType}`]"
>
<!-- 当分割线为水平的时候,且插槽有内容的时候,才渲染对应数据 -->
<!-- slots()方法返回插槽数据对象,default为默认插槽;相当于this.$slots.default。本系列文章中仿写一个el-tabs 也提到了此知识点 -->
<div
v-if="props.direction === 'horizontal' && slots().default"
:class="['text', `${props.contentPosition}`]"
>
<slot />
</div>
</div>
</template>
<script>
export default {
name: "myDivider",
props: {
// 分割线的方向,默认水平horizontal(垂直vertical可选)
direction: {
type: String,
default: "horizontal",
validator(val) {
return ["horizontal", "vertical"].includes(val);
},
},
// 文本内容位置,默认居中(仅当分割线为水平方向时,才渲染对应内容)
contentPosition: {
type: String,
default: "center",
validator(val) {
return ["left", "center", "right"].includes(val);
},
},
// 分割线线条类型,默认实线,可选虚线,圆点线
lineType: {
type: String,
default: "solid",
validator(val) {
return ["solid", "dashed", "dotted"].includes(val);
},
},
},
};
</script>
<style lang="less" scoped>
// 水平样式
.horizontal {
width: 100%;
border-bottom: 1px solid #333; // 默认solid分割线样式
display: block;
margin: 12px 0;
position: relative;
// 缩放0.95倍可以解决一像素问题(一像素看着比实际粗)横线Y缩放
transform: scaleY(0.95);
}
// dashed分割线
.dashed {
border-bottom: 1px dashed #333;
}
// dotted分割线
.dotted {
border-bottom: 1px dotted #333;
}
// 垂直样式
.vertical {
display: inline-block;
width: 1px;
height: 1em;
margin: 0 8px;
background-color: #333;
vertical-align: middle;
position: relative;
top: -1px; // 微调一下位置
// 缩放0.95倍可以解决一像素问题(一像素看着比实际粗)竖线X缩放
transform: scaleX(0.95);
}
// 文本样式
.text {
position: absolute;
padding: 0 12px;
color: #333;
font-size: 14px;
transform: translateY(-50%); // y轴移动自身的一半,使其垂直方向居中
background-color: #fff; // 通过背景色和padding去盖住水平分割线条
}
// 文本靠左
.text.left {
left: 36px;
}
// 文本靠右
.text.right {
right: 36px;
}
// 文本居中
.text.center {
left: 50%;
// 居中的话,别忘了要回正。即XY轴方向都平移自身的一半
transform: translateX(-50%) translateY(-50%);
}
</style>
以上就是elementui源码学习之仿写一个el-divider组件的详细内容,更多关于elementui仿写el-divider的资料请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341