Element 2 组件源码剖析之Link文字连接

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战javascript

0x00 简介

本文将深刻分析组件 Link 源码,剖析其实现原理,耐心读完,相信会对您有所帮助。 组件文档 Linkcss

packages/link/src/main.vue 文件是组件源码实现。 github源码 main.vuehtml

0x01 组件源码

template 模板内容

从模板内容看出,组件封装一个 <a> 元素,包含3个子节点:vue

  1. 图标节点,定义 icon,渲染此节点 ;
  2. 提供了 slot<span> 元素,class 名为el-link--inner此样式规则未定义,无效样式),没有设置后备内容(默认值);
  3. 具名插槽 icon

3个子节点都设置 v-if判断是否渲染节点元素。java

<template>
  <a :class="[ 'el-link', type ? `el-link--${type}` : '', disabled && 'is-disabled', underline && !disabled && 'is-underline' ]" :href="disabled ? null : href" v-bind="$attrs" @click="handleClick" > <!-- 图标 --> <i :class="icon" v-if="icon"></i> <!-- 不带 name 的 <slot> 出口会带有隐含的名字“default”。 --> <span v-if="$slots.default" class="el-link--inner"> <slot></slot> </span> <!-- 具名插槽 icon --> <template v-if="$slots.icon"><slot v-if="$slots.icon" name="icon"></slot></template> </a> </template>
复制代码

根据组件prop 动态添加 classgit

  • 'el-link' 组件默认样式。
  • type ? 'el-link--${type}' : '' 设置组件文字不一样类型颜色。若 type 值不是如下default/primary / success / warning / danger / info 其中一个,设置无效(生成无效的class)。
  • disabled && 'is-disabled' 禁用状态下样式。
  • underline && !disabled && 'is-underline' 文字连接下划线样式,禁用状态下无效

逻辑与(&&) 看左边的值是真仍是假。若是值是真,返回的是右边的值,若是值是假;返回的是左边的值(只有false 、0、NaN、null、undefined、空字符串为假, 其他都是真)github

:href="disabled ? null : href" 禁用状态下值为 null,设置无效。web

@click="handleClick" 监听click事件提供处理方法。gulp

接收额外属性

$attrs 包含了父做用域中不做为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含全部父做用域的绑定 (class 和 style 除外),而且能够经过 v-bind="$attrs" 传入内部组件。api

具名插槽

组件提供了两个插槽,一个在默认插槽,一个具名插槽 icon

<template>
    ...
    <!-- 具名插槽 icon --> 
    <template v-if="$slots.icon">
        <slot v-if="$slots.icon" name="icon"></slot>
    </template>
    ...
</template>
复制代码

具名插槽 icon 使用了多层 <template> 标签嵌套,<template> 不会渲染成元素,用 div的话会被渲染成元素。把 v-ifv-showv-for 等抽取出来放在<template>上面,把绑定的事件放在<template>里面的元素上,能够使结构更加清晰,还能够改善元素嵌套过深。

具名插槽的使用示例,使用 <template slot="name">指定名称。

<template>
  <div style="display: flex;flex-direction: column;">
    <!-- prop underline 没有值,意味着 `true`。-->
    <el-link underline>
      查看 <i class="el-icon-view el-icon--right"></i>
      <template slot="icon">
        <h3>Link</h3>
      </template>
    </el-link>
    <el-link underline>
      <template slot="default">
        查看 <i class="el-icon-view el-icon--right"></i>
      </template>
      <template slot="icon">
        <h3>Link</h3>
      </template>
    </el-link>
  </div>
</template>
复制代码

两种使用方式渲染内容相同。

image.png

attributes 属性

组件提供了5个 prop

props: {
    type: {
      type: String,
      default: 'default'
    },
    underline: {
      type: Boolean,
      default: true
    },
    disabled: Boolean,
    href: String,
    icon: String
},

复制代码

prop详细描述以下:

参数 说明 类型 可选值 默认值
type 类型 string primary / success / warning / danger / info default
underline 是否下划线 boolean true
disabled 是否禁用状态 boolean false
href 原生 href 属性 string -
icon 图标类名 string -

events 事件

组件提供了 click 事件 。

handleClick(event) {
  // 非禁用状态
  if (!this.disabled) {
    // href未定义值
    if (!this.href) {
      // 触发当前实例上的事件
      this.$emit('click', event);
    }
  }
}
复制代码

click事件只有非禁用状态且href未定义值的状态下生效,用于须要代码处理页面跳转的场景。

<template>
  <div>
    <el-link @click="goToPage">默认连接</el-link>
  </div>
</template>
<script> export default { methods: { goToPage(e) { // url redirect }, }, }; </script> 
复制代码

0x02 组件样式

src/link.scss

组件样式源码 packages\theme-chalk\src\link.scss 使用 scss 的混合指令 bwhen 嵌套生成组件样式。

// Maps 可视为键值对的集合
$typeMap: (
  primary: $--link-primary-font-color,
  danger: $--link-danger-font-color,
  success: $--link-success-font-color,
  warning: $--link-warning-font-color,
  info: $--link-info-font-color,
);

// 生成 .el-link
@include b(link) {
  // ...

  // 生成.el-link.is-underline:hover:after
  @include when(underline) {
    &:hover:after {
      // ...
    }
  }
  // 生成 .el-link.is-disabled
  @include when(disabled) {
    // ...
  }

  // 生成 .el-link [class*=el-icon-] + span
  & [class*="el-icon-"] {
    & + span {
      // ...
    }
  }
  // 生成 .el-link.el-link--default
  &.el-link--default {
    // ...

    // .el-link.el-link--default:hover
    &:hover {
      // ...
    }

    // 生成  .el-link.el-link--default:after
    &:after {
      // ...
    }
    // 生成 .el-link.el-link--default.is-disabled
    @include when(disabled) {
      // ...
    }
  }

  @each $type, $primaryColor in $typeMap {
    // 生成 .el-link.el-link--[type]
    &.el-link--#{$type} {
      // ...
      
      // 生成 .el-link.el-link--[type]:hover
      &:hover {
        // ...
      }
      // 生成 .el-link.el-link--[type]:after
      &:after {
        // ...
      }
      // 生成 .el-link.el-link--[type].is-disabled
      @include when(disabled) {
        // ...
      }
      // 生成 .el-link.el-link--[type].is-disabled:hover:after
      @include when(underline) {
        &:hover:after {
          // ...
        }
      }
    }
  }
}

复制代码

lib/link.scss

前文可知使用 gulpfile.js编译 scss 文件转换为CSS,通过浏览器兼容、格式压缩,最后生成 packages\theme-chalk\lib\link.scss,内容格式以下。

.el-link {
  //...
}
.el-link.is-underline:hover:after {
   //...
}
.el-link.is-disabled {
   //...
}
.el-link [class*="el-icon-"] + span {
   //...
} 

.el-link.el-link--default:after,
.el-link.el-link--primary.is-underline:hover:after,
.el-link.el-link--primary:after {
   //...
} 
/* ------------default------------- */
.el-link.el-link--default {
   //...
}
.el-link.el-link--default:hover {
   //...
}
.el-link.el-link--default.is-disabled {
   //...
}
/* ------------primary------------- */
.el-link.el-link--primary {
  //...
}
.el-link.el-link--primary:hover {
  //...
}
.el-link.el-link--primary.is-disabled {
  //...
}  

/* type danger -------------------------- */
.el-link.el-link--danger.is-underline:hover:after,
.el-link.el-link--danger:after {
  border-color: #f56c6c;
}
.el-link.el-link--danger {
  color: #f56c6c;
}
.el-link.el-link--danger:hover {
  color: #f78989;
}
.el-link.el-link--danger.is-disabled {
  color: #fab6b6;
}
/* type success -------------------------- */
// ...

/* type warning -------------------------- */
// ... 

/* type info -------------------------- */
// ... 
 

复制代码

0x03 📚参考

"vm-attrs",vuejs.org
“JavaScript 逻辑运算规则 ”, cnblogs

0x04 关注专栏

此文章已收录到专栏中 👇,能够直接关注。