This article records and imitates the details of an el-divider component, which will help you better understand the specific working details of the corresponding component of Ele.me ui. This article is another article in the elementui source code learning and imitation series. I will continue to update and imitate other components when I am free. The source code is on github, you can pull it down, npm start to run, and comments are helpful for better understanding. The github warehouse address is as follows: https://github.com/shuirongshuifu/elementSrcCodeStudy

Component requirements analysis

About the tag component, it is mainly used to display some label information. The general requirements are as follows:

  • tag标签文字颜色自定义
  • tag标签背景色自定义
  • tag标签边框颜色自定义
  • 控制是否展示关闭tag标签小叉号图标
  • 自定义tag标签的文字颜色、背景色、边框颜色
  • 标签的大小类型(大型、中型、小型标签)

Ele.me officially uses the render function written by the el-tag bf19fe81175757fe94cb11a2d1bac9c3--- function, so here we also use the render function to write. Overall, this component is relatively simple. Pay attention to the syntax of jsx .

Component renderings

If you see the effect, you can directly copy and paste it to run, and it is more helpful to understand with the comments. The most complete code is on github

code to use

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

code that wraps the component

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

Summarize

  • When you encapsulate your own components, it is best to learn from other UI component libraries. For example, the imitation here el-tag also refers to the design method of antD .
  • The other is to copy the components. Instead of copying all the official components, it is appropriate to choose and keep the functions of the more commonly used components, temporarily abandon the functions of the unpopular components, and add the functions commonly used by your company and your own understanding.
  • If there is an unpopular component function, you can consider encapsulating a separate component to solve it
  • Components need to integrate some functions, but cannot integrate very many functions, high cohesion
  • My level is limited, what I said is not necessarily correct, it is only for the reference of ^_^

水冗水孚
1.1k 声望584 粉丝

每一个不曾起舞的日子,都是对生命的辜负