el-button源码解读2——useSlots() hooks与auto-insert-space props的结合

39 阅读1分钟
<template>
  <component
    :is="tag"
    ref="_ref"
    v-bind="_props"
    :class="buttonKls"
    :style="buttonStyle"
    @click="handleClick"
  >
    <!-- 优先级 1: 如果用户提供了 loading 插槽,用插槽内容 -->
    <template v-if="loading">
      <slot v-if="$slots.loading" name="loading" />
      <!-- 优先级 2: 否则使用 loadingIcon(可以是默认的,也可以是用户自定义的) -->
      <el-icon v-else :class="ns.is('loading')">
        <component :is="loadingIcon" />
      </el-icon>
    </template>
    <el-icon v-else-if="icon || $slots.icon">
      <component :is="icon" v-if="icon" />
      <slot v-else name="icon" />
    </el-icon>
    <span
      v-if="$slots.default"
      :class="{ [ns.em('text', 'expand')]: shouldAddSpace }"
    >
      <slot />
    </span>
  </component>
</template>

本文主要分析以下代码

    <span
      v-if="$slots.default"
      :class="{ [ns.em('text', 'expand')]: shouldAddSpace }"
    >
      <slot />
    </span>
    
    // :class="{ [ns.em('text', 'expand')]: shouldAddSpace }"
    // 即 :class="{el-button__text--expand: shouldAddSpace}"
    // 其中shouldAddSpace是一个Boolean类型

shouldAddSpace来自于:

const {
  _ref,
  _size,
  _type,
  _disabled,
  _props,
  _plain,
  _round,
  _text,
  shouldAddSpace,
  handleClick,
} = useButton(props, emit)

useButton中shouldAddSpace是一个computed计算属性

  // add space between two characters in Chinese
  const shouldAddSpace = computed(() => {
    // 获取默认插槽内容
    const defaultSlot = slots.default?.()
    console.log('defaultSlot',defaultSlot)
    // 检查是否启用自动加空格
    // autoInsertSpace(来自 prop 或全局配置)
    // defaultSlot?.length === 1 插槽只有一个节点
    if (autoInsertSpace.value && defaultSlot?.length === 1) {
      const slot = defaultSlot[0]
      // 检查是否是纯文本节点
      if (slot?.type === Text) {
        const text = slot.children as string
        // 检查是否是两个中文字符
        return /^\p{Unified_Ideograph}{2}$/u.test(text.trim())
      }
    }
    return false
  })

shouldAddSpace:当 shouldAddSpace 为 true 时,会添加 el-button__text--expand 类名,CSS 会在两个中文字符之间添加空格。

<el-button auto-insert-space>提交</el-button>  // 添加空格
<el-button auto-insert-space>提交表单</el-button> // 不添加
<el-button auto-insert-space>OK</el-button> // 英文或数字 不添加

hooks useSlots()

image.png

  <div class="play-container">
    <el-button auto-insert-space>
      <template #loading>加载中...</template>
      <template #icon>🚀</template>
      提交手册
    </el-button>
  </div>
  
  import { useSlots } from 'vue'
  const slots = useSlots()
  console.log('slots', slots)

image.png