Vue3按钮(Button)

简介: 这是一个高度可定制的按钮组件,支持多种属性设置,包括按钮类型、形状、图标、尺寸、背景透明度、波纹颜色、跳转地址、打开方式、禁用状态、加载状态及指示符样式等。预览图展示了不同配置下的按钮样式变化。组件通过Vue实现,并提供了丰富的自定义选项以适应各种场景需求。

可自定义设置以下属性:

  • 设置按钮类型(type),类型:'default' | 'reverse' | 'primary' | 'danger' | 'dashed' | 'text' | 'link',默认 'default'

  • 设置按钮形状(shape),类型:'default' | 'circle' | 'round',默认 'default'

  • 设置按钮图标(icon),类型:slot,默认 undefined

  • 设置按钮尺寸(size),类型:'small' | 'middle' | 'large',默认 'middle'

  • 按钮背景是否透明(ghost),类型:boolean,仅当 type: 'primary' | 'danger' 时生效,默认 false

  • 点击时的波纹颜色(rippleColor),类型:string,一般不需要设置,默认会根据 type 自动匹配,主要用于自定义样式时且 type: 'default',默认 undefined

  • 点击跳转的地址(href),与 a 链接的 href 属性一致,类型:string,默认 undefined

  • 如何打开目标链接(target)相当于 a 链接的 target 属性,href 存在时生效,类型:'_self' | '_blank',默认 '_self'

  • 是否禁用(disabled),类型:boolean,默认 false

  • 是否加载中(loading),类型:boolean,默认 false

  • 加载指示符类型(loadingType),类型:'static' | 'dynamic',默认 'dynamic'

  • 加载指示符颜色(loadingColor),一般不需要设置,默认会根据 type 自动匹配,主要用于自定义样式时且 type: 'default',类型:string,默认 'rgba(0, 0, 0, 0.88)'

  • 是否将按钮宽度调整为其父宽度(block),类型:boolean,默认 false

效果如下图:在线预览

①创建按钮组件Button.vue:

其中引入使用了以下工具函数:

<script setup lang="ts">
import { ref, nextTick, computed } from 'vue'
import type { Slot } from 'vue'
import { useSlotsExist } from '../utils'
interface Props {
  type?: 'default' | 'reverse' | 'primary' | 'danger' | 'dashed' | 'text' | 'link' // 设置按钮类型
  shape?: 'default' | 'circle' | 'round' // 设置按钮形状
  icon?: Slot // 设置按钮图标
  size?: 'small' | 'middle' | 'large' // 设置按钮尺寸
  ghost?: boolean // 按钮背景是否透明,仅当 type: 'primary' | 'danger' 时生效
  rippleColor?: string // 点击时的波纹颜色,一般不需要设置,默认会根据 type 自动匹配,主要用于自定义样式时且 type: 'default'
  href?: string // 点击跳转的地址,与 a 链接的 href 属性一致
  target?: '_self' | '_blank' // 如何打开目标链接,相当于 a 链接的 target 属性,href 存在时生效
  disabled?: boolean // 是否禁用
  loading?: boolean // 是否加载中
  loadingType?: 'static' | 'dynamic' // 加载指示符类型
  loadingColor?: string // 加载指示符颜色,一般不需要设置,默认会根据 type 自动匹配,主要用于自定义样式时且 type: 'default'
  block?: boolean // 是否将按钮宽度调整为其父宽度
}
withDefaults(defineProps<Props>(), {
  type: 'default',
  shape: 'default',
  icon: undefined,
  size: 'middle',
  ghost: false,
  rippleColor: undefined,
  href: undefined,
  target: '_self',
  disabled: false,
  loading: false,
  loadingType: 'dynamic',
  loadingColor: 'rgba(0, 0, 0, 0.88)',
  block: false
})
const presetRippleColors = {
  default: '#1677ff',
  reverse: '#1677ff',
  primary: '#1677ff',
  danger: '#ff4d4f',
  dashed: '#1677ff',
  text: 'transparent',
  link: 'transparent'
}
const wave = ref(false)
const emit = defineEmits(['click'])
const slotsExist = useSlotsExist(['icon', 'default'])
const showIconOnly = computed(() => {
  return slotsExist.icon && !slotsExist.default
})
function onClick(e: Event) {
  if (wave.value) {
    wave.value = false
    nextTick(() => {
      wave.value = true
    })
  } else {
    wave.value = true
  }
  emit('click', e)
}
function onKeyboard(e: KeyboardEvent) {
  onClick(e)
}
function onWaveEnd() {
  wave.value = false
}
</script>
<template>
  <a
    tabindex="0"
    class="m-btn"
    :class="[
      `btn-${type} btn-${size}`,
      {
        [`loading-${size}`]: !href && loading,
        'btn-icon-only': showIconOnly,
        'btn-circle': shape === 'circle',
        'btn-round': shape === 'round',
        'btn-loading-blur': !href && loading,
        'btn-ghost': ghost,
        'btn-block': block,
        'btn-disabled': disabled
      }
    ]"
    :style="`--ripple-color: ${rippleColor || presetRippleColors[type]}; --loading-color: ${loadingColor};`"
    :disabled="disabled"
    :href="href ? href : 'javascript:void(0);'"
    :target="href ? target : '_self'"
    @click="onClick"
    @keydown.enter.prevent="onKeyboard"
  >
    <div v-if="loading || !slotsExist.icon" class="btn-loading">
      <div v-if="!href && loadingType === 'static'" class="m-ring-circle">
        <svg class="circle" viewBox="0 0 100 100">
          <path
            d="M 50,50 m 0,-45 a 45,45 0 1 1 0,90 a 45,45 0 1 1 0,-90"
            stroke-linecap="round"
            class="path"
            fill-opacity="0"
          ></path>
        </svg>
      </div>
      <div v-if="!href && loadingType === 'dynamic'" class="m-dynamic-circle">
        <svg class="circle" viewBox="0 0 50 50" fill="currentColor">
          <circle class="path" cx="25" cy="25" r="20" fill="none"></circle>
        </svg>
      </div>
    </div>
    <span v-else class="btn-icon">
      <slot name="icon"></slot>
    </span>
    <span v-if="slotsExist.default" class="btn-content">
      <slot></slot>
    </span>
    <div v-if="!disabled" class="button-wave" :class="{ 'wave-active': wave }" @animationend="onWaveEnd"></div>
  </a>
</template>
<style lang="less" scoped>
@primary: #1677ff;
@danger: #ff4d4f;
.m-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 400;
  line-height: 1.5714285714285714;
  color: rgba(0, 0, 0, 0.88);
  white-space: nowrap;
  text-align: center;
  background-color: transparent;
  border: 1px solid transparent;
  outline: none;
  user-select: none;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
  .btn-loading {
    display: inline-flex;
    align-items: center;
    overflow: hidden;
    opacity: 0;
    width: 0;
    transition:
      margin-right 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
      width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
      opacity 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
    .m-ring-circle,
    .m-dynamic-circle {
      display: inline-flex;
      justify-content: start;
      .circle {
        width: 14px;
        height: 14px;
      }
    }
    .m-ring-circle {
      .circle {
        animation: spin-circle 0.8s linear infinite;
        -webkit-animation: spin-circle 0.8s linear infinite;
        .path {
          stroke-width: 10;
          stroke-dashoffset: 0;
          stroke-dasharray: 84.82px, 282.74px;
        }
      }
    }
    .m-dynamic-circle {
      .circle {
        animation: spin-circle 2s linear infinite;
        -webkit-animation: spin-circle 2s linear infinite;
        .path {
          stroke-width: 5;
          stroke-dasharray: 90, 150;
          stroke-dashoffset: 0;
          stroke-linecap: round;
          animation: loading-dash 1.5s ease-in-out infinite;
          -webkit-animation: loading-dash 1.5s ease-in-out infinite;
          @keyframes loading-dash {
            0% {
              stroke-dasharray: 1, 200;
              stroke-dashoffset: 0;
            }
            50% {
              stroke-dasharray: 90, 150;
              stroke-dashoffset: -40px;
            }
            100% {
              stroke-dasharray: 90, 150;
              stroke-dashoffset: -124px;
            }
          }
        }
      }
    }
    @keyframes spin-circle {
      100% {
        transform: rotate(360deg);
      }
    }
  }
  .btn-icon,
  .btn-content {
    display: inline-flex;
    align-items: center;
  }
  .button-wave {
    position: absolute;
    pointer-events: none;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    animation-iteration-count: 1;
    animation-duration: 0.6s;
    animation-timing-function: cubic-bezier(0, 0, 0.2, 1), cubic-bezier(0, 0, 0.2, 1);
    border-radius: inherit;
  }
  .wave-active {
    z-index: 1;
    animation-name: wave-spread, wave-opacity;
    @keyframes wave-spread {
      from {
        box-shadow: 0 0 0.5px 0 var(--ripple-color);
      }
      to {
        box-shadow: 0 0 0.5px 5.5px var(--ripple-color);
      }
    }
    @keyframes wave-opacity {
      from {
        opacity: 0.6;
      }
      to {
        opacity: 0;
      }
    }
  }
  & > .btn-icon + .btn-content {
    margin-left: 8px;
  }
}
.btn-default {
  background-color: #ffffff;
  border-color: #d9d9d9;
  &:hover {
    color: #4096ff !important;
    border-color: #4096ff;
    .btn-icon {
      :deep(svg) {
        fill: #4096ff !important;
      }
    }
  }
  &:active {
    color: #0958d9 !important;
    border-color: #0958d9;
    .btn-icon {
      :deep(svg) {
        fill: #0958d9 !important;
      }
    }
  }
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle .path {
        stroke: var(--loading-color);
      }
    }
  }
  .btn-icon {
    :deep(svg) {
      fill: var(--loading-color);
      transition: fill 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
    }
  }
}
.btn-reverse {
  .btn-default();
  &:hover {
    color: #fff !important;
    background-color: #4096ff;
    border-color: #4096ff;
    .btn-icon {
      :deep(svg) {
        fill: #fff !important;
      }
    }
  }
  &:active {
    color: #fff !important;
    background-color: #0958d9;
    border-color: #0958d9;
    .btn-icon {
      :deep(svg) {
        fill: #fff !important;
      }
    }
  }
}
.btn-primary {
  color: #fff;
  background-color: @primary;
  &:hover {
    color: #fff;
    background-color: #4096ff;
    border-color: #4096ff;
  }
  &:active {
    color: #fff;
    background-color: #0958d9;
    border-color: #0958d9;
  }
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle .path {
        stroke: #fff;
      }
    }
  }
  .btn-icon {
    :deep(svg) {
      fill: #fff;
    }
  }
}
.btn-danger {
  color: #fff;
  background-color: @danger;
  border-color: @danger;
  &:hover {
    color: #fff;
    background-color: #ff7875;
    border-color: #ff7875;
  }
  &:active {
    color: #fff;
    background-color: #d9363e;
    border-color: #d9363e;
  }
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle .path {
        stroke: #fff;
      }
    }
  }
  .btn-icon {
    :deep(svg) {
      fill: #fff;
    }
  }
}
.btn-dashed {
  .btn-default();
  border-style: dashed;
}
.btn-text {
  &:hover {
    color: rgba(0, 0, 0, 0.88);
    background-color: rgba(0, 0, 0, 0.06);
  }
  &:active {
    color: rgba(0, 0, 0, 0.88);
    background-color: rgba(0, 0, 0, 0.15);
  }
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle .path {
        stroke: rgba(0, 0, 0, 0.88);
      }
    }
  }
  .btn-icon {
    :deep(svg) {
      fill: rgba(0, 0, 0, 0.88);
    }
  }
}
.btn-link {
  color: @primary;
  &:hover {
    color: #4096ff;
    .btn-icon {
      :deep(svg) {
        fill: #4096ff;
      }
    }
  }
  &:active {
    color: #0958d9;
    .btn-icon {
      :deep(svg) {
        fill: #0958d9;
      }
    }
  }
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle .path {
        stroke: @primary;
      }
    }
  }
  .btn-icon {
    :deep(svg) {
      fill: @primary;
      transition: fill 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
    }
  }
}
.btn-small {
  font-size: 14px;
  height: 24px;
  padding: 0 7px;
  border-radius: 4px;
}
.btn-middle {
  font-size: 14px;
  height: 32px;
  padding: 4px 15px;
  border-radius: 6px;
}
.btn-large {
  font-size: 16px;
  height: 40px;
  padding: 6.428571428571429px 15px;
  border-radius: 8px;
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle {
        width: 16px;
        height: 16px;
      }
    }
  }
}
.loading-small,
.loading-middle {
  .btn-loading {
    margin-right: 8px;
    width: 14px;
    opacity: 1;
  }
}
.loading-large {
  .btn-loading {
    margin-right: 8px;
    width: 16px;
    opacity: 1;
  }
}
.btn-icon-only {
  width: 32px;
  padding-left: 0;
  padding-right: 0;
  .btn-loading,
  .btn-icon {
    transform: scale(1.143);
  }
  .btn-loading {
    margin-right: 0;
  }
}
.btn-small.btn-icon-only {
  width: 24px;
  padding-left: 0;
  padding-right: 0;
}
.btn-large.btn-icon-only {
  width: 40px;
  padding-left: 0;
  padding-right: 0;
}
.btn-circle {
  min-width: 32px;
  padding-left: 0;
  padding-right: 0;
  border-radius: 50%;
}
.btn-small.btn-circle {
  min-width: 24px;
  padding-left: 0;
  padding-left: 0;
  border-radius: 50%;
}
.btn-large.btn-circle {
  min-width: 40px;
  padding-left: 0;
  padding-right: 0;
  border-radius: 50%;
}
.btn-round {
  border-radius: 32px;
  padding-left: 16px;
  padding-right: 16px;
}
.btn-small.btn-round {
  border-radius: 24px;
  padding-left: 12px;
  padding-right: 12px;
}
.btn-large.btn-round {
  border-radius: 40px;
  padding-left: 20px;
  padding-right: 20px;
}
.btn-icon-only.btn-round,
.btn-small.btn-icon-only.btn-round,
.btn-large.btn-icon-only.btn-round {
  width: auto;
}
.btn-loading-blur {
  opacity: 0.65;
  pointer-events: none;
}
.btn-primary.btn-ghost:not(.btn-disabled) {
  color: @primary;
  border-color: @primary;
  background-color: transparent;
  &:hover {
    color: #4096ff;
    border-color: #4096ff;
    .btn-icon {
      :deep(svg) {
        fill: #4096ff;
      }
    }
  }
  &:active {
    color: #0958d9;
    border-color: #0958d9;
    .btn-icon {
      :deep(svg) {
        fill: #0958d9;
      }
    }
  }
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle .path {
        stroke: @primary;
      }
    }
  }
  .btn-icon {
    :deep(svg) {
      fill: @primary;
      transition: fill 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
    }
  }
}
.btn-danger.btn-ghost:not(.btn-disabled) {
  color: @danger;
  border-color: @danger;
  background-color: transparent;
  &:hover {
    color: #ff7875;
    border-color: #ff7875;
    .btn-icon {
      :deep(svg) {
        fill: #ff7875;
      }
    }
  }
  &:active {
    color: #d9363e;
    border-color: #d9363e;
    .btn-icon {
      :deep(svg) {
        fill: #d9363e;
      }
    }
  }
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle .path {
        stroke: @danger;
      }
    }
  }
  .btn-icon {
    :deep(svg) {
      fill: @danger;
      transition: fill 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
    }
  }
}
.btn-block {
  width: 100%;
}
.btn-disabled {
  border-color: #d9d9d9;
  color: rgba(0, 0, 0, 0.25);
  background-color: rgba(0, 0, 0, 0.04);
  cursor: not-allowed;
  &:hover,
  &:active {
    border-color: #d9d9d9;
    color: rgba(0, 0, 0, 0.25) !important;
    background-color: rgba(0, 0, 0, 0.04);
    .btn-icon {
      :deep(svg) {
        fill: rgba(0, 0, 0, 0.25) !important;
      }
    }
  }
  &.btn-text,
  &.btn-link {
    background-color: transparent;
    border: none;
  }
  .btn-loading {
    .m-ring-circle,
    .m-dynamic-circle {
      .circle .path {
        stroke: rgba(0, 0, 0, 0.25);
      }
    }
  }
  .btn-icon {
    :deep(svg) {
      fill: rgba(0, 0, 0, 0.25) !important;
    }
  }
}
</style>

②在要使用的页面引入:

<script setup lang="ts">
import Button from './Button.vue'
import { ref } from 'vue'
import { SearchOutlined, DownloadOutlined } from '@ant-design/icons-vue'
const disabled = ref(true)
const sizeOptions = [
  {
    label: 'small',
    value: 'small'
  },
  {
    label: 'middle',
    value: 'middle'
  },
  {
    label: 'large',
    value: 'large'
  }
]
const size = ref('middle')
const customLoading = ref(false)
const loading = ref(true)
const loadingOptions = [
  {
    label: 'static',
    value: 'static'
  },
  {
    label: 'dynamic',
    value: 'dynamic'
  }
]
const loadingType = ref('dynamic')
function onClick(e: Event) {
  console.log('click', e)
}
</script>
<template>
  <div>
    <h1>{
  
  { $route.name }} {
  
  { $route.meta.title }}</h1>
    <h2 class="mt30 mb10">按钮类型</h2>
    <Space>
      <Button @click="onClick">Default Button</Button>
      <Button type="reverse">Reverse Button</Button>
      <Button type="primary">Primary Button</Button>
      <Button type="danger">Danger Button</Button>
      <Button type="dashed">Dashed Button</Button>
      <Button type="text">Text Button</Button>
      <Button type="link">Link Button</Button>
    </Space>
    <h2 class="mt30 mb10">按钮形状 & 图标</h2>
    <Space vertical>
      <Space>
        <Tooltip tooltip="search">
          <Button type="primary" shape="circle">
            <template #icon>
              <SearchOutlined />
            </template>
          </Button>
        </Tooltip>
        <Button type="primary" shape="circle">A</Button>
        <Button type="primary" shape="round">
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
        <Tooltip tooltip="search">
          <Button type="primary" shape="round">
            <template #icon>
              <SearchOutlined />
            </template>
          </Button>
        </Tooltip>
        <Button type="primary">
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
      </Space>
      <Space>
        <Tooltip tooltip="search">
          <Button href="https://blog.csdn.net/Dandrose" target="_blank">
            <template #icon>
              <SearchOutlined />
            </template>
          </Button>
        </Tooltip>
        <Tooltip tooltip="search">
          <Button shape="circle">
            <template #icon>
              <SearchOutlined />
            </template>
          </Button>
        </Tooltip>
        <Button>
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
        <Tooltip tooltip="search">
          <Button shape="round">
            <template #icon>
              <SearchOutlined />
            </template>
          </Button>
        </Tooltip>
        <Tooltip tooltip="search">
          <Button type="dashed" shape="circle">
            <template #icon>
              <SearchOutlined />
            </template>
          </Button>
        </Tooltip>
        <Button type="dashed">
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
      </Space>
      <Space>
        <Tooltip tooltip="download">
          <Button type="primary">
            <template #icon>
              <DownloadOutlined />
            </template>
          </Button>
        </Tooltip>
        <Tooltip tooltip="download">
          <Button type="primary" shape="circle">
            <template #icon>
              <DownloadOutlined />
            </template>
          </Button>
        </Tooltip>
        <Button type="primary" shape="round">
          <template #icon>
            <DownloadOutlined />
          </template>
          Download
        </Button>
        <Tooltip tooltip="download">
          <Button type="primary" shape="round">
            <template #icon>
              <DownloadOutlined />
            </template>
          </Button>
        </Tooltip>
        <Button type="primary">
          <template #icon>
            <DownloadOutlined />
          </template>
          Download
        </Button>
      </Space>
    </Space>
    <h2 class="mt30 mb10">幽灵按钮</h2>
    <Space>
      <Button type="primary" ghost>Primary Ghost Button</Button>
      <Button type="danger" ghost>Danger Ghost Button</Button>
      <Button type="primary" ghost shape="circle">
        <template #icon>
          <SearchOutlined />
        </template>
      </Button>
      <Button type="primary" ghost shape="round">
        <template #icon>
          <SearchOutlined />
        </template>
        Search
      </Button>
      <Button type="primary" ghost shape="round">
        <template #icon>
          <SearchOutlined />
        </template>
      </Button>
      <Button type="danger" ghost shape="circle">
        <template #icon>
          <DownloadOutlined />
        </template>
      </Button>
      <Button type="danger" ghost shape="round">
        <template #icon>
          <DownloadOutlined />
        </template>
        Download
      </Button>
      <Button type="danger" ghost shape="round">
        <template #icon>
          <DownloadOutlined />
        </template>
      </Button>
    </Space>
    <h2 class="mt30 mb10">禁用</h2>
    <Space vertical>
      <Space align="center"> Disabled state:<Switch v-model="disabled" /> </Space>
      <Space>
        <Button :disabled="disabled">Default Button</Button>
        <Button :disabled="disabled" type="reverse">Reverse Button</Button>
        <Button :disabled="disabled" type="primary">Primary Button</Button>
        <Button :disabled="disabled" type="danger">Danger Button</Button>
        <Button :disabled="disabled" type="dashed">Dashed Button</Button>
        <Button :disabled="disabled" type="text">Text Button</Button>
        <Button :disabled="disabled" type="link">Link Button</Button>
      </Space>
      <Space>
        <Button :disabled="disabled" type="primary" ghost>Primary Ghost Button</Button>
        <Button :disabled="disabled" type="danger" ghost>Danger Ghost Button</Button>
        <Button :disabled="disabled" type="primary" shape="circle">
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button :disabled="disabled" type="primary" shape="round">
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
        <Button :disabled="disabled" type="primary" shape="round">
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button :disabled="disabled" type="danger" shape="circle">
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
        <Button :disabled="disabled" type="danger" shape="round">
          <template #icon>
            <DownloadOutlined />
          </template>
          Download
        </Button>
        <Button :disabled="disabled" type="danger" shape="round">
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
      </Space>
    </Space>
    <h2 class="mt30 mb10">按钮尺寸</h2>
    <Space vertical>
      <Radio :options="sizeOptions" v-model:value="size" button button-style="solid" />
      <Space>
        <Button :size="size">Default Button</Button>
        <Button :size="size" type="reverse">Reverse Button</Button>
        <Button :size="size" type="primary">Primary Button</Button>
        <Button :size="size" type="danger">Danger Button</Button>
      </Space>
      <Space>
        <Button :size="size" type="dashed">Dashed Button</Button>
        <Button :size="size" type="text">Text Button</Button>
        <Button :size="size" type="link">Link Button</Button>
      </Space>
      <Space>
        <Button :size="size" type="primary" ghost>Primary Button</Button>
        <Button :size="size" type="danger" ghost>Danger Button</Button>
        <Button :size="size" type="primary" ghost loading>Primary Ghost Button</Button>
        <Button :size="size" type="danger" ghost loading>Danger Ghost Button</Button>
      </Space>
      <Space>
        <Button :size="size" type="primary" ghost>
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button :size="size" type="primary" ghost shape="circle">
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button :size="size" type="primary" ghost shape="round">
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
        <Button :size="size" type="primary" ghost shape="round">
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button :size="size" type="primary" ghost>
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
      </Space>
      <Space>
        <Button :size="size" type="danger">
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
        <Button :size="size" type="danger" shape="circle">
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
        <Button :size="size" type="danger" shape="round">
          <template #icon>
            <DownloadOutlined />
          </template>
          Download
        </Button>
        <Button :size="size" type="danger" shape="round">
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
        <Button :size="size" type="danger">
          <template #icon>
            <DownloadOutlined />
          </template>
          Download
        </Button>
      </Space>
    </Space>
    <h2 class="mt30 mb10">自定义样式</h2>
    <Space vertical>
      <Space align="center"> Loading state:<Switch v-model="customLoading" /> </Space>
      <Space>
        <Button
          style="width: 150px; height: 40px; font-size: 18px; border-color: #faad14; color: #faad14"
          ripple-color="#faad14"
          loading-color="#faad14"
          size="large"
          :loading="customLoading"
        >
          自定义样式
        </Button>
        <Button
          style="width: 150px; height: 40px; font-size: 18px; background: #faad14; border-color: #faad14; color: #fff"
          ripple-color="#faad14"
          loading-color="#fff"
          size="large"
          :loading="customLoading"
        >
          自定义样式
        </Button>
        <Button
          style="height: 40px; font-size: 18px; border-color: #faad14; color: #faad14"
          ripple-color="#faad14"
          loading-color="#faad14"
          shape="circle"
          size="large"
          :loading="customLoading"
        >
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button
          style="width: 150px; height: 40px; font-size: 18px; background: #faad14; border-color: #faad14; color: #fff"
          ripple-color="#faad14"
          loading-color="#fff"
          shape="round"
          size="large"
          :loading="customLoading"
        >
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
        <Button
          style="height: 40px; font-size: 18px; border-color: #faad14; color: #faad14"
          ripple-color="#faad14"
          loading-color="#faad14"
          shape="round"
          size="large"
          :loading="customLoading"
        >
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
      </Space>
    </Space>
    <h2 class="mt30 mb10">自定义跳转</h2>
    <Space>
      <Button type="primary" ghost href="https://themusecatcher.github.io/vue-amazing-ui/" target="_blank">
        <template #icon>
          <img class="icon-img" src="https://themusecatcher.github.io/vue-amazing-ui/amazing-logo.svg" />
        </template>
        Vue Amazing UI
      </Button>
      <Button
        type="primary"
        href="https://themusecatcher.github.io/vue-amazing-ui/guide/components/button.html"
        target="_blank"
      >
        Button Component
      </Button>
      <Button type="primary" ghost shape="round" href="https://blog.csdn.net/Dandrose" target="_blank">
        My CSDN Blogs
      </Button>
    </Space>
    <h2 class="mt30 mb10">加载中状态</h2>
    <Space vertical>
      <Space align="center"> Loading state:<Switch v-model="loading" /> </Space>
      <Space align="center"> Loading type:<Radio :options="loadingOptions" v-model:value="loadingType" /> </Space>
      <Space>
        <Button :loading="loading" :loading-type="loadingType">Default Button</Button>
        <Button type="reverse" :loading="loading" :loading-type="loadingType">Reverse Button</Button>
        <Button type="primary" :loading="loading" :loading-type="loadingType">Primary Button</Button>
        <Button type="danger" :loading="loading" :loading-type="loadingType">Danger Button</Button>
      </Space>
      <Space>
        <Button type="dashed" :loading="loading" :loading-type="loadingType">Dashed Button</Button>
        <Button type="text" :loading="loading" :loading-type="loadingType">Text Button</Button>
        <Button type="link" :loading="loading" :loading-type="loadingType">Link Button</Button>
      </Space>
      <Space>
        <Button type="primary" ghost :loading="loading" :loading-type="loadingType">Primary Ghost Button</Button>
        <Button type="danger" ghost :loading="loading" :loading-type="loadingType">Danger Ghost Button</Button>
      </Space>
      <Space>
        <Button type="primary" :loading="loading" :loading-type="loadingType">
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button type="primary" shape="circle" :loading="loading" :loading-type="loadingType">
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button type="primary" shape="round" :loading="loading" :loading-type="loadingType">
          <template #icon>
            <SearchOutlined />
          </template>
          Search
        </Button>
        <Button type="primary" shape="round" :loading="loading" :loading-type="loadingType">
          <template #icon>
            <SearchOutlined />
          </template>
        </Button>
        <Button type="danger" ghost :loading="loading" :loading-type="loadingType">
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
        <Button type="danger" ghost shape="circle" :loading="loading" :loading-type="loadingType">
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
        <Button type="danger" ghost shape="round" :loading="loading" :loading-type="loadingType">
          <template #icon>
            <DownloadOutlined />
          </template>
          Download
        </Button>
        <Button type="danger" ghost shape="round" :loading="loading" :loading-type="loadingType">
          <template #icon>
            <DownloadOutlined />
          </template>
        </Button>
      </Space>
    </Space>
    <h2 class="mt30 mb10">block 按钮</h2>
    <Space>
      <Button block>Default Button</Button>
      <Button block type="primary" shape="round">Primary Button</Button>
      <Button block type="danger" shape="round">Danger Button</Button>
      <Button block type="primary" ghost>Primary Button</Button>
      <Button block type="danger" ghost>Danger Button</Button>
    </Space>
  </div>
</template>
<style lang="less" scoped>
.icon-img {
  width: 1em;
  height: 1em;
}
</style>
相关文章
|
23天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
126 64
|
23天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
103 60
|
23天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
29 8
|
22天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
22 1
|
22天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
33 1
|
23天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
27天前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
39 0
|
27天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
28天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
2天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
下一篇
DataWorks