一句话:Vue 2 项目里反复用到的「强制刷新、函数式挂载、透传属性、VNode 渲染」四类技巧,一次收齐。
写在前面
这些技巧来自 Vue 2 + Element UI 时代的业务项目,在 Options API 下依然有效。若你已全面迁移 Vue 3,文中 $listeners、$createElement 等 API 需对照 Composition API 与 h() 使用。
读完你能:在数据变了但 DOM 不刷时快速排查;封装可全局调用的登录弹窗;用 VNode 动态渲染列表内容。
核心内容
1. 数据变了,DOM 不重新渲染
Vue 的响应式有时无法感知深层结构或第三方组件内部状态。可用 v-if 强制销毁再重建:
javascript
data() {
return { hackReset: true }
},
methods: {
forceRerender() {
this.hackReset = false
this.$nextTick(() => {
this.hackReset = true
})
}
}
模板中:<MyComponent v-if="hackReset" />。本质是「卸载 → 下一 tick 再挂载」,适合偶发 UI 不同步,不宜高频调用。
2. computed 的 getter / setter
computed 默认只读,也可定义 set 实现双向绑定:
javascript
computed: {
fullName: {
get() {
return `${this.firstName} ${this.lastName}`
},
set(newValue) {
const names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
3. v-model 修饰符
v-model.number:输入转数字v-model.trim:去掉首尾空格
4. 手动挂载组件(Vue.extend + $mount)
适合「任意页面弹出登录框」等场景:不依赖路由,直接挂到 document.body。
组件 index.vue:封装 showXiaLogin / hideXiaLogin 等方法。
入口 main.js:
javascript
import Vue from 'vue'
import XiaLogin from './index.vue'
const XiaLoginConstructor = Vue.extend(XiaLogin)
let XiaLoginInstance
function createXiaLogin() {
XiaLoginInstance = new XiaLoginConstructor({ data: {} })
// 无参数 $mount() 只生成 DOM 片段,尚未插入页面
XiaLoginInstance.$mount()
document.body.appendChild(XiaLoginInstance.$el)
return XiaLoginInstance
}
export function showXiaLogin(args, callback) {
if (!XiaLoginInstance) {
XiaLoginInstance = createXiaLogin()
}
XiaLoginInstance.showXiaLogin(args)
callback && callback()
return XiaLoginInstance
}
要点:单例避免重复创建占内存;销毁时调用 $destroy() 并移除 $el。
5. 封装组件时的属性与事件
| 机制 | 用途 |
|---|---|
| 单向数据流 | 父改子跟;子改父用 $emit |
| 勿直接改 props | 引用类型虽可改,但数据流混乱 |
provide / inject |
跨多层传递,避免 props 钻取 |
.sync / update:xxx |
子组件 $emit('update:visible', false) |
$attrs + $listeners |
二次封装 UI 库时透传(见 45 篇) |
6. 用 createElement 渲染动态内容
Element UI 的 $msgbox 等只接受 VNode 时,用 $createElement(别名 h):
javascript
const h = this.$createElement
const list = dataList.map(v =>
h('p', null, [
h('span', { style: 'font-weight:500' }, `${v.pat_name}:`),
h('span', { style: 'font-weight:500' }, v.phone_number),
h('span', {
style: {
color: v.notify_result === 1 ? '#67C23A' : '#F56C6C',
marginLeft: '20px'
}
}, v.notify_result === 1 ? '成功' : '失败')
])
)
this.$msgbox({
title: '已发送列表',
message: h('div', null, list),
showCancelButton: false
})
踩坑
v-if强刷会丢失组件内部状态,表单场景慎用。- 手动挂载忘记
$destroy会导致内存泄漏和重复监听。 - 直接改 props 对象属性在 Vue 2 不报错但违反单向数据流,后期难排查。
- Vue 3 中
$listeners已合并进$attrs,.sync改为v-model:propName。
小结
- 渲染异常:优先查 key / 响应式边界,必要时
v-if强刷。 - 全局弹窗:
Vue.extend+ 单例 +$mount()+appendChild。 - 封装 UI 库:用
$attrs/$listeners(Vue 3 见inheritAttrs+$attrs)。 - 动态 DOM:
h()/$createElement比字符串 HTML 更安全可控。


全部评论(0)