头图
This article will record and imitate an el-badge markup prompt, which will help you better understand the specific working details of the wheel 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 and run npm start, which is helpful for better understanding. The github warehouse address is as follows: https://github.com/shuirongshuifu/elementSrcCodeStudy

Knowledge point review

As usual, in order to better understand the code, let's review some of the knowledge point APIs that are not very exposed in el-badge组件

sup and sub tags

  • The sup tag defines the text superscript content (such as squared, cubed, unread messages, etc...)
  • The sub tag can define the subscript content of the text (usually more scientific formulas)

Code example:

 <h5>未读消息<sup style="color:red">99+</sup></h5>
<h5>水是生命之源,化学分子式为:H<sub style="color:brown">2</sub>O</h5>

Effect picture:

From this, we can understand that the text written in the sup tag will be automatically placed in the upper right corner, and the style can also be set normally, so it is indeed more appropriate to use the sup tag as the el-badge markup component.

However, because you need to use the slot to pass in the definition content, the sup tag used in the Ele.me UI is not like the above nested, which is equivalent to side-by-side, such as: <h5>未读消息</h5><sup style="color:red">99+</sup> So Ele.me is modified by style positioning its position so that it is in the upper right corner

validator validation function in props

Assuming requirements: The value of the age attribute field passed by the parent component to the child component needs to be a numeric type

We usually write like this:

 props: {
    age: Number,
},

Or write this (additionally specifying a default value):

 props: {
  age: {
    type: Number,
    default: 100,
  }
},

This is generally enough, but if you want to refine the verification, you need to use the props to verify the validator function that comes with a property field.

For example, new requirements: the age attribute field of parent-child transmission must be of numeric type and cannot exceed 180

So, we can use the validator function to write:

 props: {
    age: {
      type: Number,
      default: 100,
      validator(val) { // validator函数接收的参数是父传子此字段的值
        if (val <= 180) {
          return true; // 返回true代表校验通过,不报[Vue warn]警告
        } else {
          return false; // 返回false代表校验不通过,报[Vue warn]警告,告知用户传值不对
        }
      },
    },
}

In this case, it is indeed more convenient to finely control the parent-child parameters. Official description: https://cn.vuejs.org/v2/guide/components-props.html#Prop-%E9%AA%8C%E8%AF%81

Imitation renderings

use code

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

Copy the package code

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

Summarize

Okay, one article water文章 is finished (manually covering his face and crying), but I think that continuous learning, continuous output, and continuous improvement are probably


水冗水孚
1.1k 声望585 粉丝

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