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

4次阅读

共计 5456 个字符,预计需要花费 14 分钟才能阅读完成。

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

组件思考

简而言之,el-link 组件 就是给 a 标签包了一层,加上一些款式。故 link 组件 除了领有 a 标签的性能,还须要有一些可能应用的款式成果。所以,咱们仿写这个组件标签的时候次要是温习一下 传参的变量和款式的搭配,从而实现咱们须要的成果

组件的需要

  • link 组件 加上不同类型的链接款式,比方一般款式、胜利款式、正告款式、危险款式的链接款式
  • link 组件 加上鼠标悬浮时下划线。封装组件中应用的是伪元素搭配 border-bottom 实现的
  • 通过传参去管制 link 组件 什么时候有下划线,什么时候没有下划线
  • 另外,也须要思考组件会被禁用,禁用时,不能点击,不能跳转,且更换一下款式成果
  • 同时,link 组件 跳转链接时的一些操作
  • 也要是思考到 link 组件 须要搭配小图标去应用(本例中以饿了么 icon 为例)

组件的效果图

组件实现剖析

link 组件 加上链接款式

这里应用 动静 class 的数组用法 去管制,如下简略例子:

// html
<a
  :class="['myLink',
    type
]"
>

// js
props:{type: String, // 标签色彩的类型}

// css
.primary {color: #2d8cf0;}
.success {color: #19be6b;}
.warning {color: #f90;}
.danger {color: #ed4014;}

由上,比方传递的 type 参数值为 success,那么a 标签就会加上一个 success 的类名,这样的话,就会找到对应 css 中的类名,从而出现相应的色彩成果(当然 type 的值在底下 css 中要有对应的)

link 组件 加上鼠标悬浮时下划线

其实相似这种,悬浮下划线,悬浮上划线,悬浮非凡背景管制。大抵能够演绎为在次要dom 旁边加上一个小东西,都能够思考应用伪元素

对于啥是伪元素,这里不赘述

咱们看下方的鼠标悬浮上划线和下划线的效果图,这个效果图就是应用 伪元素搭配定位以及 border去实现的

代码:

// css
span {
     font-size: 24px;
     position: relative;
}
span:hover::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    height: 0;
    /* 定位管制 */
    top: 2px;
    border-top: 1px solid red;
}
span:hover::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    height: 0;
    /* 定位管制 */
    bottom: -2px;
    border-bottom: 1px solid red;
}

// html
<span> 早上好,程序猿兽们 </span>

通过传参管制是否加上下划线(即:是否加上这个下划线类名)

这里仍然是应用 动静 class 的数组用法 ,在数组中书写 四元表达式,简洁代码如下:

<a
    :class="['myLink',
       hideUnderline ? '': disabled ?'' : 'underline'
    ]"
  >

粗心:即不去暗藏下划线,又不去禁用这个 link 组件的时候,才加上 underline 类名,才产生下划线

应用 v-bind="$attrs" 兜底 a 标签的其余的未在 props 中申明的参数

<a
    :href="disabled ? null : href"
    v-bind="$attrs"
  >

咱们晓得 a 标签中有很多原生属性,如下图:

这么多 a 标签的属性,咱们不可能在封装的组件的时候,如果把每一个属性都在 props 中申明,倒是有些麻烦。所以此时 $attr 就应运而生了。对于 $attr$listener的用法,这里也不赘述,大家只有记得 $attr 是做参数属性兜底的即可。详情可看笔者之前写的文章:https://segmentfault.com/a/11…

组件需要因为篇幅起因就不赘述了,详情见代码中正文(毕竟这个组件其实也挺简略的),接下来上代码

代码

演示的话,间接复制粘贴即可,联合正文更好了解。留神 my-divider 组件是之前封装的组件。

笔者封装的组件和官网封装的组件在一些细节的中央可能略有不同,算是多一个 解法思路 ^o^

应用代码

<template>
  <div class="box">
    <my-divider lineType="dashed" content-position="left"
      > 五种链接款式 </my-divider
    >
    <my-link> 默认超链接 </my-link>
    <my-link type="primary">primary 超链接 </my-link>
    <my-link type="success">success 超链接 </my-link>
    <my-link type="warning">warning 超链接 </my-link>
    <my-link type="danger">danger 超链接 </my-link>
    <my-divider lineType="dashed" content-position="left"
      > 是否有下划线 </my-divider
    >
    <my-link> 默认有下划线 </my-link>
    <my-link hideUnderline> 也可暗藏下划线 </my-link>
    <my-divider lineType="dashed" content-position="left"
      > 禁用链接款式 </my-divider
    >
    <my-link disabled> 禁用 | 默认超链接 </my-link>
    <my-link type="primary" disabled> 禁用 |primary 超链接 </my-link>
    <my-link type="success" disabled> 禁用 |success 超链接 </my-link>
    <my-link type="warning" disabled> 禁用 |warning 超链接 </my-link>
    <my-link type="danger" disabled> 禁用 |danger 超链接 </my-link>
    <my-divider lineType="dashed" content-position="left"
      > 增加 href 和 target 原生属性 </my-divider
    >
    <my-link type="primary" href="https://www.baidu.com/"> 默认 self 跳转 </my-link>
    <my-link type="success" target="_blank" href="https://cn.bing.com/"
      > 反对原生属性 target 等 </my-link
    >
    <my-divider lineType="dashed" content-position="left"
      > 通过 icon 属性或者间接在默认插槽中增加图标 </my-divider
    >
    <my-link type="primary" icon="el-icon-share"> 默认图标在后方 </my-link>
    <my-link type="success" icon="el-icon-share" back
      >back 属性管制图标在前方 </my-link
    >
    <my-link type="primary"
      ><i class="el-icon-goods"></i> 默认插槽后方加图标 </my-link
    >
    <my-link type="success"
      > 默认插槽前方加图标 <i class="el-icon-goods"></i
    ></my-link>
    <my-divider lineType="dashed" content-position="left"
      > 绑定事件应用 </my-divider
    >
    <my-link @click="clickThis" type="danger" icon="el-icon-aim"
      > 点击这个哦 </my-link
    >
  </div>
</template>

<script>
export default {
  methods: {clickThis() {console.log("留神:当 myLink 禁用或有 href 属性时,点击事件生效");
    },
  },
};
</script>

封装组件代码

<template>
  <!-- 
       hideUnderline ? '': disabled ?'' : 'underline',
       先看 hideUnderline 是否为 true,为 true 则要暗藏下划线,即不加 underline 类名
       再看 disabled 是否为 true,为 true 则禁用,禁用也要暗藏下划线,即也不加 underline 类名
       若既不暗藏下划线又不禁用链接,则加上 underline 类名用于显示下划线
   -->
  <a
    :href="disabled ? null : href"
    :class="['myLink',
      hideUnderline ? '': disabled ?'' : 'underline',
      type,
      disabled ? 'toDisabled' : '',
    ]"v-bind="$attrs"@click="handleClick"
  >
    <!-- 
       这里加上 v -bind="$attrs" 是为了传递更多的属性,做一个参数兜底的性能成果。因为 a 标签还有其余很多属性,如:target、download、type 等。props 中未声明的参数,会被 $attr 兜底交给 a 标签应用。故加了 v -bind="$attrs" 当前,在外层 my-link 标签上,咱们便可失常应用除 props 中申明的属性了,如应用 target 原生属性:<my-link target="_blank" href="xxx"/>
    -->
    <!-- 内容区 -->
    <span class="aContent" :class="{spaceC: icon, back: back}">
      <i :class="icon" v-if="icon"></i>
      <span><slot></slot></span>
    </span>
  </a>
</template>

<script>
export default {
  name: "myLink",
  props: {
    href: String, // a 标签的 href 属性,用于跳转
    disabled: Boolean, // 是否禁用超链接
    type: String, // 标签色彩的类型
    // 是否暗藏下划线
    hideUnderline: {
      type: Boolean,
      default: false, // 默认不暗藏下划线,默认展现下划线
    },
    icon: String, // 应用饿了么 UI 的小图标
    back: Boolean, // 设置图标在内容前方
  },
  methods: {handleClick(event) {
      // 禁用状态下不容许传递事件
      if (this.disabled) {return;}
      // 有链接了也不容许传递事件
      if (this.href) {return;}
      // 没有禁用没有链接,便可失常传递事件
      this.$emit("click", event);
    },
  },
};
</script>

<style lang="less" scoped>
// 默认款式
.myLink {
  display: inline-block;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  color: #666; // 默认色彩,当然也能够应用 type 类型的配色
  text-decoration: none; // 去除 a 标签默认的下划线(不应用自带的下划线成果)position: relative; // 定位搭配伪元素实现悬浮下划线成果
  margin: 4px;
  .aContent {
    display: flex;
    align-items: center;
  }
  // 当传的有图标的时候,把第一个元素加上一个左边距,产生间距
  .spaceC > :first-child {margin-right: 4px;}
  // 管制弹性盒方向,管制图标在前方地位(默认后方地位).back {flex-direction: row-reverse;}
  // 留神这里要笼罩上方 spaceC 的款式
  .back > :first-child {margin: 0 0 0 4px;}
}
// 通过变量管制是否有这个 underline 类名,从而管制是否有下划线
.underline:hover::after {
  // 这样的话,元素在哪,下划线就在哪里
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  bottom: -2px;
  // 留神,这里不设置色彩,就会追随参考定位的元素的色彩了
  border-bottom: 1px solid;
}
// 下方的配色是抄 iview 的
.primary {color: #2d8cf0;}
.success {color: #19be6b;}
.warning {color: #f90;}
.danger {color: #ed4014;}
// 通过透明度模仿禁用的色彩款式成果,要不然要写两份色彩会略微麻烦一些
.toDisabled {
  opacity: 0.36;
  cursor: not-allowed;
}
</style>
正文完
 0