本篇文章记录一下,仿写一个el-badge标记提示,有助于大家更好理解,饿了么ui的轮子具体工作细节。本文是elementui源码学习仿写系列的又一篇文章,后续空闲了会不断更新并仿写其他组件。源码在github上,大家可以拉下来,npm start运行跑起来,有助于更好的理解。github仓库地址如下: https://github.com/shuirongshuifu/elementSrcCodeStudy
知识点复习
还是像往常一样,为了便于更好的理解代码,咱们先复习一下,el-badge组件
中使用的一些曝光度不是非常高的知识点api
sup和sub标签
- sup标签可定义文本上标内容(如平方、立方、未读消息等...)
- sub标签可定义文本下标内容(一般是科学公式多一些)
代码举例:
<h5>未读消息<sup style="color:red">99+</sup></h5>
<h5>水是生命之源,化学分子式为:H<sub style="color:brown">2</sub>O</h5>
效果图:
由此我们可以明了,sup标签内写的文字,会自动放在右上方,也可以正常设置样式,所以使用sup标签用来做el-badge标记组件,的确是比较合适的。
不过因为需要使用插槽传入定义内容,所以饿了么UI中使用sup标签不像上述嵌套的,相当于并排的,如:<h5>未读消息</h5><sup style="color:red">99+</sup>
所以饿了么又通过样式定位修改其位置,使其在右上角了
props中的validator校验函数
假设需求:父组件传递给子组件的age属性字段的值需要为数字类型的
我们一般都会这样写:
props: {
age: Number,
},
或者这样写(额外指定一个默认值):
props: {
age: {
type: Number,
default: 100,
}
},
这样写一般也就够用了,不过如果要精细化校验,就需要使用props校验某个属性字段自带的validator
函数了。
比如新需求:父传子的age属性字段需为数字类型、且不能超过180
于是乎,我们使用validator函数可以这样写:
props: {
age: {
type: Number,
default: 100,
validator(val) { // validator函数接收的参数是父传子此字段的值
if (val <= 180) {
return true; // 返回true代表校验通过,不报[Vue warn]警告
} else {
return false; // 返回false代表校验不通过,报[Vue warn]警告,告知用户传值不对
}
},
},
}
这样的话,的确是更方便精细化控制父传子参数了。官方说明:https://cn.vuejs.org/v2/guide/components-props.html#Prop-%E9%AA%8C%E8%AF%81
仿写效果图
使用代码
<template>
<div class="wrap">
<my-badge :value="11" type="primary">
<h5>primary类型</h5>
</my-badge>
<br />
<br />
<my-badge :value="22" type="success">
<h5>success类型</h5>
</my-badge>
<br />
<br />
<my-badge value="0" type="warning">
<h5>warning类型</h5>
</my-badge>
<br />
<br />
<my-badge :value="44" type="info">
<h5>info类型</h5>
</my-badge>
<br />
<br />
<my-badge :value="55" type="danger">
<h5>danger类型</h5>
</my-badge>
<br />
<br />
<my-badge :value="188" :max="99">
<h5>指定max最大值99</h5>
</my-badge>
<br />
<br />
<my-badge is-dot>
<h5>小圆点</h5>
</my-badge>
<br />
<br />
<my-badge value="热点追踪">
<h5>《震惊!一程序猿光天化日竟然...网友必看!》</h5>
</my-badge>
<br />
<br />
<my-badge :isShow="isShow" value="^@^">
<h5>隐藏</h5>
</my-badge>
<br /><button @click="isShow = !isShow">隐藏显示切换</button>
</div>
</template>
<script>
export default {
data() { return { isShow: true } },
};
</script>
<style lang="less" scoped> .wrap { width: 100%; height: 100%; padding: 24px;} </style>
仿写封装代码
<template>
<div class="my-badge">
<slot></slot>
<!-- 使用sup上标,让sup标签内的文字内容渲染在的右上角(需要嵌套),但是
这里的写法不会让sup标签的文字直接渲染到右上角,还需定位移动控制一下样式 -->
<transition name="el-zoom-in-center">
<!-- el-zoom-in-center过渡动画是自带的哦,咱们直接加上就能用啦 -->
<sup
v-show="showSup"
:class="[
'fixedRightTop',
typeArr.includes(type) ? type : '', /** 类型数组是否包含传进来的类型,包含就应用此类型样式,不包含就不应用类型样式 */
isDot ? 'isDotClass' : '', /** isDot为true就加上小圆点样式类型 */
]"
v-text="showValue"
></sup>
</transition>
</div>
</template>
<script>
// 定义这五种类型
const typeArr = ["primary", "success", "warning", "info", "danger"];
export default {
name: "myBadge",
props: {
value: [String, Number],
type: {
type: String,
validator(val) {
// console.log("校验参数", val);
// props也可以加入类型校验函数,vue自带的哦,不符合就抛出警告
if (typeArr.includes(val)) {
return true;
} else {
return false;
}
},
},
max: {
type: Number,
validator(val) { // 校验最大值要是数字
if (val) {
if (typeof val === "number") {
return true;
} else {
return false;
}
} else {
return true;
}
},
},
isDot: Boolean,
isShow: {
// 默认展示
type: Boolean,
default: true,
},
},
data() { return { typeArr } },
computed: {
showValue() {
// 如果是小圆点,就不用返回值
if (this.isDot) {
return;
}
// 如果告知最大值,就做一个判断
if (this.max) {
return this.value > this.max ? `${this.max}+` : this.value;
}
// 其他的情况,无论是数字或者自定义文字,就正常显示即可
else {
return this.value;
}
},
showSup() {
// isShow为false就隐藏喽
if (!this.isShow) {
return false;
}
// 内容为空,也隐藏咯
if (this.value === "") {
return false;
}
// 其他正常显示
return true;
},
},
};
</script>
<style lang="less" scoped>
.my-badge {
position: relative;
vertical-align: middle;
display: inline-block; // 把块元素转换成行内块元素,如此,宽度便由内容撑开了
// 通过定位,把上标定位到右上角的哦
.fixedRightTop {
position: absolute; // 因为上方display: inline-block;了
top: 0; // 所以定位才正好在插槽内容的右上方了,否则块元素默认宽度100%,那定位就在最右侧了
right: 3px; // 但是还需要transform平移一下
}
sup {
color: #fff;
background-color: #f56c6c; // 默认淡红色
border-radius: 10px; // 加个圆角好看些
padding: 1px 4px;
font-size: 12px; // 上标字体要设置最小
transform: translate(100%, -50%); // 要移动一下才行
white-space: nowrap; // 自定义文字内容会换行,通过css控制,使之不换行
}
// 五种类型配色,这里直接抄官方的
.primary { background-color: #409eff; }
.success { background-color: #67c23a; }
.warning { background-color: #e6a23c; }
.info { background-color: #909399; }
.danger { background-color: #f56c6c; }
// 小圆点加样式
.isDotClass { height: 8px; width: 8px; right: 1px; border-radius: 50%; }
}
</style>
总结
好了,一篇water文章
写完啦(手动捂脸哭),不过愚以为不断学习、不断输出、大抵便是不断进步吧