渐进式JavaScript框架:Vue --- API
- 前言
-
- 全局配置
- [全局 API](#全局 API)
- 选项
-
- 核心数据选项(处理响应式数据)
- [DOM 选项(关联 DOM 元素 / 模板)](#DOM 选项(关联 DOM 元素 / 模板))
- [资源选项(注册指令 / 过滤器 / 组件)](#资源选项(注册指令 / 过滤器 / 组件))
- [组合选项(复用 / 扩展实例逻辑)](#组合选项(复用 / 扩展实例逻辑))
- 其他选项(杂项配置)
- 生命周期钩子选项(控制实例生命周期)
-
- [特殊生命周期钩子(路由 /keep-alive 相关)](#特殊生命周期钩子(路由 /keep-alive 相关))
- 实例属性
- 指令
- [特殊 attribute](#特殊 attribute)
- 内置的组件
- [VNode 接口](#VNode 接口)
- 服务端渲染
前言
Vue 提供给开发者用于构建组件、管理状态、处理事件等的一系列方法、属性和规则。
全局配置
Vue.config 是一个对象,包含 Vue 的全局配置。它的配置应该在你调用 new Vue() 之前完成,因为一旦应用实例被创建,某些配置可能就无法更改了。
silent:boolean类型,默认值false,用于取消 Vue 所有的日志与警告。
html
<body>
<div id="app" v-cloak>
<h1>{{hello-world}}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.config.silent = true;
new Vue({
el: "#app",
data: {
helloWorld: 1
},
})
</script>
</body>
设置为true后就不会打印错误日志,执行结果如图:

devtools:boolean类型,默认值true,true(在开发环境中) /false(在生产环境中) ,配置是否允许使用 Vue Devtools 调试插件。
需要先安装浏览器调试插件:Vue DevTools或者再Chrome 商店搜索安装Vue.js devtools (需要VPN ,要注意插件最新的仅支持Vue3 ,我们这使用Vue2 所以插件版本也是Vue2 )。

安装完毕后重启浏览器,F12 可以看到标签多了一个Vue标签,开启调试插件(关闭的情况下看不到元素标签)
html
<body>
<div id="app" v-cloak>
<h1>{{helloworld}}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.config.devtools = true;
new Vue({
el: "#app",
data: {
helloworld: 1
},
})
</script>
</body>
直接操作元素后,如图所示:

optionMergeStrategies:{ [key: string]: Function }类型,默认值{},用于自定义组件选项的合并策略。
js
<script>
Vue.config.optionMergeStrategies._my_option = function (parent, child, vm) {
console.log(parent); // undefined
console.log(child); // 1
return child + 1
}
const Profile = Vue.extend({
_my_option: 1
})
console.log(Profile.options._my_option)
// Profile.options._my_option = 2
</script>
performance:boolean类型,默认值false,设置为true以在浏览器开发工具的性能/时间线面板中启用对组件初始化、编译、渲染和打补丁的性能追踪。只适用于开发模式和支持performance.markAPI 的浏览器上。
javascript
Vue.config.performance = true;
productionTip:boolean类型,默认值true,控制在浏览器控制台中是否显示生产环境的提示信息。
javascript
Vue.config.productionTip = true;
在 HTML 环境中Vue.config.productionTip 的设置几乎不起作用(使用vue.min.js(生产版)去除警告)。当你使用 Vue CLI 或其他构建工具时才会生效。

errorHandler:Function类型,默认值undefined,指定一个全局的错误处理函数,用于捕获组件渲染和观察器执行期间的错误。这在生产环境中非常有用,可以帮助你收集错误信息。
javascript
<script>
// 1. 全局错误处理配置(必须在 new Vue() 之前)
// err: 错误对象(包含错误信息、堆栈等)
// vm: 发生错误的 Vue 实例(可通过 vm 访问组件信息)
// info: 错误发生场景描述(如 "render" 渲染时、"watch getter" 侦听器中)
Vue.config.errorHandler = function (err, vm, info) {
// 2. 控制台打印错误详情(开发环境调试用)
console.group('%c Vue 全局错误捕获 ', 'background: #f03838; color: white; padding: 2px 8px; border-radius: 3px;')
console.log('错误信息:', err.message) // 简洁错误描述
console.log('错误堆栈:', err.stack) // 错误调用栈(定位代码位置)
console.log('发生错误的组件:', vm.$options.name || '匿名组件') // 组件名称
console.log('错误场景:', info) // 场景说明(如 render/watcher/生命周期钩子)
console.log('组件 props:', vm.$props) // 组件接收的 props(辅助排查)
console.groupEnd()
// 模拟接口请求(实际用 axios/fetch 发送)
fetch('/api/error-log', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(errorData)
}).catch(reportErr => {
console.log('错误上报失败:', reportErr)
})
}
// 2. 创建 Vue 实例
new Vue({
render: h => h(App)
}).$mount('#app')
</script>
执行结果如图:

warnHandler:Function类型,默认值undefined,指定一个全局的警告处理函数。
javascript
<script>
// 全局警告处理(必须在 new Vue() 之前配置)
// msg: 警告核心信息(如 "props 校验失败")
// vm: 触发警告的 Vue 实例(可获取组件名称、props 等)
// trace: 组件树追踪(显示警告在哪个组件层级触发)
Vue.config.warnHandler = function (msg, vm, trace) {
// 格式化打印警告(控制台分组,更清晰)
console.group('%c Vue 全局警告捕获 ', 'background: #ff9800; color: white; padding: 2px 8px; border-radius: 3px;')
console.log('警告信息:', msg)
console.log('触发组件:', vm.$options.name || '匿名组件') // 组件名称(方便定位)
console.log('组件 Props:', vm.$props) // 组件当前接收的 props(辅助排查)
console.log('组件树追踪:', trace) // 组件嵌套路径(多层组件时有用)
console.groupEnd()
}
// 2. 创建 Vue 实例
new Vue({
render: h => h(App)
}).$mount('#app2')
</script>
执行结果如图:

ignoredElements:Array<string>类型,默认值[],告诉 Vue 编译器要忽略哪些自定义元素。这在你使用像 Web Components 或其他库创建的自定义元素时非常有用,以避免 Vue 报出 "未知自定义元素" 的警告。
html
<body>
<div id="app">
<!-- 1. 自定义 HTML 元素(非 Vue 组件):my-header、my-footer -->
<my-header>这是自定义 HTML 元素 <my-header></my-header>
<!-- 2. Vue 组件(正常注册,无需忽略) -->
<vue-component></vue-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 关键配置:忽略指定的自定义 HTML 元素(字符串数组形式)
// 这里忽略 <my-header> 和 <my-footer> 两个自定义元素
Vue.config.ignoredElements = ['my-header']
// 注册 Vue 组件(正常使用,无需忽略)
Vue.component('vue-component', {
template: `
<div class="vue-component">
<p>这是 Vue 注册的组件(正常渲染)</p>
<p>Vue 会解析这个组件,不会报未知元素警告</p>
</div>
`
})
// 创建 Vue 实例
new Vue({
el: '#app'
})
</script>
</body>
若注释掉 Vue.config.ignoredElements 配置,浏览器控制台会报警告,如图所示:

keyCodes:Object类型,默认值{},给v-on自定义键位别名。
html
<body>
<div id="app">
<!-- 场景1:输入框按 "S" 触发保存(自定义组合键 alias-save) -->
<p>输入框 1:按 <strong>S</strong> 触发保存</p>
<input v-model="inputValue" @keyup.alias-save="handleSave" placeholder="输入内容后按 S 试试">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.config.keyCodes = {
// 1. 键码 83 是 S,自定义别名为 "alias-save"
'alias-save': 83, // S 键的键码,配合 @keyup.ctrl 使用
}
// 创建 Vue 实例
new Vue({
el: '#app',
data: {
inputValue: '',
},
methods: {
handleSave() {
alert(this.inputValue)
}
}
})
</script>
</body>
输入内容后,按S键触发。
全局 API
Vue.extend():基于 Vue 构造函数创建一个 "子类"(组件构造函数,可以包含普通 Vue 组件的所有选项props、data、template、methods),用于高级组件开发。
javascript
<body>
<div id="app">
<div id="app"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
const UserCard = Vue.extend({
// 组件选项(和普通 Vue 组件一致)
props: {
// 接收外部传入的属性
username: {
type: String,
required: true
},
age: {
type: Number,
default: 18
}
},
data() {
return {
isShow: true
}
},
template: `
<div class="user-card" v-if="isShow">
<h3>用户名:{{ username }}</h3>
<p>年龄:{{ age }}</p>
<button @click="hideCard">隐藏卡片</button>
</div>
`,
methods: {
hideCard() {
this.isShow = false;
}
}
})
// 直接实例化组件并挂载到指定 DOM(静态挂载)
new UserCard({
propsData: { // 给 props 传值(实例化时用 propsData,组件内用 props)
username: "张三",
age: 25
}
}).$mount('#app'); // 挂载到 #app 元素
</script>
</body>
用 $mount(容器选择器) 手动挂载组件到 DOM,适合需要动态创建组件的场景。
Vue.component():注册全局组件或获取全局组件(全局组件可在任何子组件模板中直接使用,无需在components选项中声明)。
html
<body>
<div id="app">
<global-button text="全局按钮"></global-button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 方式1:直接传组件选项对象
Vue.component('global-button', {
template: '<button @click="handleClick">{{ text }}</button>',
props: ['text'],
methods: {
handleClick() {
alert('全局组件被点击!')
}
}
})
// 方式2:传入组件构造函数(通过 Vue.extend)
const GlobalCard = Vue.extend({
template: '<div class="card">{{ content }}</div>',
props: ['content']
})
Vue.component('global-card', GlobalCard)
// 获取注册的组件 (始终返回构造器)
var globalComponent = Vue.component('global-button')
// 创建 Vue 实例
new Vue({
el:"#app",
})
</script>
</body>
在任何组件模板中直接用<global-button>标签使用。
Vue.compile( template ):将一个模板字符串编译成渲染(render)函数。
javascript
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 定义模板字符串(支持 Vue 所有模板语法:插值、指令、事件绑定等)。
var templateStr =`<div> hello,{{msg}} </div>`;
const complied = Vue.compile(templateStr);
new Vue({
el:"#app",
data:{
msg:"Vue compile"
},
render: complied.render,// 核心渲染函数,负责生成 VNode(虚拟 DOM)。
staticRenderFns: complied.staticRenderFns // 静态内容的渲染函数(优化性能)。
})
</script>
</body>
将字符串内容编译成渲染函数后,再app元素中生成内容。
Vue.directive():注册全局自定义指令(操作 DOM 元素,如防抖、权限控制)。
html
<body>
<div id="app">
<input v-focus type="text" placeholder="自动聚焦的输入框">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.directive('focus', {
// 指令绑定到元素时调用(只调用一次)
bind: function () { },
// 元素插入到 DOM 时调用
inserted: function (el) {
// 当元素插入到 DOM 时自动聚焦
el.focus()
},
// 指令模板被重新解析时调用
update: function () { },
// 指令模板全部更新后调用
componentUpdated: function () { },
// 指令与元素解绑时调用(只调用一次)
unbind: function () { }
})
// 创建Vue实例(父组件)
var app = new Vue({
el: "#app",
data: {}
});
</script>
</body>
再标签中使用自定义指令,页面渲染后会自动选中。
Vue.filter():注册全局过滤器(格式化数据,如日期、金额;Vue 3 已移除)。
html
<body>
<div id="app">
<p>{{message | toUpperCase}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.filter('toUpperCase', function (value) {
return value ? value.toUpperCase() : ''
})
var app = new Vue({
el: '#app',
data: {
message: 'hello vue'
}
})
</script>
</body>
通过 |(管道符)使用过滤器,支持链式调用(多个过滤器依次处理),语法为:{``{ 数据 | 过滤器名 | 过滤器名2...}}。
Vue.nextTick():等待 DOM 更新完成后执行回调(Vue 异步更新 DOM ,需在 nextTick 中获取更新后的 DOM)。
html
<body>
<div id="app">
<p ref="content">{{message}}</p>
<button @click="updateMessage">更新文本</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'hello vue'
},
methods:{
updateMessage(){
// 1. 修改数据
this.message = 'hello vue2'
// 2. 立即获取 DOM 内容,此时 DOM 还未更新
console.log('立即获取:', this.$refs.content.textContent); // Output:hello vue
// 3. 使用 nextTick,DOM 更新后执行回调
this.$nextTick(()=>{
console.log(this.$el.querySelector('p').innerHTML) // Output:hello vue2
})
// 全局使用
Vue.nextTick(function() {
console.log('全局 nextTick:', this.$refs.content.textContent); // Output:hello vue2
}, this);
}
}
})
</script>
</body>
组件内优先用 this.$nextTick(),无需手动绑定上下文,更简洁
Vue.set():向响应式对象添加新属性(Vue 2 中直接给响应式对象赋值新属性不会触发响应式更新,需用Vue.set)。
html
<body>
<div id="app">
<span>姓名:</span>
<p>{{user.name}}</p>
<span>爱好:</span>
<p v-for="item in user.hobby">{{item}}</p>
<button @click="updateMessage">变更按钮</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
// 响应式对象(非 Vue 实例、非根数据对象)
user: {
name: '张三',
hobby:['打球','阅读','装逼']
}
},
methods: {
updateMessage() {
// Vue.set 修改对象属性元素
Vue.set(this.user, 'name', '李四')
// Vue.set 修改数组下标元素
Vue.set(this.user.hobby, 2, '听音乐')
}
}
})
</script>
</body>
Vue2 基于 Object.defineProperty 实现响应式,直接给对象新增属性 / 修改数组下标元素。Vue.set()(或实例方法 this.$set)的作用是:手动给响应式对象添加响应式属性,确保属性的修改能触发视图更新。
对象不能是 Vue 实例,或者 Vue 实例的根数据对象
js
// 错误1:对象是 Vue 实例(this 是当前组件实例)
Vue.set(this, 'age', 20);
// 错误2:对象是根数据对象(this.$data 是根数据)
Vue.set(this.$data, 'gender', '男');
// 正确:给根数据下的子对象新增属性(非根、非实例)
this.$set(this.user, 'age', 20); // 前提:data 里定义 user: {}
Vue.set() 的第一个参数必须是:响应式的普通对象 / 数组(比如 data() 里定义的 user: {}、list: []) 。禁止操作 Vue 实例 / 根数据对象,是为了避免破坏 Vue 内部的响应式管理逻辑。
Vue.observable():让一个对象可响应。Vue 内部会用它来处理data函数返回的对象。
html
<body>
<div id="app">
<p>点击次数:{{count}}</p>
<p>用户:{{userInfo.name}}</p>
<button @click="increment">点击+1</button>
<button @click="updateName">更新文本</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 1. 定义普通对象
const state = {
count: 0,
user: {
name: 'zhangsan'
}
}
// 2. 转为响应式对象
const reactiveState = Vue.observable(state);
var app = new Vue({
el: '#app',
// 方式1:通过计算属性读取(推荐,确保响应式)
computed: {
count() {
return reactiveState.count
},
userInfo() {
return reactiveState.user
}
},
methods: {
increment() {
reactiveState.count++;
},
updateName(){
reactiveState.user.name = 'lisi';
}
}
})
</script>
</body>
对于小型项目 / 简单全局状态,无需引入 Vuex ,用 observable 快速实现跨组件响应式数据共享。
Vue.delete():删除响应式对象的属性(并触发 DOM 更新,直接 delete 不会触发响应式)。
html
<body>
<div id="app">
<span>姓名:</span>
<p>{{user.name}}</p>
<span>年龄</span>
<p>{{user.age}}</p>
<span>爱好:</span>
<p v-for="item in user.hobby">{{item}}</p>
<button @click="delAge">删除按钮</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
// 响应式对象(非 Vue 实例、非根数据对象)
user: {
name: '张三',
age: 19,
hobby: ['打球', '阅读', '装逼']
}
},
methods: {
delAge() {
// 方式1:组件内用 this.$delete(推荐)
this.$delete(this.user, 'age')
// 方式2:全局 Vue.delete(效果相同)
Vue.delete(this.user, 'age')
// 删除数组索引为1的元素
this.$delete(this.user.hobby, 1)
// 等价于(推荐数组方法)
this.user.hobby.splice(1, 1)
}
}
})
</script>
</body>
但是你应该很少会使用它。使用时记住:
对象删属性用
$delete,数组删元素优先用splice。
Vue.mixin():注册全局混入(混入对象的选项会合并到所有组件的选项中,用于复用逻辑)。
html
<body>
<div id="app">
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建全局混入
Vue.mixin({
data() {
return {
globalData: '全局数据'
}
},
created() {
console.info('全局混入的 created 钩子执行')
},
methods: {
mixinMethod() {
console.log('全局混入的 mixinMethod 方法')
}
}
})
// 创建组件
Vue.component('my-component', {
data(){
return{
componentData: '组件数据'
}
},
created() {
console.log(this.$data); // => {globalData: '全局数据'componentData:'组件数据'}
this.mixinMethod(); // 覆盖mixin中的方法
},
methods: {
mixinMethod() {
console.log('组件的mixinMethod');
}
},
template: `<div>{{globalData}}-{{componentData}}</div>`
})
new Vue({
el: "#app"
})
</script>
</body>
当组件自有配置和 mixin 配置冲突时,Vue 会按规则合并:组件自有 data覆盖 mixin 中同名属性;组件自有methods/computed覆盖 mixin 中同名方法;生命周期钩子,不覆盖,先执行 mixin 中的钩子,再执行组件自有钩子。
Vue.use():安装 Vue 插件(如 Vuex、Vue Router、Element UI ),本质是调用插件的 install 方法。
js
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// 安装 ElementUI,并传递语言配置
Vue.use(ElementUI, { size: 'small', zIndex: 3000 })
在纯HTML 中使用Vue 时,不需要强制使用Vue.use,直接引入Vue 的JS文件即可使用核心功能。
Vue.version:提供字符串形式的 Vue 安装版本号。可以根据不同的版本号采取不同的策略。
html
<body>
<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
console.log(Vue.version) // 2.7.16
var version = Number(Vue.version.split('.')[0])
if (version === 2) {
// Vue v2.x.x
} else if (version === 1) {
// Vue v1.x.x
} else {
// Unsupported versions of Vue
}
</script>
</body>
选项
Vue 2.0 的实例选项是在 new Vue({ /* 这里的配置 */ }) 或组件定义中传入的键值对。
核心数据选项(处理响应式数据)
data:Function | Object(根实例)类型,声明组件的响应式数据(Vue2 组件的定义只接受function,避免组件复用数据污染;根实例可直接是对象)。
html
<body>
<div id="app">
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 组件
Vue.component('my-component', {
data() {
return {
message: 'hello component'
}
},
template:'<div>{{message}}</div>'
})
// 根实例
new Vue({
el: "#app",
data: {
message: 'hello vue'
}
})
console.log(vm.$data)
</script>
</body>
Vue 会递归地把 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。

实例创建之后,可以通过 vm.$data 访问原始数据对象。Vue 实例也代理了 data 对象上所有的属性,因此访问 vm.属性 等价于访问 vm.$data.属性。
javascript
<script>
const vm = new Vue({
el: "#app",
data: {
message: 'hello vue'
}
})
console.log(vm.$data) // 对象实例 message
console.log(vm.message === vm.$data.message); // true
</script>
以 _ 或 $ 开头的属性不会被 Vue 实例代理,因为它们可能和 Vue 内置的属性、API 方法冲突。你可以使用例如 vm.$data._property 的方式访问这些属性。
javascript
<script>
const vm = new Vue({
el: "#app",
data: {
$message: 'hello vue',
_content:'this content'
}
})
console.log(vm.$data+"-"+vm.$data.$message+"-"+vm.$data._content);// 对象实例以及具体内容
console.log(vm.$message);// undefined
console.log(vm._content);// undefined
</script>
当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。
javascript
<script>
// 不使用函数报:The "data" option should be a function that returns a per-instance value in component definitions.
Vue.component('my-component', {
data() {
return {
message: 'hello component'
}
},
template:'<div>{{message}}</div>'
})
</script>
如果需要,可以通过将 vm.$data 传入 JSON.parse(JSON.stringify(...)) 得到深拷贝的原始数据对象。
注意,如果你为 data 属性使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。
javascript
<script>
Vue.component('my-component', {
data() {
return {
count: this.count + 1 // this 不是组件实例,this.count 是 undefined
}
},
template: '<div>{{count}}</div>'
})
</script>
此时 this 指向外层作用域(比如浏览器中是 window ),而 window 没有 count 属性,会报错或返回 NaN 。官方强烈不推荐 data 使用箭头函数。
props:Array<string> | Object类型,可以是数组或对象,用于接收来自父组件的数据,是组件间通信的核心方式。
你可以基于对象的语法使用以下选项:
(1)type:可以是下列原生构造函数中的一种:String、Number、Boolean、Array、Object、Date、Function、Symbol、任何自定义构造函数、或上述内容组成的数组。会检查一个 prop 是否是给定的类型,否则抛出警告。
(2)default:为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回。
(3)required:是否必传(Boolean);
(4)validator:自定义验证函数会将该 prop 的值作为唯一的参数代入。
html
<body>
<div id="app">
<props-demo-simple :size="10" :msg="msg"></props-demo-simple>
<props-demo-advanced :height="100" :age="10"></props-demo-advanced>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 简单语法
Vue.component('props-demo-simple', {
props: ['size', 'msg'],
template: `
<div class="simple">
<p>{{size}}</p>
<p>{{msg}}</p>
</div>
`
})
// 对象语法,提供验证
Vue.component('props-demo-advanced', {
props: {
// 检测类型
height: Number,
// 检测类型 + 其他验证
title: {
type: String,
default: "default title",
required: false,
},
age: {
required: true,
validator: function (value) {
return value >= 0
}
}
},
template: `
<div class="advanced">
<p>{{height}}</p>
<p>{{title}}</p>
<p>{{age}}</p>
</div>
`
})
new Vue({
el: '#app',
data: {
msg: 'Hello World'
}
})
</script>
</body>
propsData:Object类型,仅用于new创建的实例中或「测试」时,手动传递props数据(组件实例化时用)。
html
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
const Mycomponent = Vue.extend({
props:['msg'],
template: '<div>{{msg}}</div>'
})
new Mycomponent({
propsData: {
msg: 'Hello World'
}
}).$mount('#app');
</script>
</body>
创建实例时传递 props。主要作用是方便测试。
computed:{ [key: string]: Function | { get: Function, set: Function } }类型,声明基于现有数据的「计算属性」,有缓存(依赖数据不变时,多次访问不会重复计算)。
html
<body>
<div id="app">
加法:{{sum}},姓名:{{fullName}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
num1: 123,
num2: 345,
firstName: 'Jone',
lastName: 'Doe'
},
computed: {
// 可读
sum() {
return this.num1 + this.num2
},
// 可写
fullName: {
get() {
return this.firstName + ' ' + this.lastName
},
set(val) {
const [first, last] = val.split(' ')
this.firstName = first
this.lastName = last
}
}
}
})
</script>
</body>
methods:{ [key: string]: Function }类型,声明组件的方法(用于事件处理、逻辑复用,无缓存)。
html
<body>
<div id="app">
<div>当前数量:{{count}}</div>
<button @click="add">点击+1</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
count: 0
},
methods: {
add() {
this.count++
}
}
})
</script>
</body>
注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.count++),理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.count 将是 undefined。
watch:{ [key: string]: string | Function | Object | Array }类型,监听数据变化并执行回调(适合处理「数据变化后的异步 / 复杂逻辑」)。
html
<body>
<div id="app">
<button @click="c.d.e++">点击+1</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
a: 1,
b: 2,
c: {
d: {
e: 5
}
}
},
methods: {
add() {
}
},
watch: {
a(newValue, oldValue) {
console.log(newValue, oldValue)
},
// 该回调会在任何被侦听的对象的属性改变时被调用,不论其被嵌套多深
b: {
handler: function (newValue, oldValue) { console.log(newValue, oldValue) },
deep: true, // 深度监听
immediate: true // 初始化时立即执行
},
// 监听嵌套属性
'c.d.e': function (newValue, oldValue) { console.log(newValue, oldValue) }
}
})
</script>
</body>
注意,不应该使用箭头函数来定义 watcher 函数 (例如 a:newValue => this.add(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.add将是 undefined。
DOM 选项(关联 DOM 元素 / 模板)
el:string | Element(CSS 选择器字符串 或 原生 DOM 元素)类型,指定组件 / 实例挂载到页面的 DOM 元素(仅适用于根 Vue 实例,组件中不生效)。
html
<body>
<div id="app">
<div>{{msg}}</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 直接指定 el
new Vue({
el: "#app",
data: {
msg: "hello"
}
})
// 手动挂载
var vm = new Vue({
data: {
msg: "vue"
}
});
vm.$mount("#app");
</script>
</body>
根实例无 el 时,需手动调用 vm.$mount('#app') 完成挂载。挂载后,实例会替换目标元素(而非追加),可通过 template/render 控制渲染内容;
template:string类型,指定组件的模板字符串,Vue 会将模板编译为渲染函数,最终渲染到 DOM 中。
html
<body>
<div id="app">
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component("my-component", {
template: "<div>{{msg}}</div>",
data: function () {
return {
msg: "A custom component!"
}
}
});
new Vue({
el: "#app"
})
</script>
</body>
如果值以 # 开始,则它将被用作选择符,并使用匹配元素的 innerHTML 作为模板。常用的技巧是用 <script type="x-template"> 包含模板。
html
<body>
<div id="app">
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script type="text/x-template" id="my-tpl">
<div>{{ msg }}</div>
</script>
<script>
Vue.component("my-component", {
template: "#my-tpl",
data: function () {
return {
msg: "A custom component!"
}
}
});
new Vue({
el: "#app"
})
</script>
</body>
render:(createElement: () => VNode) => VNode类型,手动编写渲染函数(JS 方式),替代模板编译,优先级最高(性能更好,适合动态 / 复杂组件)。
html
<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
render: function (createElement) {
return createElement(
'div', // 标签名
{ attrs: { id: 'container' } }, // 元素属性
[createElement('h1', 'Hello Render')] // 子元素
)
}
})
</script>
</body>
Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或通过 el 选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。
renderError:(createElement: () => VNode, error: Error) => VNode类型,仅在开发环境生效 ,当render函数抛出错误时,替代原渲染内容(错误兜底)。
html
<body>
<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
render: function (createElement) {
throw new Error('oops')
},
renderError(h, err) {
return h('pre', { style: { color: 'red' } }, err.stack)
}
})
</script>
</body>
资源选项(注册指令 / 过滤器 / 组件)
directives:自定义指令不仅可以创建全局指令还可以创建局部指令。
html
<body>
<div id="app">
<input type="text" v-focus>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {},
directives:{
'focus':{
inserted:function(el){
el.focus()
}
}
}
})
</script>
</body>
filters:过滤器不仅可以创建全局过滤器还可以创建局部过滤器。
html
<body>
<div id="app">
<p>{{message | toUpperCase}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
message: 'hello world'
},
filters:{
toUpperCase:function(value){
return value.toUpperCase()
}
}
})
</script>
</body>
components:你可以在一个组件的选项中定义本地的过滤器
html
<body>
<div id="app">
<local-component></local-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 定义局部组件
const localComponent = {
data() {
return {
msg: 'hello world'
}
},
template: `<div>{{msg}}</div>`
}
// 创建实例
new Vue({
el: "#app",
components: {
// 局部组件
'localComponent': localComponent
}
})
</script>
</body>
组合选项(复用 / 扩展实例逻辑)
parent:用于访问当前组件的直接父组件实例,是父子组件通信 / 交互的重要方式。
html
<body>
<div id="app">
<local-component></local-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
const localComponent = {
template: `<button @click="callParent">获取父组件</button>`,
methods: {
callParent() {
console.log(this.$parent.msg);
this.$parent.parentMethod();
}
}
}
new Vue({
el: "#app",
data() {
return {
msg: 'hello Vue'
}
},
methods:{
parentMethod() {
console.log("父组件被调用")
}
},
components: {
'localComponent': localComponent
}
})
</script>
</body>
mixins:除了注册全局混入还可注册局部混入。
js
<script>
// 定义局部混入
const localMinix = {
data() {
return {
globalData: '局部数据'
}
},
created() {
console.info('局部混入的 created 钩子执行')
},
methods: {
mixinMethod() {
console.log('局部混入的 mixinMethod 方法')
}
}
}
// 创建Vue实例
new Vue({
el: "#app",
data: {
componentData: '组件数据'
},
created() {
console.log(this.$data); // => {globalData: '局部数据'componentData:'组件数据'}
this.mixinMethod(); // 覆盖mixin中的方法
},
methods: {
mixinMethod() {
console.log('组件的mixinMethod');
}
},
mixins: [localMinix],
template: `<div>{{globalData}}-{{componentData}}</div>`
})
</script>
extends:允许声明扩展另一个组件 (可以是一个简单的选项对象或构造函数),而无需使用Vue.extend。这主要是为了便于扩展单文件组件。
js
<script>
// 定义extends
const localBase = {
data() {
return {
baseData: '父类数据',
overData: '覆盖数据'
}
},
created() {
console.info('父类的 created 钩子执行')
},
methods: {
baseMethod() {
console.log('父类的方法')
}
}
}
// 创建Vue实例
new Vue({
el: "#app",
data: {
overData: '子类覆盖数据'
},
created() {
console.log(this.$data); // => {baseData: '父类数据',overData: '子类覆盖数据'}
this.baseMethod(); // 覆盖子类的方法
},
methods: {
baseMethod() {
console.log('子类覆盖方法');
}
},
extends: localBase,
template: `<div>{{baseData}}-{{overData}}</div>`
})
</script>
provide / inject:provide / inject是一对用于跨层级组件通信的核心 API ,解决了props/$emit仅能父子通信、多层级传递数据繁琐的问题(如祖父组件向孙组件传值)。它遵循「依赖注入」思想:上层组件通过provide提供数据 / 方法,下层任意层级组件通过inject注入使用,无需关心组件间的层级关系。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 子组件
Vue.component('child-component', {
template: `
<div>
<input ref="myInput" type="text" />
</div>
`,
// 注入数据
inject: ['userInfo', 'greet'],
mounted() {
console.log('用户信息:', this.userInfo) // { name: '张三', age: 28 }
this.greet()
}
})
// 父组件
Vue.component('my-component', {
template: `
<div>父组件
<child-component></child-component>
</div>`,
// 向外提供需要共享的数据
provide: function () {
return {
userInfo: { name: '张三', age: 20 },
greet: () => console.log('Hello from parent')
}
},
methods: {}
})
// 创建实例
var app = new Vue({
el: "#app"
})
</script>
</body>
其他选项(杂项配置)
name:string类型,用于定义组件的 "名称标识"。组件在全局用Vue.component()注册时,全局 ID 自动作为组件的name(就算定义了name也会以全局ID为准)。
html
<body>
<!-- 父组件 -->
<div id="app">
<local-component></local-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 全局 ID 自动作为组件的 name
Vue.component('my-component', {
// ...
})
const localComponent = {
name: 'local-component',
template: '<div>A custom component!</div>'
}
// 创建实例
var app = new Vue({
el: "#app",
components: {
localComponent
}
})
</script>
</body>
delimiters:Array<string>类型,默认值:["{``{", "}}"],用于自定义模板插值分隔符的配置项,核心作用是替换默认的 {{ }} 插值符号,避免与其他模板引擎(如 Jinja2 、EJS)或后端模板语法冲突。
html
<body>
<!-- 父组件 -->
<div id="app">
<p>${msg}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var app = new Vue({
el: "#app",
data: {
msg: 'hello world'
},
delimiters: ['${', '}']
})
</script>
</body>
functional:boolean类型,一种无状态、无实例、轻量级的组件类型,核心特点是仅通过函数接收props和 上下文 并返回虚拟 DOM ,没有响应式数据、生命周期钩子,也没有this上下文,性能远高于普通组件。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component :msg="msg"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 定义组件
Vue.component('my-component', {
functional: true, // 标记为函数式组件
props: {
msg: String
},
render(h, context) {
// 1. 获取 props(context.props 替代 this.props)
const { msg } = context.props;
// 返回 VNode
return h('p', msg);
}
})
// 创建实例
var app = new Vue({
el: "#app",
data: {
msg: 'Hello World'
}
})
</script>
</body>
model:{ prop?: string, event?: string }类型,自定义组件的v-model行为,v-model会把value用作prop且把input用作event,但是一些输入类型比如单选框和复选框按钮可能想使用valueprop 来达到不同的目的。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component v-model="isChecked"></my-component>
<p>是否选中:{{ isChecked }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 定义组件
Vue.component('my-component', {
model: {
prop: 'checked', // 绑定选中状态
event: 'toggle' // 自定义事件名
},
props: {
checked: Boolean,
label: String
},
template: `<input type="checkbox" :checked=checked v-on:input="$emit('toggle', $event.target.checked)">`
})
// 创建实例
var app = new Vue({
el: "#app",
data: {
isChecked: false
}
})
</script>
</body>
inheritAttrs:boolean类型,默认值:true,控制组件根元素是否自动继承父组件传入的未被声明为props的属性。
html
<body>
<!-- 父组件 -->
<div id="app">
<child-component type="text" placeholder="这是一个文本" class="date-picker-theme-dark"></child-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 子组件
Vue.component('child-component', {
inheritAttrs: true,
props: {
'message': String
},
template: '<input type="date" class="form-control">',
created() {
console.log(this)
}
})
// 创建实例
var app = new Vue({
el: "#app",
data: {},
methods: {}
})
</script>
</body>
非 prop 属性 id、title 自动挂载到子组件根元素。
html
<!--渲染DOM-->
<input type="text" id="childTex" placeholder="这是一个文本" class="form-control date-picker-theme-dark">
当指定设置inheritAttrs: false时:
javascript
<script>
// 子组件
Vue.component('child-component', {
inheritAttrs: false,
props: {
'message': String
},
template: '<input type="date" class="form-control">',
created() {
console.log(this)
}
})
// 创建实例
var app = new Vue({
el: "#app",
data: {},
methods: {}
})
</script>
非 prop 属性不再自动挂载到根元素,但仍可通过 this.$attrs 访问。
html
<!--渲染DOM-->
<input type="date" class="form-control date-picker-theme-dark">
class和style是特殊属性,即使设置inheritAttrs: false,仍会自动合并到子组件的根元素上。
comments:boolean类型,默认值:false,控制模板编译时是否保留 HTML 注释。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var app = new Vue({
el: "#app",
data:{
msg:'hello vue'
},
template: `<div><!-- 这是一个的注释 -->{{msg}}</div>`,
comments:true
})
</script>
</body>
注释被保留在 DOM 中,可在浏览器开发者工具中看到。

一般情况下,建议关闭;减少最终 DOM 的体积,提升页面加载性能;避免注释泄露业务逻辑或调试信息。
生命周期钩子选项(控制实例生命周期)
beforeCreate:Function类型,实例创建后立即调用,此时this已存在,但data、props、methods均未初始化(无法访问)。
js
<script>
new Vue({
el: "#app",
data:{
msg:'hello world'
},
beforeCreate() {
console.log(this.msg); // 输出:undefined
}
})
</script>
created:Function类型,实例创建完成后调用,实例已完成对选项的处理,意味着以下内容已被配置完毕:数据侦听、计算属性、方法、事件/侦听器的回调函数。挂载阶段还没开始,且$el属性目前尚不可用。
js
<script>
new Vue({
el: "#app",
data:{
msg:'hello world'
},
created() {
console.log(this.msg); // 输出:hello world
}
})
</script>
beforeMount:Function类型,在挂载开始之前被调用,已编译模板,但未挂载到 DOM ,$el为虚拟 DOM 节点。
js
<script>
new Vue({
el: "#app",
data:{
msg:'hello world'
},
beforeMount() {
console.log("beforeMount:", this.$el); // 虚拟 DOM(未挂载到页面)
// 输出:
// beforeMount:<div id="app"></div>
},
template: `
<div>
{{msg}}
</div>
`
})
</script>
mounted:Function类型,实例挂载完成后调用,真实 DOM 已生成,$el指向挂载后的 DOM 元素。
js
<script>
new Vue({
el: "#app",
data:{
msg:'hello world'
},
mounted() {
console.log("mounted:", this.$el); // 真实 DOM(已挂载)
// 输出:
// mounted:<div> hello world </div>
},
template: `
<div>
{{msg}}
</div>
`
})
</script>
</body>
注意 mounted 不会保证所有的子组件也都被挂载完成 。如果你希望等到整个视图都渲染完毕再执行某些操作,可以在 mounted 内部使用 vm.$nextTick:
js
mounted: function () {
this.$nextTick(function () {
// 仅在整个视图都被渲染之后才会运行的代码
})
}
beforeUpdate:Function类型,数据更新后、DOM 重新渲染前调用(data已更新,但 DOM 仍为旧值)。
js
<script>
new Vue({
el: "#app",
data: {
msg: 'hello world'
},
beforeUpdate() {
console.log("beforeUpdate:", document.querySelector("div").innerText); // 新数据(DOM 未更新)
console.log("beforeUpdate-msg:", this.msg);
// 输出:
// beforeUpdate: hello world 修改
// beforeUpdate-msg:hello vue
},
template: `
<div>
{{msg}}
<button @click="msg='hello vue'">修改</button>
</div>
`
})
</script>
updated:Function类型,DOM 重新渲染完成后调用(data和 DOM 均为最新值)。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或watcher取而代之。
js
<script>
new Vue({
el: "#app",
data:{
msg:'hello world'
},
updated() {
console.log("beforeUpdate:", document.querySelector("div").innerText);
console.log("beforeUpdate-msg:", this.msg); // 新 DOM 内容
// 输出:
// beforeUpdate: hello vue 修改
// beforeUpdate-msg: hello vue
},
template: `
<div>
{{msg}}
<button @click="msg='hello vue'">修改</button>
</div>
`
})
</script>
注意,updated 不会保证所有的子组件也都被重新渲染完毕 。如果你希望等到整个视图都渲染完毕,可以在 updated 里使用 vm.$nextTick:
js
updated: function () {
this.$nextTick(function () {
// 仅在整个视图都被重新渲染之后才会运行的代码
})
}
beforeDestroy:Function类型,实例销毁流程启动后、实际清理工作开始前调用。此时实例的data可访问 / 修改、methods可正常调用,DOM 节点仍存在于页面中(未被移除);但 Vue 已阻断数据到 DOM 的更新链路,修改数据不会触发视图重渲染,Vue 绑定的事件 / 指令的后续触发也会被逐步清理。
js
<script>
new Vue({
el: "#app",
data: {
msg: 'hello world'
},
beforeDestroy() {
this.msg = 'hello vue'
console.log("beforeDestroy", this.msg); // 正常访问,输出:beforeDestroy hello vue
this.destroyInvoke();// 正常访问
console.log('实例是否销毁:', this._isDestroyed); // 实例是否销毁:false
// 尝试手动触发Vue绑定的事件(有效)
this.$el.querySelector('button').click(); // 会触发destroySelf(事件未移除)
},
template: `
<div>
{{msg}}
<button @click="destroySelf">手动销毁</button>
</div>
`,
methods: {
destroySelf() {
// 手动调用根实例的 $destroy() 方法,触发销毁流程
this.$destroy();
},
destroyInvoke() {
console.log("销毁被调用");
}
},
})
</script>
destroyed:Function类型,实例销毁后调用(所有指令解绑、事件监听器移除、子实例销毁)。
js
<script>
new Vue({
el: "#app",
data: {
msg: 'hello world'
},
destroyed() {
console.log("destroyed", this.msg); // 正常访问,输出:beforeDestroy hello world
this.destroyInvoke(); // 正常访问
console.log('实例是否销毁:', this._isDestroyed); // 实例是否销毁:true
// 尝试手动触发Vue绑定的事件(无效)
this.$el.querySelector('button').click(); // 不会触发destroySelf(事件已移除)
},
template: `
<div>
{{msg}}
<button @click="destroySelf">手动销毁</button>
</div>
`,
methods: {
destroySelf() {
console.log("手动执行销毁")
// 手动调用根实例的 $destroy() 方法,触发销毁流程
this.$destroy();
},
destroyInvoke() {
console.log("销毁被调用");
}
},
})
</script>
通过代码this.$el.querySelector('button').click()手动触发Vue 绑定的事件,能非常直观地看出 beforeDestroy 和 destroyed 的核心区别, 因为这直接对应了Vue 绑定的事件监听是否被移除。
errorCaptured:Function类型,用于捕获当前组件及其子组件(包括后代组件) 抛出的 JavaScript 错误(同步 / 异步均可),并允许开发者自定义错误处理逻辑(如提示用户、上报错误、阻止错误传播等)。
默认情况下,如果全局的 config.errorHandler 被定义,所有的错误仍会发送它,因此这些错误仍然会向单一的分析服务的地方进行汇报。
html
<body>
<div id="app">
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component("my-component", {
template: "<div>{{ msg }}</div>",
data: function () {
return {
msg: "A custom component!"
}
},
created() {
undefined.fn(); // 调用不存在的函数,触发 TypeError
}
});
new Vue({
el: "#app",
errorCaptured(err, vm, info) {
console.log('父组件 errorCaptured 捕获到错误:');
console.log('错误信息:', err.message); // Cannot read properties of undefined (reading 'fn')
console.log('错误组件:', vm.$options.name); // 打印抛出错误的组件名 my-component
console.log('错误来源:', info); // created hook 如 "render"(渲染时错误)、"v-on handler"(事件处理函数错误)
// 返回 false,阻止错误向上传播(父组件的父组件不会捕获,全局 errorHandler 也不会触发)
return false;
}
})
</script>
</body>
一个 errorCaptured 钩子能够返回 false 以阻止错误继续向上传播 。本质上是说"这个错误已经被搞定了且应该被忽略"。它会阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler。
特殊生命周期钩子(路由 /keep-alive 相关)
如果使用 vue-router 或 keep-alive 组件,会额外触发以下钩子:
activated:Function类型,组件被 keep-alive 缓存,缓存组件被激活时(如从其他路由切回)。deactivated:Function类型,组件被 keep-alive 缓存,缓存组件被失活时(如切到其他路由)。beforeRouteEnter:vue-router 路由组件,路由进入当前组件前调用(此时组件实例未创建,this为undefined)。beforeRouteUpdate:vue-router 路由组件,路由参数变化但组件复用(如/user/1→/user/2)时调用。beforeRouteLeave:vue-router 路由组件,路由离开当前组件前调用。
实例属性
Vue 2.0 的实例属性(也常被称为实例属性 / 实例 API )是挂载在 new Vue() 创建的实例对象上的内置属性,主要用于访问实例的核心数据、DOM 元素、父 / 子实例等,大部分以 $ 开头(区分自定义属性)。
数据相关属性
vm.$data:Object类型,Vue 实例观察的数据对象。Vue 实例代理了对其data对象实例的访问。
js
<script>
// 创建实例
var vm = new Vue({
el: "#app",
data: {
msg: 'hello vue'
},
mounted(){
console.log(this.$data) // Output: {msg : "hello vue"}
console.log(this.msg) // Output: "hello vue"
console.log(this.$data.msg === this.msg) // Output:true
}
})
console.log(vm.$data) // Output: {msg : "hello vue"}
console.log(vm.msg) // Output: "hello vue"
console.log(vm.$data.msg === vm.msg) // Output:true
</script>
不推荐用 vm.$data.xx 修改数据,Vue 实例会自动将 $data 中的所有属性代理到实例本身,另一方面保证了代码可读性 / 规范性。
javascript
// 推荐(简洁)
vm.name = '新值';
// 不推荐(冗余,多写 $data 无意义)
vm.$data.name = '新值';
vm.$props:Object类型,只读 ,访问组件接收的所有props(响应式)。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component title="hello,Vue"content="Vue is a progressive framework for building user interfaces"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
props: ['title', 'content'],
template: '<div><h1>{{title}}</h1><br/><h5>{{content}}</h5></div>',
mounted: function () {
console.log(this.$props) // Output: {'title':'xxx','content': 'xxx'}
console.log(this.$props.title === this.title) // Output: true
this.$props.title = 'xxx'; // 报错,无法修改
}
})
// 创建实例
var vm = new Vue({
el: "#app"
})
</script>
</body>
vm.$el:Element类型,访问组件实例挂载的根 DOM 元素。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component title="hello,Vue"
content="Vue is a progressive framework for building user interfaces"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
props: ['title', 'content'],
template: '<div><h1>{{title}}</h1><br/><h5>{{content}}</h5></div>',
mounted: function () {
console.log(this.$el) // 根节点DOM内容
this.$el.style.color = 'red'; // 设置样式
this.$el.setAttribute('data-custom', 'value'); // 添加自定义属性
this.$el.classList.add('active'); // 添加类
this.$el.addEventListener('click', this.handleClick); // 手动绑定
const firstChild = this.$el.querySelector('.child-class'); // 获取第一个匹配的子元素
}
})
// 创建实例
var vm = new Vue({
el: "#app"
})
</script>
</body>
vm.$options:Object类型,用于当前 Vue 实例的初始化选项。需要在选项中包含自定义属性时会有用处。
js
<script>
// 创建实例
var vm = new Vue({
el: "#app",
data: {
msg: 'hello,vue'
},
mounted: function () {
// 访问 $options(非原始选项)
console.log(this.$options.customOption) // Output: '根组件自定义选项'
this.$options.customOption = 'hello,vue';
// 访问 $options(原始选项),调用methods 的 test 方法
this.$options.methods.test.call(this)
},
methods: {
test() {
console.log('test')
}
},
// 自定义选项(通过 $options 访问)
customOption: '根组件自定义选项',
})
// 全局根实例
console.log(vm.$options.customOption) // Output: hello,vue
</script>
this.$options 的核心能力是「访问组件的所有原始选项 (data/props/methods 等)」,自定义选项只是其使用场景之一,通过this.$options进行重置data数据、动态校验 props、动态调用方法、备份 / 恢复方法等。
vm.$set( target, propertyName/index, value ):全局Vue.set的别名,修改对象属性内容。
html
<body>
<!-- 父组件 -->
<div id="app">
<span>姓名:</span>
<p>{{user.name}}</p>
<span>爱好:</span>
<p v-for="item in user.hobby">{{item}}</p>
<button @click="updateMessage">变更按钮</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var vm = new Vue({
el: "#app",
data: {
user: {
name: '张三',
hobby: ['打球', '阅读', '装逼']
}
},
methods: {
updateMessage() {
// 修改对象属性元素
this.$set(this.user, 'name', '李四')
// 修改数组下标元素
this.$set(this.user.hobby, 2, '听音乐')
}
}
});
</script>
</body>
vm.$delete( target, propertyName/index ):全局Vue.delete的别名用于删除响应式对象属性并触发视图更新。
html
<body>
<div id="app">
<span>姓名:</span>
<p>{{user.name}}</p>
<span>年龄</span>
<p>{{user.age}}</p>
<span>爱好:</span>
<p v-for="item in user.hobby">{{item}}</p>
<button @click="delAge">删除按钮</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
// 响应式对象(非 Vue 实例、非根数据对象)
user: {
name: '张三',
age: 19,
hobby: ['打球', '阅读', '装逼']
}
},
methods: {
delAge() {
// 方式1:组件内用 this.$delete(推荐)
this.$delete(this.user, 'age')
// 删除数组索引为1的元素
this.$delete(this.user.hobby, 1)
// 等价于(推荐数组方法)
this.user.hobby.splice(1, 1)
}
}
})
</script>
</body>
vm.$watch( expOrFn, callback, [options] ):手动创建侦听器,观察 Vue 实例上的一个表达式或者一个函数计算结果的变化。回调函数得到的参数为新值和旧值。
html
<body>
<!-- 父组件 -->
<div id="app">
<button @click="c.d.e++">点击+1</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var vm = new Vue({
el: "#app",
data: {
a: 1,
b: 2,
c: {
d: {
e: 5
}
}
}
});
// 监听属性
vm.$watch('a', function (newValue, oldValue) {
console.log(newValue, oldValue)
})
// 深度监听
vm.$watch('b', {
handler: function (newValue, oldValue) { console.log(newValue, oldValue) },
deep: true, // 深度监听
immediate: true // 监听初始化时立即执行
})
// 嵌套监听
vm.$watch('c.d.e', function (newValue, oldValue) { console.log(newValue, oldValue) })
</script>
</body>
在option中使用this.$watch也可以。
DOM / 模板相关属性
vm.$slots:{ [name: string]: ?Array<VNode> }类型,用于访问组件的插槽内容。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component>
<!-- 默认插槽 -->
<p>这是默认插槽的内容</p>
<!-- 具名插槽:header -->
<template slot="header">
<div class="header-slot">这是header插槽的内容</div>
</template>
<!-- 具名插槽:footer -->
<template slot="footer">
<div class="footer-slot">这是footer插槽的内容</div>
</template>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
template: `<div>子组件模板<slot></slot><slot name='header'></slot><slot name='footer'></slot></div>`,
mounted(){
// 获取插槽
console.log(this.$slots) // {default: Array(3), header: Array(1), footer: Array(1)}
// 具名插槽
console.log(this.$slots.header) // [VNode]
console.log(this.$slots.footer) // [VNode]
// 默认插槽
console.log(this.$slots.default) // [VNode, VNode, VNode]
}
})
// 创建实例
var vm = new Vue({
el: "#app"
})
</script>
</body>
本质是 Vue 内部维护的VNode 数组,语法上可修改但绝对不建议手动篡改------ 这会破坏插槽的单向数据流、导致视图更新异常,甚至引发内存泄漏或渲染错误。
vm.$scopedSlots:{ [name: string]: props => Array<VNode> | undefined }类型,用于访问父组件传入的作用域插槽渲染函数(父组件的插槽内容会被编译为函数,接收子组件传递的props)。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component>
<!-- 作用域插槽 -->
<template slot="scope" slot-scope="item">
<h1>{{item.msg}}</h1>
</template>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
// 判断$scopedSlots 是否存在,防止多余的空 DOM 节点,让 DOM 结构更干净。
template: `<div>子组件模板<div v-if='$scopedSlots.scope'><slot name='scope' :msg=msg></slot></div></div>`,
data() {
return {
msg: 'hello world'
}
},
mounted() {
// 打印 $scopedSlots 结构:键是插槽名,值是渲染函数
console.log('$scopedSlots 对象:', this.$scopedSlots)
// 调用渲染函数(传入 props),获取 VNode 数组
const slotVNodes = this.$scopedSlots.scope({
msg: 'hello vue'
})
console.log('作用域插槽 VNode 数组:', slotVNodes)
// 若插槽未传入,$scopedSlots.xxx 为 undefined
console.log('未传入的 address 插槽:', this.$scopedSlots.address) // undefined
}
})
// 创建实例
var vm = new Vue({
el: "#app"
})
</script>
</body>
Vue2 中,$scopedSlots 是作用域插槽的唯一脚本访问方式。
vm.$refs:Object类型,访问模板中通过ref标记的 DOM 元素 / 子组件实例。
html
<body>
<!-- 父组件 -->
<div id="app">
<!-- 给 DOM 元素加 ref -->
<input ref="inputBox" type="text" placeholder="请输入内容" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var vm = new Vue({
el: "#app",
mounted() {
const inputBox = this.$refs.inputBox;
// 获取 DOM 元素
console.log(inputBox); // Output <input type="text" placeholder="请输入内容">
inputBox.focus(); // 让输入框获取焦点
inputBox.value = "通过 $refs 赋值"; // 修改输入框内容
}
})
</script>
</body>
不建议手动修改 $refs,因为这会破坏 Vue 内部对 ref 的管理逻辑,导致不可预期的问题。
实例关系相关属性
vm.$parent:Vue instance类型,访问当前组件的父实例(慎用,易造成耦合)。
js
<script>
Vue.component('my-component', {
template:`<div>子组件模板</div>`,
mounted: function () {
// 调用父组件方法
this.$parent.hello();
// 调用父组件数据
console.log(this.$parent.msg);
// 写入父组件数据
this.$parent.msg = 'hello vue';
console.log(this.$parent.msg);
}
})
// 创建实例
var vm = new Vue({
el: "#app",
data:{
msg:'hello'
},
methods:{
hello(){
console.log('hello vue')
}
}
})
</script>
vm.$parent指向当前组件的直接父组件实例(层级相关) ,禁止在业务代码中直接修改 $parent 数据,必须遵循「单向数据流」(子→父通过 $emit)
vm.$root:Vue instance类型,访问 Vue 应用的根实例(所有组件共享)。
js
<script>
Vue.component('my-component', {
template:`<div>子组件模板</div>`,
mounted: function () {
// 调用根组件方法
this.$root.hello();
// 调用根组件数据
console.log(this.$root.msg);
// 写入根组件数据
this.$root.msg = 'hello vue';
console.log(this.$root.msg);
}
})
// 创建实例
var vm = new Vue({
el: "#app",
data:{
msg:'hello'
},
methods:{
hello(){
console.log('hello vue')
}
}
})
</script>
vm.$root指向整个组件树的根 Vue 实例(唯一) ,禁止在业务代码中直接修改 $root 数据,仅允许「只读访问全局配置 」或「通过全局事件触发根实例自己修改」。
vm.$children:Array<Vue instance>类型,访问当前组件的直接子组件数组(无序,不保证顺序)。
js
<script>
Vue.component('my-component', {
template: `<div>子组件模板</div>`,
data() {
return{
msg: 'hello'
}
},
methods: {
hello() {
console.log('hello vue')
}
}
})
// 创建实例
var vm = new Vue({
el: "#app",
mounted: function () {
console.log(this.$children)
// 调用第一个子组件方法
this.$children[0].hello();
// 调用第一个子组件组件数据
console.log(this.$children[0].msg);
// 写入第一个子组件组件数据
this.$children[0].msg = 'hello vue';
console.log(this.$children[0].msg);
}
})
</script>
vm.$children 语法上可修改,但绝对不要手动赋值,会破坏 Vue 内部的组件管理
vm.$attrs:{ [key: string]: string }类型,只读 ,访问父组件传递的非prop属性(包括class/style以外的普通属性、事件监听器等),核心作用是实现属性透传。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component title="hello,Vue" content="Vue is a progressive framework for building user interfaces"
class="my-component" @click="handleClick" not-defined="没有定义"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
props: ['title', 'content'],
template: `<div>子组件模板</div>`,
data() {
return {
msg: 'hello world'
}
},
mounted() {
console.log(this.$attrs) // Output: {not-defined: '没有定义'}
}
})
// 创建实例
var vm = new Vue({
el: "#app",
methods: {
handleClick() {
console.log('按钮被点击')
}
}
})
</script>
</body>
vm.$listeners:{ [key: string]: Function | Array<Function> }类型,只读 ,包含了父组件传递给当前组件的所有自定义事件监听器(不包含.native修饰符的原生事件),核心作用是透传事件。
html
<body>
<!-- 父组件 -->
<div id="app">
<my-component title="hello,Vue" content="Vue is a progressive framework for building user interfaces"
class="my-component" @click="handleClick" not-defined="没有定义"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
props: ['title', 'content'],
template: `<div>子组件模板</div>`,
data() {
return {
msg: 'hello world'
}
},
mounted() {
console.log(this.$listeners) // Output: {click: ƒ}
}
})
// 创建实例
var vm = new Vue({
el: "#app",
methods: {
handleClick() {
console.log('按钮被点击')
}
}
})
</script>
</body>
事件属性
vm.$on( event, callback ):监听当前实例上的自定义事件。
js
<script>
const vm = new Vue({
el: "#app"
})
// 步骤1:使用 $on 监听自定义事件(事件名:'sayHello')
vm.$on('sayHello', (name) => {
this.message = `你好,${name}!`
console.log(this.message) // 触发时输出:你好,张三!
})
// 步骤2:使用 $emit 触发这个事件(传参给回调函数)
vm.$emit('sayHello', '张三')
</script>
vm.$once( event, callback ):监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。
js
<script>
const vm = new Vue({
el: "#app"
})
// 步骤1:使用 $once 监听一次自定义事件(事件名:'sayHello')
vm.$once('sayHello', (name) => {
this.message = `你好,${name}!`
console.log(this.message) // 触发时输出:你好,张三!
})
// 步骤2:使用 $emit 触发这个事件(传参给回调函数)
vm.$emit('sayHello', '张三')
vm.$emit('sayHello', '李四') // 无输出
</script>
-
vm.$off( [event, callback] ):移除自定义事件监听器。-
如果没有提供参数,则移除所有的事件监听器;
-
如果只提供了事件,则移除该事件所有的监听器;
-
如果同时提供了事件与回调,则只移除这个回调的监听器。
-
js
<script>
const vm = new Vue({
el: "#app"
})
const callback = (name) => {
this.message = `你好,${name}!`
console.log(this.message) // 触发时输出:你好,张三!
}
// 步骤1:使用 $on 监听自定义事件(事件名:'sayHello')
vm.$on('sayHello', callback)
// 步骤2:使用 $emit 触发这个事件(传参给回调函数)
vm.$emit('sayHello', '张三')
// 移除方式一:不传参数时
vm.$off(); // 移除所有事件的所有监听器
vm.$emit('sayHello', '张三') // 不会触发事件
// 移除方式二:传事件名时
vm.$off('sayHello'); // 移除所有监听器
vm.$emit('sayHello', '张三') // 不会触发事件
// 移除方式三:传事件名和回调时
vm.$off('sayHello', callback); // 移除特定回调
vm.$emit('sayHello', '张三') // 不会触发事件
</script>
vm.$emit( eventName, [...args] ):触发当前实例上的事件。附加参数都会传给监听器回调。常用于子组件向父组件通信,支持传递多个参数。
html
<body>
<div id="app">
<my-component @handle-click="handleClick"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
Vue.component('my-component', {
template: '<button @click="send">点击发送</button>',
methods: {
send() {
this.$emit('handle-click', 'hello', 'world')
}
}
})
const vm = new Vue({
el: "#app",
methods: {
handleClick(msg, msg2) {
console.log(msg + ',' + msg2) // Output: hello,world
}
}
})
</script>
</body>
生命周期属性
vm.$mount( [elementOrSelector] ):如果 Vue 实例在实例化时没有收到el选项,则它处于"未挂载"状态,没有关联的 DOM 元素。可以使用vm.$mount()手动地挂载一个未挂载的实例。
html
<body>
<div id="app">
{{message}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
var vm = new Vue({
data: {
message: 'hello vue'
}
})
vm.$mount('#app'); // 挂载到 id 为 app 的元素
</script>
</body>
vm.$forceUpdate():强制组件重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
html
<body>
<div id="app">
{{nonReactiveData.message}}
<button @click="forceChange">强制更新</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
// 非响应式数据(未在 data 中声明)
nonReactiveData: {}
},
methods: {
forceChange() {
this.nonReactiveData.message = 'hello vue'
this.$forceUpdate();
}
}
})
</script>
</body>
vm.$nextTick( [callback] ):在下次 DOM 更新循环结束后执行回调。
html
<body>
<div id="app">
<p ref="content">{{message}}</p>
<button @click="updateMessage">更新文本</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'hello vue'
},
methods:{
updateMessage(){
// 1. 修改数据
this.message = 'hello vue2'
// 2. 使用 nextTick,DOM 更新后执行回调
this.$nextTick(()=>{
console.log(this.$refs.content.textContent)
})
}
}
})
</script>
</body>
它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
vm.$destroy():完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。触发beforeDestroy和destroyed的钩子。
html
<body>
<div id="app">
{{message}}
<button @click="forceDestroy">强制销毁</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'hello world'
},
methods: {
forceDestroy() {
this.$destroy();
this.message='已被强制销毁'; // 不再生效
}
},
beforeDestroy() {
console.log('实例即将销毁');
},
destroyed() {
console.log('实例已销毁');
}
})
</script>
</body>
环境检测属性
vm.$isServer:boolean类型,只读 ,当前 Vue 实例是否运行于服务器。
js
<script>
// 创建实例
var vm = new Vue({
el: "#app",
mounted() {
console.log(this.$isServer); // Output: false
}
})
</script>
$isServer 的值是 Vue 根据执行环境自动判定的,任何场景下都不要尝试修改 ------ 修改它不会改变实际运行环境,只会让代码逻辑与真实环境脱节,引发不可修复的错误。
指令
Vue 2.0 提供了丰富的内置指令,用于快速实现视图与数据的绑定、DOM 操作、事件处理等核心功能。
数据绑定指令
v-text:更新元素的textContent(纯文本),替代插值语法{``{ }}。
html
<body>
<!-- 父组件 -->
<div id="app">
<p v-text="message"></p>
<!-- 等价于 <p>{{ message }}</p> -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var vm = new Vue({
el: "#app",
data: {
message: 'hello,vue'
}
})
</script>
</body>
会覆盖元素原有内容,且不会解析 HTML。
v-html:更新元素的innerHTML,可渲染 HTML 字符串。
html
<body>
<!-- 父组件 -->
<div id="app">
<div v-html="htmlContent"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var vm = new Vue({
el: "#app",
data: {
htmlContent: '<h1>hello,vue</h1>'
}
})
</script>
</body>
存在 XSS 风险,仅用于可信内容,切勿用于用户输入。
v-bind:动态绑定 HTML 特性(如属性、样式、class ),可简写为:。
html
<body>
<!-- 父组件 -->
<div id="app">
<!-- 绑定普通属性 -->
<img v-bind:src="imgUrl" />
<img :src="imgUrl" /> <!-- 简写 -->
<!-- 绑定class -->
<div :class="{ active: isActive, 'text-red': hasError }">绑定class</div>
<!-- 绑定style -->
<div :style="{ color: textColor, fontSize: '14px' }">绑定style</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var vm = new Vue({
el: "#app",
data: {
imgUrl: 'https://img0.baidu.com/it/u=694429811,492128807&fm=253&app=138&f=JPEG?w=500&h=889',
isActive: true,
textColor: 'blue'
}
})
</script>
<style>
.active {
background-color: aqua;
}
</style>
</body>
v-model:实现表单元素的双向数据绑定,仅适用于表单控件。
html
<body>
<!-- 父组件 -->
<div id="app">
<input v-model="username" />
<input v-model.lazy="email" />
<input v-model.number="age" type="number" />
<textarea v-model.trim="content"></textarea>
<select v-model="selected">
<option value="1">选项1</option>
</select>
<p>{{username}}-{{email}}--{{age}}--{{content}}--{{selected}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// 创建实例
var vm = new Vue({
el: "#app",
data: {
username: '张三',
email: '8888@126.com',
age: 18,
selected: 1
}
})
</script>
</body>
条件渲染指令
v-if:根据表达式的布尔值条件性渲染元素(销毁 / 重建 DOM)。v-else:配合v-if使用,作为 "else块",无独立表达式。v-else-if:配合v-if使用,作为 "else if块",可链式调用。v-show:根据表达式的布尔值显示 / 隐藏元素(通过display: none控制)。
具体可参考条件渲染指令。
列表渲染指令
v-for:基于数组 / 对象循环渲染元素。
具体可参考列表渲染指令
事件处理指令
v-on:绑定事件监听器,可简写为@。
具体可参考事件绑定指令。
插槽指令
v-slot:用于定义具名插槽和作用域插槽,是 Vue 组件插槽的标准化语法(Vue 2.6+ 推荐用法,2.6 之前的slot/slot-scope已被废弃),核心解决 "组件内部向外部传递数据"+"外部自定义组件内部结构" 的问题。
具体可参考作用域插槽
其他常用指令
v-cloak:解决插值表达式 "闪烁问题"(页面加载时先显示{``{ }}再渲染内容)。v-once:元素 / 组件仅渲染一次,后续数据更新不再重新渲染(静态内容优化)。v-pre:跳过元素及其子元素的编译过程,直接显示原始内容(提升静态内容渲染性能)。
具体可参考其他指令。
特殊 attribute
ref:给元素 / 组件注册引用信息,通过this.$refs访问 DOM 元素或组件实例。
具体可参考访问子组件实例。
key:用于标识节点的唯一性,帮助 Vue 的虚拟 DOM 算法精准判断节点是否需要复用 / 重新渲染,是列表渲染(v-for)的核心优化属性。
具体可参考列表渲染指令。
is:动态组件渲染、解决原生 HTML 标签的解析限制(如<table>内嵌套组件)。具体参考动态组件。slot:用于标记往哪个具名插槽中插入子组件内容。废弃 ,推荐 2.6.0 新增的v-slot,具体参考插槽。slot-scope:用于将元素或组件表示为作用域插槽。废弃 ,推荐 2.6.0 新增的v-slot,具体参考插槽。scope:用于表示一个作为带作用域的插槽的<template>元素,它在 2.5.0+ 中被slot-scope替代。移除 ,推荐 2.6.0 新增的v-slot。
内置的组件
component:根据绑定的is属性动态渲染不同组件,实现组件的动态切换。具体参考动态组件。keep-alive:缓存包裹的组件实例,避免组件反复创建 / 销毁,保留组件状态(如表单输入、滚动位置)。具体参考动态组件。transition:为单个元素 / 组件的插入 / 更新 / 移除添加过渡动画(基于 CSS 过渡 / 动画 或 JS 钩子)。具体参考过渡 & 动画。transition-group:为v-for渲染的列表元素添加过渡动画(支持元素的插入、移除、移动)。具体参考过渡 & 动画。
VNode 接口
VNode (Virtual Node ,虚拟节点) 是对真实 DOM 节点的抽象描述,是 Vue 虚拟 DOM 体系的核心数据结构。VNode 接口(本质是一个 JavaScript 对象规范)定义了虚拟节点的属性和结构,Vue 通过操作 VNode 来实现 DOM 的高效更新(对比新旧 VNode 差异,仅更新变化部分)。
javascript
class VNode {
constructor (
tag?: string, // 标签名(如'div'/'component',组件为组件选项/名称)
data?: VNodeData, // 节点数据(属性、指令、样式等)
children?: ?Array<VNode>, // 子虚拟节点数组
text?: string, // 文本内容(文本节点专用)
elm?: Node, // 对应的真实 DOM 元素(渲染后赋值)
context?: Component, // 所属的组件实例
componentOptions?: VNodeComponentOptions, // 组件 VNode 专用配置
key?: string | number // 节点唯一标识(对应 :key)
componentInstance?: Component | void // 组件 VNode 对应的组件实例(仅组件 VNode 有值)
parent?: VNode | void // 父 VNode(用于反向查找节点层级)
isComment?: boolean // 是否为注释节点(如 <!-- 注释 -->)
isStatic?: boolean // 是否为静态节点(由 v-once 或纯静态内容生成,diff 时跳过对比)
isCloned?: boolean // 是否为克隆节点(如 v-for 复用节点时的克隆标记)
isOnce?: boolean // 是否为 v-once 渲染的节点(仅渲染一次)
) {
// 赋值逻辑...
}
}
VNodeData 是 VNode data 属性的类型规范,包含节点的所有动态绑定信息,核心字段:
javascript
interface VNodeData {
key?: string | number;
props?: { [key: string]: any }; // 组件 props
attrs?: { [key: string]: any }; // 普通 HTML 属性(如 id、class)
class?: { [key: string]: boolean } | string | Array<string>; // 类名
style?: { [key: string]: any } | Array<{ [key: string]: any }>; // 样式
on?: { [key: string]: Function | Array<Function> }; // 事件绑定(v-on)
nativeOn?: { [key: string]: Function | Array<Function> }; // 原生事件(组件上的 .native)
dirs?: Array<Directive>; // 指令(如 v-if/v-for/v-model)
slot?: string; // 插槽名
scopedSlots?: { [key: string]: ScopedSlot }; // 作用域插槽
ref?: string; // ref 名称
refInFor?: boolean; // 是否在 v-for 中使用 ref
// 其他:hook(生命周期钩子)、transition(过渡配置)等
}
Vue 2 提供 createElement(或 h 函数)来手动创建符合接口规范的 VNode ,这也是渲染函数(render)的核心:
javascript
// 渲染函数中创建 VNode
export default {
render(h) { // h 是 createElement 的别名,等价于 Vue.createElement
// 参数:tag, data, children/text
return h(
'div', // tag(元素/组件)
{
key: 'root',
attrs: { id: 'app' },
class: { active: true },
on: { click: this.handleClick }
}, // VNodeData
[
h('span', { key: 'text' }, 'Hello VNode'), // 子 VNode
h(MyComponent, { key: 'comp', props: { msg: 'hi' } }) // 组件 VNode
] // children
)
},
methods: {
handleClick() { /* ... */ }
}
}
服务端渲染
服务端渲染(Server-Side Rendering ,SSR ) 是指在服务器端将页面的模板和数据组装成完整的 HTML 字符串,再发送给浏览器的渲染方式。浏览器接收到 HTML 后,直接解析渲染出页面,无需等待前端 JavaScript 加载执行后再生成 DOM。
与之相对的是客户端渲染(Client-Side Rendering ,CSR )------ 浏览器先加载空白 HTML 和 JavaScript 文件,再由 JS 在客户端请求数据、生成 DOM 并渲染页面。