从基础到高级应用详解Vue3中自定义指令的完整指南

 更新时间:2025年11月24日 09:10:47   作者:北辰alk  
自定义指令是 Vue.js 中一个强大而灵活的特性,它允许开发者直接对 DOM 元素进行底层操作,本文将深入探讨 Vue3 中自定义指令的定义方式、生命周期钩子、使用场景和最佳实践,快跟随小编一起学习一下吧

摘要

自定义指令是 Vue.js 中一个强大而灵活的特性,它允许开发者直接对 DOM 元素进行底层操作。Vue3 在保留自定义指令核心概念的同时,对其 API 进行了调整和优化,使其更符合组合式 API 的设计理念。本文将深入探讨 Vue3 中自定义指令的定义方式、生命周期钩子、使用场景和最佳实践,通过丰富的代码示例和清晰的流程图,帮助你彻底掌握这一重要特性。

一、 什么是自定义指令?为什么需要它?

1.1 自定义指令的概念

在 Vue.js 中,指令是带有 v- 前缀的特殊属性。除了 Vue 内置的指令(如 v-modelv-showv-if 等),Vue 还允许我们注册自定义指令,用于对普通 DOM 元素进行底层操作。

1.2 使用场景

自定义指令在以下场景中特别有用:

  • DOM 操作:焦点管理、文本选择、元素拖拽
  • 输入限制:格式化输入内容、阻止无效字符
  • 权限控制:根据权限显示/隐藏元素
  • 集成第三方库:与 jQuery 插件、图表库等集成
  • 性能优化:图片懒加载、无限滚动
  • 用户体验:点击外部关闭、滚动加载更多

1.3 Vue2 与 Vue3 自定义指令的区别

特性Vue2Vue3
生命周期钩子bind, inserted, update, componentUpdated, unbindcreated, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted
参数传递el, binding, vnode, oldVnodeel, binding, vnode, prevVnode
注册方式全局 Vue.directive(),局部 directives 选项全局 app.directive(),局部 directives 选项
与组合式API集成有限更好,可在 setup 中使用

二、 自定义指令的基本结构

2.1 指令的生命周期钩子

Vue3 中的自定义指令包含一系列生命周期钩子,这些钩子在指令的不同阶段被调用:

流程图:自定义指令生命周期

2.2 钩子函数参数

每个生命周期钩子函数都会接收以下参数:

  • el:指令绑定的元素,可以直接操作 DOM
  • binding:一个对象,包含指令的相关信息
  • vnode:Vue 编译生成的虚拟节点
  • prevVnode:上一个虚拟节点(仅在 beforeUpdateupdated 中可用)

binding 对象结构:

{
  value:        any,        // 指令的绑定值,如 v-my-directive="value"
  oldValue:     any,        // 指令绑定的前一个值
  arg:          string,     // 指令的参数,如 v-my-directive:arg
  modifiers:    object,     // 指令的修饰符对象,如 v-my-directive.modifier
  instance:     Component,  // 使用指令的组件实例
  dir:          object      // 指令的定义对象
}

三、 定义自定义指令的多种方式

3.1 全局自定义指令

全局指令在整个 Vue 应用中都可用。

方式一:使用app.directive()

// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// 定义全局焦点指令
app.directive('focus', {
  mounted(el) {
    el.focus()
    console.log('元素获得焦点')
  }
})

// 定义全局颜色指令(带参数和值)
app.directive('color', {
  beforeMount(el, binding) {
    el.style.color = binding.value
  },
  updated(el, binding) {
    el.style.color = binding.value
  }
})

app.mount('#app')

方式二:使用插件形式

// directives/index.js
export const focusDirective = {
  mounted(el) {
    el.focus()
  }
}

export const colorDirective = {
  beforeMount(el, binding) {
    el.style.color = binding.value
  },
  updated(el, binding) {
    el.style.color = binding.value
  }
}

// 注册所有指令
export function registerDirectives(app) {
  app.directive('focus', focusDirective)
  app.directive('color', colorDirective)
}

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { registerDirectives } from './directives'

const app = createApp(App)
registerDirectives(app)
app.mount('#app')

3.2 局部自定义指令

局部指令只在特定组件中可用。

选项式 API

<template>
  <div>
    <input v-focus-local placeholder="局部焦点指令" />
    <p v-color-local="textColor">这个文本颜色会变化</p>
    <button @click="changeColor">改变颜色</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      textColor: 'red'
    }
  },
  methods: {
    changeColor() {
      this.textColor = this.textColor === 'red' ? 'blue' : 'red'
    }
  },
  directives: {
    // 局部焦点指令
    'focus-local': {
      mounted(el) {
        el.focus()
      }
    },
    // 局部颜色指令
    'color-local': {
      beforeMount(el, binding) {
        el.style.color = binding.value
      },
      updated(el, binding) {
        el.style.color = binding.value
      }
    }
  }
}
</script>

组合式 API

<template>
  <div>
    <input v-focus-local placeholder="局部焦点指令" />
    <p v-color-local="textColor">这个文本颜色会变化</p>
    <button @click="changeColor">改变颜色</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const textColor = ref('red')

const changeColor = () => {
  textColor.value = textColor.value === 'red' ? 'blue' : 'red'
}

// 局部自定义指令
const vFocusLocal = {
  mounted(el) {
    el.focus()
  }
}

const vColorLocal = {
  beforeMount(el, binding) {
    el.style.color = binding.value
  },
  updated(el, binding) {
    el.style.color = binding.value
  }
}
</script>

四、 完整生命周期示例

让我们通过一个完整的示例来演示所有生命周期钩子的使用:

<template>
  <div class="demo-container">
    <h2>自定义指令完整生命周期演示</h2>
    
    <div>
      <button @click="toggleDisplay">{{ isVisible ? '隐藏' : '显示' }}元素</button>
      <button @click="changeMessage">改变消息</button>
      <button @click="changeColor">改变颜色</button>
    </div>

    <div v-if="isVisible" v-lifecycle-demo:arg.modifier="directiveValue" 
         class="demo-element" :style="{ color: elementColor }">
      {{ message }}
    </div>

    <div class="log-container">
      <h3>生命周期日志:</h3>
      <div v-for="(log, index) in logs" :key="index" class="log-item">
        {{ log }}
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

const isVisible = ref(false)
const message = ref('Hello, Custom Directive!')
const elementColor = ref('#333')
const logs = ref([])

const directiveValue = reactive({
  text: '指令值对象',
  count: 0
})

// 添加日志函数
const addLog = (hookName, el, binding) => {
  const log = `[${new Date().toLocaleTimeString()}] ${hookName}: value=${JSON.stringify(binding.value)}, arg=${binding.arg}`
  logs.value.push(log)
  // 保持日志数量不超过20条
  if (logs.value.length > 20) {
    logs.value.shift()
  }
}

// 完整的生命周期指令
const vLifecycleDemo = {
  created(el, binding) {
    addLog('created', el, binding)
    console.log('created - 指令创建,元素还未挂载')
  },
  
  beforeMount(el, binding) {
    addLog('beforeMount', el, binding)
    console.log('beforeMount - 元素挂载前')
    el.style.transition = 'all 0.3s ease'
  },
  
  mounted(el, binding) {
    addLog('mounted', el, binding)
    console.log('mounted - 元素挂载完成')
    console.log('修饰符:', binding.modifiers)
    console.log('参数:', binding.arg)
    
    // 添加动画效果
    el.style.opacity = '0'
    el.style.transform = 'translateY(-20px)'
    
    setTimeout(() => {
      el.style.opacity = '1'
      el.style.transform = 'translateY(0)'
    }, 100)
  },
  
  beforeUpdate(el, binding) {
    addLog('beforeUpdate', el, binding)
    console.log('beforeUpdate - 元素更新前')
  },
  
  updated(el, binding) {
    addLog('updated', el, binding)
    console.log('updated - 元素更新完成')
    
    // 更新时的动画
    el.style.backgroundColor = '#e3f2fd'
    setTimeout(() => {
      el.style.backgroundColor = ''
    }, 500)
  },
  
  beforeUnmount(el, binding) {
    addLog('beforeUnmount', el, binding)
    console.log('beforeUnmount - 元素卸载前')
    
    // 卸载动画
    el.style.opacity = '1'
    el.style.transform = 'translateY(0)'
    el.style.opacity = '0'
    el.style.transform = 'translateY(-20px)'
  },
  
  unmounted(el, binding) {
    addLog('unmounted', el, binding)
    console.log('unmounted - 元素卸载完成')
  }
}

const toggleDisplay = () => {
  isVisible.value = !isVisible.value
}

const changeMessage = () => {
  message.value = `消息已更新 ${Date.now()}`
  directiveValue.count++
}

const changeColor = () => {
  const colors = ['#ff4444', '#44ff44', '#4444ff', '#ff44ff', '#ffff44']
  elementColor.value = colors[Math.floor(Math.random() * colors.length)]
}
</script>

<style scoped>
.demo-container {
  padding: 20px;
  max-width: 800px;
  margin: 0 auto;
}

.demo-element {
  padding: 20px;
  margin: 20px 0;
  border: 2px solid #42b983;
  border-radius: 8px;
  background: #f9f9f9;
}

.log-container {
  margin-top: 20px;
  padding: 15px;
  background: #f5f5f5;
  border-radius: 8px;
  max-height: 400px;
  overflow-y: auto;
}

.log-item {
  padding: 5px 10px;
  margin: 2px 0;
  background: white;
  border-radius: 4px;
  font-family: 'Courier New', monospace;
  font-size: 12px;
}

button {
  margin: 5px;
  padding: 8px 16px;
  background: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background: #369870;
}
</style>

五、 实用自定义指令示例

5.1 点击外部关闭指令

<template>
  <div class="click-outside-demo">
    <h2>点击外部关闭演示</h2>
    
    <button @click="showDropdown = !showDropdown">
      切换下拉菜单 {{ showDropdown ? '▲' : '▼' }}
    </button>

    <div v-if="showDropdown" v-click-outside="closeDropdown" class="dropdown">
      <div class="dropdown-item">菜单项 1</div>
      <div class="dropdown-item">菜单项 2</div>
      <div class="dropdown-item">菜单项 3</div>
    </div>

    <div v-if="showModal" v-click-outside="closeModal" class="modal">
      <div class="modal-content">
        <h3>模态框</h3>
        <p>点击模态框外部可以关闭</p>
        <button @click="showModal = false">关闭</button>
      </div>
    </div>

    <button @click="showModal = true" style="margin-left: 10px;">
      打开模态框
    </button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const showDropdown = ref(false)
const showModal = ref(false)

// 点击外部关闭指令
const vClickOutside = {
  mounted(el, binding) {
    el._clickOutsideHandler = (event) => {
      // 检查点击是否在元素外部
      if (!(el === event.target || el.contains(event.target))) {
        binding.value(event)
      }
    }
    document.addEventListener('click', el._clickOutsideHandler)
  },
  unmounted(el) {
    document.removeEventListener('click', el._clickOutsideHandler)
  }
}

const closeDropdown = () => {
  showDropdown.value = false
}

const closeModal = () => {
  showModal.value = false
}
</script>

<style scoped>
.dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  background: white;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  z-index: 1000;
  margin-top: 5px;
}

.dropdown-item {
  padding: 10px 20px;
  cursor: pointer;
  border-bottom: 1px solid #eee;
}

.dropdown-item:hover {
  background: #f5f5f5;
}

.dropdown-item:last-child {
  border-bottom: none;
}

.modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0,0,0,0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
}

.modal-content {
  background: white;
  padding: 30px;
  border-radius: 8px;
  max-width: 400px;
  width: 90%;
}
</style>

5.2 输入限制指令

<template>
  <div class="input-restriction-demo">
    <h2>输入限制指令演示</h2>
    
    <div class="input-group">
      <label>仅数字输入:</label>
      <input v-number-only v-model="numberInput" placeholder="只能输入数字" />
      <span>值: {{ numberInput }}</span>
    </div>

    <div class="input-group">
      <label>最大长度限制:</label>
      <input v-limit-length="10" v-model="limitedInput" placeholder="最多10个字符" />
      <span>值: {{ limitedInput }}</span>
    </div>

    <div class="input-group">
      <label>禁止特殊字符:</label>
      <input v-no-special-chars v-model="noSpecialInput" placeholder="不能输入特殊字符" />
      <span>值: {{ noSpecialInput }}</span>
    </div>

    <div class="input-group">
      <label>自动格式化手机号:</label>
      <input v-phone-format v-model="phoneInput" placeholder="输入手机号" />
      <span>值: {{ phoneInput }}</span>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const numberInput = ref('')
const limitedInput = ref('')
const noSpecialInput = ref('')
const phoneInput = ref('')

// 仅数字输入指令
const vNumberOnly = {
  mounted(el) {
    el.addEventListener('input', (e) => {
      e.target.value = e.target.value.replace(/[^\d]/g, '')
      // 触发 v-model 更新
      e.dispatchEvent(new Event('input'))
    })
  }
}

// 长度限制指令
const vLimitLength = {
  mounted(el, binding) {
    const maxLength = binding.value
    el.setAttribute('maxlength', maxLength)
    
    el.addEventListener('input', (e) => {
      if (e.target.value.length > maxLength) {
        e.target.value = e.target.value.slice(0, maxLength)
        e.dispatchEvent(new Event('input'))
      }
    })
  }
}

// 禁止特殊字符指令
const vNoSpecialChars = {
  mounted(el) {
    el.addEventListener('input', (e) => {
      e.target.value = e.target.value.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '')
      e.dispatchEvent(new Event('input'))
    })
  }
}

// 手机号格式化指令
const vPhoneFormat = {
  mounted(el) {
    el.addEventListener('input', (e) => {
      let value = e.target.value.replace(/\D/g, '')
      
      if (value.length > 3 && value.length <= 7) {
        value = value.replace(/(\d{3})(\d+)/, '$1-$2')
      } else if (value.length > 7) {
        value = value.replace(/(\d{3})(\d{4})(\d+)/, '$1-$2-$3')
      }
      
      e.target.value = value
      e.dispatchEvent(new Event('input'))
    })
  }
}
</script>

<style scoped>
.input-restriction-demo {
  padding: 20px;
}

.input-group {
  margin: 15px 0;
}

label {
  display: inline-block;
  width: 150px;
  font-weight: bold;
}

input {
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  margin: 0 10px;
  width: 200px;
}

span {
  color: #666;
  font-size: 14px;
}
</style>

5.3 权限控制指令

<template>
  <div class="permission-demo">
    <h2>权限控制指令演示</h2>
    
    <div class="user-info">
      <label>当前用户角色:</label>
      <select v-model="currentRole" @change="updatePermissions">
        <option value="guest">游客</option>
        <option value="user">普通用户</option>
        <option value="editor">编辑者</option>
        <option value="admin">管理员</option>
      </select>
    </div>

    <div class="permission-list">
      <h3>可用功能:</h3>
      
      <button v-permission="'view'" class="feature-btn">
        🔍 查看内容
      </button>
      
      <button v-permission="'edit'" class="feature-btn">
        ✏️ 编辑内容
      </button>
      
      <button v-permission="'delete'" class="feature-btn">
        🗑️ 删除内容
      </button>
      
      <button v-permission="'admin'" class="feature-btn">
        ⚙️ 系统管理
      </button>
      
      <button v-permission="['edit', 'delete']" class="feature-btn">
        🔄 批量操作
      </button>
    </div>

    <div class="current-permissions">
      <h3>当前权限:</h3>
      <ul>
        <li v-for="permission in currentPermissions" :key="permission">
          {{ permission }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

// 角色权限映射
const rolePermissions = {
  guest: ['view'],
  user: ['view', 'edit'],
  editor: ['view', 'edit', 'delete'],
  admin: ['view', 'edit', 'delete', 'admin']
}

const currentRole = ref('user')
const currentPermissions = ref(['view', 'edit'])

// 权限控制指令
const vPermission = {
  mounted(el, binding) {
    checkPermission(el, binding)
  },
  updated(el, binding) {
    checkPermission(el, binding)
  }
}

// 检查权限函数
const checkPermission = (el, binding) => {
  const requiredPermissions = Array.isArray(binding.value) 
    ? binding.value 
    : [binding.value]
  
  const hasPermission = requiredPermissions.some(permission => 
    currentPermissions.value.includes(permission)
  )
  
  if (!hasPermission) {
    el.style.display = 'none'
  } else {
    el.style.display = 'inline-block'
  }
}

// 更新权限
const updatePermissions = () => {
  currentPermissions.value = rolePermissions[currentRole.value] || []
}
</script>

<style scoped>
.permission-demo {
  padding: 20px;
  max-width: 600px;
  margin: 0 auto;
}

.user-info {
  margin: 20px 0;
}

select {
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  margin-left: 10px;
}

.permission-list {
  margin: 30px 0;
}

.feature-btn {
  display: inline-block;
  padding: 12px 20px;
  margin: 5px;
  background: #42b983;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  transition: background 0.3s;
}

.feature-btn:hover {
  background: #369870;
}

.current-permissions {
  margin-top: 30px;
  padding: 15px;
  background: #f5f5f5;
  border-radius: 8px;
}

.current-permissions ul {
  list-style: none;
  padding: 0;
}

.current-permissions li {
  padding: 5px 10px;
  background: white;
  margin: 5px 0;
  border-radius: 4px;
  border-left: 4px solid #42b983;
}
</style>

六、 高级技巧与最佳实践

6.1 指令参数动态化

<template>
  <div>
    <input v-tooltip="tooltipConfig" placeholder="悬浮显示提示" />
    
    <div v-pin="pinConfig" class="pinned-element">
      可动态配置的固定元素
    </div>
    
    <button @click="updateConfig">更新配置</button>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

// 动态提示指令
const vTooltip = {
  mounted(el, binding) {
    const config = binding.value
    el.title = config.text
    el.style.cursor = config.cursor || 'help'
    
    if (config.position) {
      el.dataset.position = config.position
    }
  },
  updated(el, binding) {
    const config = binding.value
    el.title = config.text
  }
}

// 动态固定指令
const vPin = {
  mounted(el, binding) {
    updatePinPosition(el, binding)
  },
  updated(el, binding) {
    updatePinPosition(el, binding)
  }
}

const updatePinPosition = (el, binding) => {
  const config = binding.value
  el.style.position = 'fixed'
  el.style[config.side] = config.distance + 'px'
  el.style.zIndex = config.zIndex || 1000
}

const tooltipConfig = reactive({
  text: '这是一个动态提示',
  cursor: 'help',
  position: 'top'
})

const pinConfig = reactive({
  side: 'top',
  distance: 20,
  zIndex: 1000
})

const updateConfig = () => {
  tooltipConfig.text = `更新后的提示 ${Date.now()}`
  pinConfig.side = pinConfig.side === 'top' ? 'bottom' : 'top'
  pinConfig.distance = Math.random() * 100 + 20
}
</script>

6.2 指令组合与复用

// directives/composable.js
export function useClickHandlers() {
  return {
    mounted(el, binding) {
      el._clickHandler = binding.value
      el.addEventListener('click', el._clickHandler)
    },
    unmounted(el) {
      el.removeEventListener('click', el._clickHandler)
    }
  }
}

export function useHoverHandlers() {
  return {
    mounted(el, binding) {
      el._mouseenterHandler = binding.value.enter
      el._mouseleaveHandler = binding.value.leave
      
      if (el._mouseenterHandler) {
        el.addEventListener('mouseenter', el._mouseenterHandler)
      }
      if (el._mouseleaveHandler) {
        el.addEventListener('mouseleave', el._mouseleaveHandler)
      }
    },
    unmounted(el) {
      if (el._mouseenterHandler) {
        el.removeEventListener('mouseenter', el._mouseenterHandler)
      }
      if (el._mouseleaveHandler) {
        el.removeEventListener('mouseleave', el._mouseleaveHandler)
      }
    }
  }
}

// 组合指令
export const vInteractive = {
  mounted(el, binding) {
    const { click, hover } = binding.value
    
    if (click) {
      el.addEventListener('click', click)
      el._clickHandler = click
    }
    
    if (hover) {
      el.addEventListener('mouseenter', hover.enter)
      el.addEventListener('mouseleave', hover.leave)
      el._hoverHandlers = hover
    }
  },
  unmounted(el) {
    if (el._clickHandler) {
      el.removeEventListener('click', el._clickHandler)
    }
    if (el._hoverHandlers) {
      el.removeEventListener('mouseenter', el._hoverHandlers.enter)
      el.removeEventListener('mouseleave', el._hoverHandlers.leave)
    }
  }
}

七、 总结

7.1 核心要点回顾

  • 生命周期钩子:Vue3 提供了 7 个生命周期钩子,覆盖了指令的完整生命周期
  • 参数传递:通过 binding 对象可以访问指令的值、参数、修饰符等信息
  • 多种定义方式:支持全局注册和局部注册,兼容选项式 API 和组合式 API
  • 灵活性:指令可以接收动态参数、对象值,支持复杂的交互逻辑

7.2 最佳实践

  • 命名规范:使用小写字母和连字符命名指令
  • 内存管理:在 unmounted 钩子中清理事件监听器和定时器
  • 性能优化:避免在指令中进行昂贵的 DOM 操作
  • 可复用性:将通用指令提取为独立模块
  • 类型安全:为指令提供 TypeScript 类型定义

7.3 适用场景

  • DOM 操作:焦点管理、元素定位、动画控制
  • 输入处理:格式化、验证、限制
  • 用户交互:点击外部、滚动加载、拖拽
  • 权限控制:基于角色的元素显示/隐藏
  • 第三方集成:包装现有的 JavaScript 库

自定义指令是 Vue.js 生态中一个非常强大的特性,合理使用可以极大地提高代码的复用性和可维护性。

以上就是从基础到高级应用详解Vue3中自定义指令的完整指南的详细内容,更多关于Vue3自定义指令的资料请关注脚本之家其它相关文章!

相关文章

  • 详解VUE的状态控制与延时加载刷新

    详解VUE的状态控制与延时加载刷新

    本篇文章主要介绍了详解VUE的状态控制与延时刷新,实例分析了数据延时到展示的时候再去刷新的技巧,有兴趣的可以了解一下。
    2017-03-03
  • 在同一个Vue项目中的不同vue和HTML页面之间进行跳转方式

    在同一个Vue项目中的不同vue和HTML页面之间进行跳转方式

    这篇文章主要介绍了在同一个Vue项目中的不同vue和HTML页面之间进行跳转方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • Vue项目优化的一些实战策略

    Vue项目优化的一些实战策略

    代码优化不仅仅局限在业务逻辑这块,像是代码复用、效率等等都是我们可以加以改进的地方,这篇文章主要给大家介绍了关于Vue项目优化的一些实战策略,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • Vue 事件中的 .native你搞明白了吗

    Vue 事件中的 .native你搞明白了吗

    .native主要是给自定义的组件添加原生事件,可以理解为该修饰符的作用就是把一个vue组件转化为一个普通的HTML标签,并且该修饰符对普通HTML标签是没有任何作用的,这篇文章主要介绍了vue 事件中的 .native你搞清楚了吗,需要的朋友可以参考下
    2023-02-02
  • 如何使用Vue3设计实现一个Model组件浅析

    如何使用Vue3设计实现一个Model组件浅析

    v-model在Vue里面是一个语法糖,数据的双向绑定,本质上还是通过 自定义标签的attribute传递和接受,下面这篇文章主要给大家介绍了关于如何使用Vue3设计实现一个Model组件的相关资料,需要的朋友可以参考下
    2022-08-08
  • vue中echarts视图不更新问题及解决

    vue中echarts视图不更新问题及解决

    这篇文章主要介绍了vue中echarts视图不更新问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Vue中的nextTick作用和几个简单的使用场景

    Vue中的nextTick作用和几个简单的使用场景

    这篇文章主要介绍了Vue中的nextTick作用和几个简单的使用场景,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下
    2021-01-01
  • 详解Vue3如何优雅的加载大量图片

    详解Vue3如何优雅的加载大量图片

    最近开发了一个功能,页面首页会加载大量的图片,初次进入页面时,会导致页面性能下降,于是乎,我改进了这个功能,可以让所有图片自动懒加载,文中有详细的代码示例,需要的朋友可以参考下
    2023-09-09
  • Vue中Video标签播放解析后短视频去水印无响应解决

    Vue中Video标签播放解析后短视频去水印无响应解决

    这篇文章主要为大家介绍了Vue中使用Video标签播放 <解析后的短视频>去水印视频无响应的解决方式,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-04-04
  • Vue中动态引入图片要是require的原因解析

    Vue中动态引入图片要是require的原因解析

    require是一个node方法,用于引入模块,JSON或本地文件,这篇文章主要介绍了vue中动态引入图片为什么要是require,需要的朋友可以参考下
    2022-10-10

最新评论