乐趣区

关于element-ui:elementui源码学习之仿写一个eltag

本篇文章记录仿写一个 el-divider 组件细节,从而有助于大家更好了解饿了么 ui 对应组件具体工作细节。本文是 elementui 源码学习仿写系列的又一篇文章,后续闲暇了会不断更新并仿写其余组件。源码在 github 上,大家能够拉下来,npm start 运行跑起来,联合正文有助于更好的了解。github 仓库地址如下:https://github.com/shuirongsh…

组件需要剖析

对于 tag 组件,次要是用于展现一些标签信息,个别的需要有如下:

  • tag 标签文字色彩自定义
  • tag 标签背景色自定义
  • tag 标签边框色彩自定义
  • 管制是否展现敞开 tag 标签小叉号图标
  • 自定义 tag 标签的文字色彩、背景色、边框色彩
  • 标签的大小类型(大型、中型、小型标签)

饿了么官网应用的是 render 函数编写的 el-tag,所以这里咱们也应用render 函数去写。整体来说,这个组件还是比较简单的。留神一下 jsx 的语法即可。

组件效果图

看成果的话,间接复制粘贴运行跑起来,联合正文更有助于了解。最残缺的代码在 github 上哦

应用之代码

<template>
  <div>
    <my-divider lineType="dotted" content-position="left"
      > 默认标签款式 </my-divider
    >
    <my-tag> 默认标签 </my-tag>
    <my-tag closable> 默认标签可敞开 </my-tag>

    <my-divider lineType="dotted" content-position="left"
      > 类型标签款式 </my-divider
    >
    <my-tag type="primary"> 类型标签 primary</my-tag>
    <my-tag type="primary" closable> 类型标签 primary 可敞开 </my-tag>
    <my-tag type="success"> 类型标签 success</my-tag>
    <my-tag type="success" closable> 类型标签 success 可敞开 </my-tag>
    <my-tag type="info"> 类型标签 info</my-tag>
    <my-tag type="info" closable> 类型标签 info 可敞开 </my-tag>
    <my-tag type="warning"> 类型标签 warning</my-tag>
    <my-tag type="warning" closable> 类型标签 warning 可敞开 </my-tag>
    <my-tag type="danger"> 类型标签 danger</my-tag>
    <my-tag type="danger" closable> 类型标签 danger 可敞开 </my-tag>

    <my-divider lineType="dotted" content-position="left"
      > 自定义标签款式 </my-divider
    >
    <my-tag color="blue"> 标签文字色彩自定义 </my-tag>
    <my-tag bgColor="pink"> 标签背景色彩自定义 </my-tag>
    <my-tag borderColor="red"> 标签边框色彩自定义 </my-tag>
    
    <my-divider lineType="dotted" content-position="left"
      > 中等标签及大型标签 </my-divider
    >
    <my-tag type="primary" sizeType="big" closable> 大型标签 </my-tag>
    <my-tag type="success" sizeType="medium" closable> 中型标签 </my-tag>
    <my-tag style="cursor: pointer" type="info" sizeType="small"
      > 默认 (小型) 标签,sizeType="small" 写不写都行的 </my-tag
    >

    <my-divider lineType="dotted" content-position="left"
      > 动静编辑标签 </my-divider
    >
    <my-tag
      v-for="(item, index) in arr"
      closable
      @close="handleClose(item)"
      @click="handleClick(item)"
      type="success"
      :key="item"
      >{{item}}</my-tag
    >
    <el-input
      v-model.trim="val"
      @blur="blurFn"
      size="mini"
      style="width: 120px"
    ></el-input>
  </div>
</template>

<script>
export default {data() {
    return {arr: ["标签一", "标签二", "标签三"],
      val: "",
    };
  },
  methods: {blurFn() {if (this.val === "") return;
      this.arr.push(this.val);
      this.val = "";
    },
    handleClose(tag) {
      // 找到点击的是哪个
      let i = this.arr.findIndex((item) => {return tag === item;});
      // 删除之
      this.arr.splice(i, 1);
    },
    handleClick(tag) {console.log("点击标签啦", tag);
    },
  },
};
</script>

封装组件的代码

<script>
const typeArr = ["primary", "success", "info", "warning", "danger"]; // 标签类型数组
const sizeType = ["big", "medium", "small"]; // 标签大小数组
export default {
  name: "myTag",
  props: {
    closable: Boolean, // 是否展现可敞开的小叉号图标
    color: String, // 标签文字的色彩
    bgColor: String, // 标签背景色
    borderColor: String, // 标签边框色彩
    // 五种标签类型
    type: {
      type: String,
      validator(val) {return typeArr.includes(val); // 校验类型
      },
    },
    // 三种标签大小
    sizeType: {
      type: String,
      validator(val) {return sizeType.includes(val); // 校验大小
      },
    },
  },
  methods: {handleClose(event) {
      /* 阻止冒泡避免与下方的 handleClick 办法抵触,要不然点击 close 敞开小图标,也会
         触发下方 click 事件的执行。即:内层事件阻止冒泡与外层事件隔离开来 */
      event.stopPropagation();
      this.$emit("close", event);
    },
    handleClick(event) {this.$emit("click", event);
    },
  },
  // render 函数 jsx 语法更加灵便
  render(h) {
    // 1. 筹备款式类 class 绑定 classArr 数组罕用款式,style 绑定 props 变量自定义款式
    const classArr = ["my-tag", this.type, this.sizeType];
    // 2. 筹备一个 dom,并绑定相干 class、style、event
    const tagEl = (
      <span
        class={classArr}
        style={{
          backgroundColor: this.bgColor,
          color: this.color,
          borderColor: this.borderColor,
        }}
        on-click={this.handleClick}
      >
        {/* 默认插槽渲染内容即 my-tag 标签中的文字 */}
        {this.$slots.default}
        {/* 三元表达式条件管制是否渲染敞开小图标 */}
        {this.closable ? (<span class="close-tag" on-click={this.handleClose}>
            x
          </span>
        ) : null}
      </span>
    );
    // 3. 返回 render 渲染之
    return <transition name="el-fade-in">{tagEl}</transition>;
    // 应用饿了么 UI 自带的突变过渡动画
  },
};
</script>
<style scoped>
/* 默认标签款式 */
.my-tag {
  display: inline-block;
  box-sizing: border-box;
  padding: 0 8px;
  color: #252525;
  background-color: #fafafa;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  height: auto;
  line-height: 20px;
  margin: 0 8px 8px 0;
}
/* 标签敞开小叉号款式 */
.close-tag {
  position: relative;
  margin-left: 5px;
  cursor: pointer;
  display: inline-block;
  transform: translateY(-6%);
}
/* 5 种类型标签款式 */
.primary {
  color: #409eff;
  border: 1px solid #d9ecff;
  background-color: #ecf5ff;
}
.success {
  background-color: #f0f9eb;
  border-color: #e1f3d8;
  color: #67c23a;
}
.info {
  background-color: #f4f4f5;
  border-color: #e9e9eb;
  color: #909399;
}
.warning {
  background-color: #fdf6ec;
  border-color: #faecd8;
  color: #e6a23c;
}
.danger {
  background-color: #fef0f0;
  border-color: #fde2e2;
  color: #f56c6c;
}
/* 默认小型标签款式,可选值为中等标签、大型标签。当然这里没有 small,因为 small 就是默认的 */
.big {padding: 4px 10px;}
.medium {padding: 2px 10px;}
</style>

总结

  • 大家封装本人的组件的时候,最好借鉴其余 UI 组件库,比方这里仿写 el-tag 也是参照了 antD 的设计形式。
  • 再一个就是仿写组件,不是把官网的组件全副照搬过去,而是适当取舍,保留比拟罕用的组件性能,临时摒弃冷门组件性能,并退出本人公司罕用的性能,以及本人的了解
  • 如果有遇到冷门的组件性能,能够思考再独自封装一个组件去解决
  • 组件须要集成一些性能,然而不能集成十分多的性能,高内聚
  • 自己程度无限,说的不肯定对,仅供各位道友参考 ^_^
退出移动版