Vue3评分(Rate)

简介: 这是一个基于 Vue 3 的评分组件 `Rate.vue`,支持多种自定义设置,包括是否允许清除、半选状态、星星总数、字符样式、字符大小、选中颜色、字符间距及是否禁用等。组件内置四种 SVG 图标,并允许使用自定义字符。通过 `v-model:value` 实现双向绑定,并提供了 `change` 和 `hoverChange` 事件回调。组件演示了不同的使用场景,如禁用状态、不同形状的图标、自定义字符和颜色等。同时提供了一个评分配置器,可以动态调整各项参数以满足不同需求。在线预览效果展示了各种配置下的评分显示样式。

可自定义设置以下属性:

  • 是否允许再次点击后清除(allowClear),类型:boolean,默认 true

  • 是否允许半选(allowHalf),类型:boolean,默认 false

  • star 总数(count),类型:number,默认 5

  • 自定义字符(character),类型:'star-outlined' | 'star-filled' | 'heart-outlined' | 'heart-filled' | string | slot ,默认 'star-filled',预置四种 svg 图标

  • 字符时是字体高度,图标时是图片大小(size),类型:number,单位 px,默认 20

  • 字符选中颜色(color),类型:string,默认 '#fadb14'

  • 字符间距(gap),类型:number,单位 px,默认 8

  • 只读,无法进行交互(disabled),类型:boolean,默认 false

  • 当前数,受控值 1,2,3...(v-model:value),类型:number,默认 0

效果如下图: 在线预览

cbb21581b9328e657e288e774d71a582.png

e21f2970c0d5db888731cf345002ff6f.png

①创建评分组件Rate.vue:

<script setup lang="ts">
import { ref, watch } from 'vue'
interface Props {
  allowClear?: boolean // 是否允许再次点击后清除
  allowHalf?: boolean // 是否允许半选
  count?: number // star 总数
  character?: 'star-outlined' | 'star-filled' | 'heart-outlined' | 'heart-filled' | string // 自定义字符,预置四种 svg 图标 string | slot
  size?: number // 字符时是字体高度,图标时是图标大小,单位 px
  color?: string // 字符选中颜色
  gap?: number // 字符间距,单位 px
  disabled?: boolean // 只读,无法进行交互
  value?: number // (v-model) 当前数,受控值 1,2,3...
}
const props = withDefaults(defineProps<Props>(), {
  allowClear: true,
  allowHalf: false,
  count: 5,
  character: 'star-filled',
  size: 20,
  color: '#fadb14',
  gap: 8,
  disabled: false,
  value: 0
})
const activeValue = ref(props.value)
const tempValue = ref() // 清除时保存点击value
watch(
  () => props.value,
  (to) => {
    activeValue.value = to
  }
)
const emits = defineEmits(['update:value', 'change', 'hoverChange'])
function onClick(value: number) {
  tempValue.value = null
  if (value !== props.value) {
    emits('change', value) // 选择时的回调
    emits('update:value', value)
  } else {
    if (props.allowClear) {
      tempValue.value = value
      emits('change', 0)
      emits('update:value', 0)
    } else {
      // 不允许清除
      emits('change', value) // 选择时的回调
    }
  }
}
function onFirstEnter(value: number) {
  activeValue.value = value
  emits('hoverChange', value) // 鼠标经过时数值变化的回调
}
function onSecondEnter(value: number) {
  activeValue.value = value
  emits('hoverChange', value)
}
function resetTempValue() {
  // 重置点击value
  tempValue.value = null
}
function onLeave() {
  activeValue.value = props.value
}
</script>
<template>
  <div
    class="m-rate"
    :class="{ disabled: disabled }"
    :style="`--star-color: ${color}; --star-gap: ${gap}px; --start-size: ${size}px;`"
    @mouseleave="onLeave"
  >
    <div
      class="rate-star"
      :class="{
        'star-half': allowHalf && activeValue >= n - 0.5 && activeValue < n,
        'star-full': activeValue >= n,
        'temp-gray': !allowHalf && tempValue === n
      }"
      @click="allowHalf ? () => false : onClick(n)"
      v-for="n in count"
      :key="n"
    >
      <div
        v-if="allowHalf"
        class="star-first"
        :class="{ 'temp-gray-first': tempValue === n - 0.5 }"
        @click.stop="onClick(n - 0.5)"
        @mouseenter="onFirstEnter(n - 0.5)"
        @mouseleave="resetTempValue"
      >
        <svg
          v-if="character === 'star-filled'"
          class="icon-svg"
          focusable="false"
          data-icon="star"
          aria-hidden="true"
          viewBox="64 64 896 896"
        >
          <path
            d="M908.1 353.1l-253.9-36.9L540.7 86.1c-3.1-6.3-8.2-11.4-14.5-14.5-15.8-7.8-35-1.3-42.9 14.5L369.8 316.2l-253.9 36.9c-7 1-13.4 4.3-18.3 9.3a32.05 32.05 0 00.6 45.3l183.7 179.1-43.4 252.9a31.95 31.95 0 0046.4 33.7L512 754l227.1 119.4c6.2 3.3 13.4 4.4 20.3 3.2 17.4-3 29.1-19.5 26.1-36.9l-43.4-252.9 183.7-179.1c5-4.9 8.3-11.3 9.3-18.3 2.7-17.5-9.5-33.7-27-36.3z"
          ></path>
        </svg>
        <svg
          v-else-if="character === 'star-outlined'"
          class="icon-svg"
          focusable="false"
          data-icon="star"
          aria-hidden="true"
          viewBox="64 64 896 896"
        >
          <path
            d="M908.1 353.1l-253.9-36.9L540.7 86.1c-3.1-6.3-8.2-11.4-14.5-14.5-15.8-7.8-35-1.3-42.9 14.5L369.8 316.2l-253.9 36.9c-7 1-13.4 4.3-18.3 9.3a32.05 32.05 0 00.6 45.3l183.7 179.1-43.4 252.9a31.95 31.95 0 0046.4 33.7L512 754l227.1 119.4c6.2 3.3 13.4 4.4 20.3 3.2 17.4-3 29.1-19.5 26.1-36.9l-43.4-252.9 183.7-179.1c5-4.9 8.3-11.3 9.3-18.3 2.7-17.5-9.5-33.7-27-36.3zM664.8 561.6l36.1 210.3L512 672.7 323.1 772l36.1-210.3-152.8-149L417.6 382 512 190.7 606.4 382l211.2 30.7-152.8 148.9z"
          ></path>
        </svg>
        <svg
          v-else-if="character === 'heart-filled'"
          class="icon-svg"
          focusable="false"
          data-icon="heart"
          aria-hidden="true"
          viewBox="64 64 896 896"
        >
          <path
            d="M923 283.6a260.04 260.04 0 00-56.9-82.8 264.4 264.4 0 00-84-55.5A265.34 265.34 0 00679.7 125c-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5a258.44 258.44 0 00-56.9 82.8c-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3.1-35.3-7-69.6-20.9-101.9z"
          ></path>
        </svg>
        <svg
          v-else-if="character === 'heart-outlined'"
          class="icon-svg"
          focusable="false"
          data-icon="heart"
          aria-hidden="true"
          viewBox="64 64 896 896"
        >
          <path
            d="M923 283.6a260.04 260.04 0 00-56.9-82.8 264.4 264.4 0 00-84-55.5A265.34 265.34 0 00679.7 125c-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5a258.44 258.44 0 00-56.9 82.8c-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3.1-35.3-7-69.6-20.9-101.9zM512 814.8S156 586.7 156 385.5C156 283.6 240.3 201 344.3 201c73.1 0 136.5 40.8 167.7 100.4C543.2 241.8 606.6 201 679.7 201c104 0 188.3 82.6 188.3 184.5 0 201.2-356 429.3-356 429.3z"
          ></path>
        </svg>
        <span
          v-else
          class="icon-character"
          :style="`font-size: ${(size * 2) / 3}px; height: ${size}px; line-height: ${size}px;`"
        >
          <slot name="character">{
  { character }}</slot>
        </span>
      </div>
      <div
        class="star-second"
        :class="{ 'temp-gray-second': tempValue === n }"
        @click.stop="onClick(n)"
        @mouseenter="onSecondEnter(n)"
        @mouseleave="resetTempValue"
      >
        <svg
          v-if="character === 'star-filled'"
          class="icon-svg"
          focusable="false"
          data-icon="star"
          aria-hidden="true"
          viewBox="64 64 896 896"
        >
          <path
            d="M908.1 353.1l-253.9-36.9L540.7 86.1c-3.1-6.3-8.2-11.4-14.5-14.5-15.8-7.8-35-1.3-42.9 14.5L369.8 316.2l-253.9 36.9c-7 1-13.4 4.3-18.3 9.3a32.05 32.05 0 00.6 45.3l183.7 179.1-43.4 252.9a31.95 31.95 0 0046.4 33.7L512 754l227.1 119.4c6.2 3.3 13.4 4.4 20.3 3.2 17.4-3 29.1-19.5 26.1-36.9l-43.4-252.9 183.7-179.1c5-4.9 8.3-11.3 9.3-18.3 2.7-17.5-9.5-33.7-27-36.3z"
          ></path>
        </svg>
        <svg
          v-else-if="character === 'star-outlined'"
          class="icon-svg"
          focusable="false"
          data-icon="star"
          aria-hidden="true"
          viewBox="64 64 896 896"
        >
          <path
            d="M908.1 353.1l-253.9-36.9L540.7 86.1c-3.1-6.3-8.2-11.4-14.5-14.5-15.8-7.8-35-1.3-42.9 14.5L369.8 316.2l-253.9 36.9c-7 1-13.4 4.3-18.3 9.3a32.05 32.05 0 00.6 45.3l183.7 179.1-43.4 252.9a31.95 31.95 0 0046.4 33.7L512 754l227.1 119.4c6.2 3.3 13.4 4.4 20.3 3.2 17.4-3 29.1-19.5 26.1-36.9l-43.4-252.9 183.7-179.1c5-4.9 8.3-11.3 9.3-18.3 2.7-17.5-9.5-33.7-27-36.3zM664.8 561.6l36.1 210.3L512 672.7 323.1 772l36.1-210.3-152.8-149L417.6 382 512 190.7 606.4 382l211.2 30.7-152.8 148.9z"
          ></path>
        </svg>
        <svg
          v-else-if="character === 'heart-filled'"
          class="icon-svg"
          focusable="false"
          data-icon="heart"
          aria-hidden="true"
          viewBox="64 64 896 896"
        >
          <path
            d="M923 283.6a260.04 260.04 0 00-56.9-82.8 264.4 264.4 0 00-84-55.5A265.34 265.34 0 00679.7 125c-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5a258.44 258.44 0 00-56.9 82.8c-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3.1-35.3-7-69.6-20.9-101.9z"
          ></path>
        </svg>
        <svg
          v-else-if="character === 'heart-outlined'"
          class="icon-svg"
          focusable="false"
          data-icon="heart"
          aria-hidden="true"
          viewBox="64 64 896 896"
        >
          <path
            d="M923 283.6a260.04 260.04 0 00-56.9-82.8 264.4 264.4 0 00-84-55.5A265.34 265.34 0 00679.7 125c-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5a258.44 258.44 0 00-56.9 82.8c-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3.1-35.3-7-69.6-20.9-101.9zM512 814.8S156 586.7 156 385.5C156 283.6 240.3 201 344.3 201c73.1 0 136.5 40.8 167.7 100.4C543.2 241.8 606.6 201 679.7 201c104 0 188.3 82.6 188.3 184.5 0 201.2-356 429.3-356 429.3z"
          ></path>
        </svg>
        <span v-else class="icon-character" :style="`font-size: ${0.66 * size}px; height: ${size}px;`">
          <slot name="character">{
  { character }}</slot>
        </span>
      </div>
    </div>
  </div>
</template>
<style lang="less" scoped>
.m-rate {
  display: inline-flex;
  gap: var(--star-gap);
  .rate-star {
    position: relative;
    display: inline-block;
    cursor: pointer;
    transition: transform 0.3s ease-in-out;
    &:hover {
      transform: scale(1.1);
    }
    .icon-svg {
      width: var(--start-size);
      .icon-character();
    }
    .icon-character {
      display: inline-flex;
      align-items: center;
      text-align: center;
      vertical-align: middle;
      fill: rgba(0, 0, 0, 0.06);
      color: rgba(0, 0, 0, 0.06);
      transition: all 0.3s;
    }
    .star-first {
      position: absolute;
      top: 0;
      width: 50%;
      height: 100%;
      opacity: 0;
      overflow: hidden;
      transition: all 0.3s;
      &:hover {
        opacity: 1;
        .icon-svg,
        .icon-character {
          fill: var(--star-color);
          color: var(--star-color);
        }
      }
    }
    .star-second {
      display: inline-block;
      &:hover {
        .icon-svg,
        .icon-character {
          fill: var(--star-color);
          color: var(--star-color);
        }
      }
    }
    .temp-gray-first {
      &:hover {
        opacity: 0;
        .icon-svg,
        .icon-character {
          fill: rgba(0, 0, 0, 0.06);
          color: rgba(0, 0, 0, 0.06);
        }
      }
    }
    .temp-gray-second {
      &:hover {
        .icon-svg,
        .icon-character {
          fill: rgba(0, 0, 0, 0.06);
          color: rgba(0, 0, 0, 0.06);
        }
      }
    }
  }
  .star-half {
    .star-first {
      opacity: 1;
      .icon-svg,
      .icon-character {
        fill: var(--star-color);
        color: var(--star-color);
      }
    }
  }
  .star-full {
    .star-second {
      .icon-svg,
      .icon-character {
        fill: var(--star-color);
        color: var(--star-color);
      }
    }
  }
}
.disabled {
  pointer-events: none;
}
</style>

②在要使用的页面引入:

<script setup lang="ts">
import Rate from './Rate.vue'
import { ref, watchEffect, reactive } from 'vue'

const value = ref(2.99)
watchEffect(() => {
  console.log('value', value.value)
})
function onChange(value: number) {
  console.log('change value', value)
}
function onHoverChange(value: number) {
  console.log('hover value', value)
}
const characterOptions = [
  {
    label: 'star-outlined',
    value: 'star-outlined'
  },
  {
    label: 'star-filled',
    value: 'star-filled'
  },
  {
    label: 'heart-outlined',
    value: 'heart-outlined'
  },
  {
    label: 'heart-filled',
    value: 'heart-filled'
  },
  {
    label: 'custom-character',
    value: 'custom-character'
  }
]
const state = reactive({
  allowClear: true,
  allowHalf: true,
  count: 5,
  character: 'star-filled',
  customCharacter: 'S',
  size: 36,
  color: '#fadb14',
  gap: 8,
  disabled: false,
  value: 3
})
const score = ref(2.5)
watchEffect(() => {
  console.log('score', score.value)
})
</script>
<template>
  <div>
    <h1>{
  { $route.name }} {
  { $route.meta.title }}</h1>
    <h2 class="mt30 mb10">基本使用</h2>
    <Rate v-model:value="value" />
    <h2 class="mt30 mb10">禁用</h2>
    <Rate v-model:value="value" disabled />
    <h2 class="mt30 mb10">空心星型</h2>
    <Rate character="star-outlined" :size="30" v-model:value="value" />
    <h2 class="mt30 mb10">实心心型</h2>
    <Rate character="heart-filled" :size="30" v-model:value="value" />
    <h2 class="mt30 mb10">空心心型</h2>
    <Rate character="heart-outlined" :size="30" v-model:value="value" />
    <h2 class="mt30 mb10">支持选中半星</h2>
    <Rate v-model:value="value" :size="30" allow-half />
    <h2 class="mt30 mb10">使用中文文字: 好</h2>
    <Rate character="好" :size="36" v-model:value="value" @change="onChange" @hover-change="onHoverChange" />
    <h2 class="mt30 mb10">使用英文字母: A</h2>
    <Rate character="A" :size="48" v-model:value="value" @change="onChange" @hover-change="onHoverChange" />
    <h2 class="mt30 mb10">自定义选中颜色</h2>
    <Rate color="#1677FF" :size="30" v-model:value="value" />
    <h2 class="mt30 mb10">自定义间距</h2>
    <Rate :size="30" :gap="16" v-model:value="value" />
    <h2 class="mt30 mb10">自定义 star 总数</h2>
    <Rate :size="30" :count="10" v-model:value="value" />
    <h2 class="mt30 mb10">评分配置器</h2>
    <Row :gutter="[24, 12]">
      <Col :span="6">
        <Space gap="small" vertical> allowClear:<Switch v-model="state.allowClear" /> </Space>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical> allowHalf:<Switch v-model="state.allowHalf" /> </Space>
      </Col>
      <Col :span="6">
        <Flex vertical> count:<Slider v-model:value="state.count" :min="3" :max="10" /> </Flex>
      </Col>
      <Col :span="6">
        <Flex vertical> size:<Slider v-model:value="state.size" :min="10" :max="100" /> </Flex>
      </Col>
      <Col :span="6">
        <Flex gap="small" vertical> color:<Input v-model:value="state.color" placeholder="color" /> </Flex>
      </Col>
      <Col :span="6">
        <Flex vertical> gap:<Slider v-model:value="state.gap" :min="0" :max="100" /> </Flex>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical> disabled:<Switch v-model="state.disabled" /> </Space>
      </Col>
      <Col :span="6">
        <Flex gap="small" vertical> effect:<Select :options="characterOptions" v-model="state.character" /> </Flex>
      </Col>
      <Col :span="6" v-if="state.character === 'custom-character'">
        <Flex gap="small" vertical> character:<Input v-model:value="state.customCharacter" placeholder="customCharacter" /> </Flex>
      </Col>
    </Row>
    <Badge :value="score" style="margin-top: 30px">
      <Rate
        :allow-clear="state.allowClear"
        :allow-half="state.allowHalf"
        :count="state.count"
        :character="state.character === 'custom-character' ? state.customCharacter : state.character"
        :size="state.size"
        :color="state.color"
        :gap="state.gap"
        :disabled="state.disabled"
        v-model:value="score"
      />
    </Badge>
  </div>
</template>
相关文章
|
12天前
|
开发工具 iOS开发 MacOS
基于Vite7.1+Vue3+Pinia3+ArcoDesign网页版webos后台模板
最新版研发vite7+vue3.5+pinia3+arco-design仿macos/windows风格网页版OS系统Vite-Vue3-WebOS。
138 11
|
5月前
|
缓存 JavaScript PHP
斩获开发者口碑!SnowAdmin:基于 Vue3 的高颜值后台管理系统,3 步极速上手!
SnowAdmin 是一款基于 Vue3/TypeScript/Arco Design 的开源后台管理框架,以“清新优雅、开箱即用”为核心设计理念。提供角色权限精细化管理、多主题与暗黑模式切换、动态路由与页面缓存等功能,支持代码规范自动化校验及丰富组件库。通过模块化设计与前沿技术栈(Vite5/Pinia),显著提升开发效率,适合团队协作与长期维护。项目地址:[GitHub](https://github.com/WANG-Fan0912/SnowAdmin)。
750 5
|
2月前
|
缓存 前端开发 大数据
虚拟列表在Vue3中的具体应用场景有哪些?
虚拟列表在 Vue3 中通过仅渲染可视区域内容,显著提升大数据列表性能,适用于 ERP 表格、聊天界面、社交媒体、阅读器、日历及树形结构等场景,结合 `vue-virtual-scroller` 等工具可实现高效滚动与交互体验。
272 1
|
2月前
|
缓存 JavaScript UED
除了循环引用,Vue3还有哪些常见的性能优化技巧?
除了循环引用,Vue3还有哪些常见的性能优化技巧?
148 0
|
3月前
|
JavaScript
vue3循环引用自已实现
当渲染大量数据列表时,使用虚拟列表只渲染可视区域的内容,显著减少 DOM 节点数量。
99 0
|
5月前
|
JavaScript API 容器
Vue 3 中的 nextTick 使用详解与实战案例
Vue 3 中的 nextTick 使用详解与实战案例 在 Vue 3 的日常开发中,我们经常需要在数据变化后等待 DOM 更新完成再执行某些操作。此时,nextTick 就成了一个不可或缺的工具。本文将介绍 nextTick 的基本用法,并通过三个实战案例,展示它在表单验证、弹窗动画、自动聚焦等场景中的实际应用。
420 17
|
6月前
|
JavaScript 前端开发 算法
Vue 3 和 Vue 2 的区别及优点
Vue 3 和 Vue 2 的区别及优点
|
6月前
|
存储 JavaScript 前端开发
基于 ant-design-vue 和 Vue 3 封装的功能强大的表格组件
VTable 是一个基于 ant-design-vue 和 Vue 3 的多功能表格组件,支持列自定义、排序、本地化存储、行选择等功能。它继承了 Ant-Design-Vue Table 的所有特性并加以扩展,提供开箱即用的高性能体验。示例包括基础表格、可选择表格和自定义列渲染等。
417 6
|
5月前
|
JavaScript 前端开发 API
Vue 2 与 Vue 3 的区别:深度对比与迁移指南
Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架,在过去的几年里,Vue 2 一直是前端开发中的重要工具。而 Vue 3 作为其升级版本,带来了许多显著的改进和新特性。在本文中,我们将深入比较 Vue 2 和 Vue 3 的主要区别,帮助开发者更好地理解这两个版本之间的变化,并提供迁移建议。 1. Vue 3 的新特性概述 Vue 3 引入了许多新特性,使得开发体验更加流畅、灵活。以下是 Vue 3 的一些关键改进: 1.1 Composition API Composition API 是 Vue 3 的核心新特性之一。它改变了 Vue 组件的代码结构,使得逻辑组
1508 0
|
7月前
|
JavaScript 前端开发 UED
vue2和vue3的响应式原理有何不同?
大家好,我是V哥。本文详细对比了Vue 2与Vue 3的响应式原理:Vue 2基于`Object.defineProperty()`,适合小型项目但存在性能瓶颈;Vue 3采用`Proxy`,大幅优化初始化、更新性能及内存占用,更高效稳定。此外,我建议前端开发者关注鸿蒙趋势,2025年将是国产化替代关键期,推荐《鸿蒙 HarmonyOS 开发之路》卷1助你入行。老项目用Vue 2?不妨升级到Vue 3,提升用户体验!关注V哥爱编程,全栈开发轻松上手。
445 2