Vue 实例
创建一个 Vue 实例
每个 Vue 应用都是通过用 Vue
函数创建一个新的 Vue 实例开始的:
var vm = new Vue({// 选项
})
Vue 设计受到了 MVVM模型启发,所以文档常用 vm
(ViewModel 的缩写) 这个变量名表示 Vue 实例
现在我给出一个标准 HTML 文档结构
这样我们的示例可以方便放入
<!DOCTYPE html> <!-- 声明文档类型为 HTML5 -->
<html lang="zh-CN"> <!-- 根元素,定义页面语言 -->
<head><!-- 元数据区(用户不可见) --><meta charset="UTF-8"> <!-- 字符编码 --><meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 响应式必备 --><title>页面标题</title> <!-- 浏览器标签页标题 --><link rel="stylesheet" href="styles.css"> <!-- 引入外部 CSS --><script src="script.js" defer></script> <!-- 引入 JavaScript(defer 延迟加载) -->
</head>
<body><!-- 用户可见内容区 --><header>网站头部(LOGO/导航)</header><nav><a href="#home">首页</a><a href="#news">新闻</a></nav><main> <!-- 页面核心内容 --><article> <!-- 独立内容区块(如博客文章) --><h1>主标题</h1><section> <!-- 内容分组 --><h2>子标题</h2><p>段落文本</p><img src="image.jpg" alt="图片描述"></section></article><aside>侧边栏(广告/相关链接)</aside></main><footer>页脚(版权/联系方式)</footer>
</body>
</html>
解释一下 head 中的元数据,元数据 = 数据的信息说明书,也就是用来描述其他数据特征的数据,类似商品标签
我们再给出一个类似的思维导图,这个思维导图中,body 里面还写了 script
内容与上面代码不完全一致,但意思表达出来了
当我们创建一个 Vue 实例的时候,可以传入一个选项对象
比如这个例子里面的对象
new Vue({// 选项对象el: '#app', // 指定 Vue 实例挂载的 DOM 元素data: { // 存储数据message: 'Hello Vue!'},methods: { // 定义方法greet() {console.log('Hello World!');}},computed: { // 定义计算属性reversedMessage() {return this.message.split('').reverse().join('');}},mounted() { // 生命周期钩子console.log('Vue instance mounted');}
});
而使用这些选项的目的是为了创建我们想要的行为
当然文档中有完整的选项列表, API 文档
一个 Vue 应用由
- 一个通过
new Vue
创建的根 Vue 实例 - 以及可选的嵌套的、可复用的组件树
组成
举个栗子🌰:
一个 todo 应用的组件树可以是这样
根实例
└─ TodoList├─ TodoItem│ ├─ TodoButtonDelete│ └─ TodoButtonEdit└─ TodoListFooter├─ TodosButtonClear└─ TodoListStatistics
根实例通过 props 传递 todos 数据给 TodoList
TodoItem 则循环传递单个 todo 数据
TodoButtonDelete、TodoButtonEdit 则通过事件 emit 触发
TodoListFooter 内可以通过 props 接收统计信息
总之,所有的 Vue 组件都是 Vue 实例,并且接受相同的选项对象 (一些根实例特有的选项除外)
数据与方法
当一个 Vue 实例被创建时,它将 data
对象中的所有的 property 加入到 Vue 的响应式系统中
解释一下,在 JS 中,对象是由 { key: value }
组成的
每个 key 就是对象的一个 property(属性)
当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值
// 我们的数据对象
var data = { a: 1 }// 该对象被加入到一个 Vue 实例中
var vm = new Vue({data: data
})
当这些数据改变时,视图会进行重渲染
注意:只有当实例创建时就已经存在 data
中的 property 才是响应式的
比如这时候我们在加入一个新的 property
vm.b = 'hi'
那么 b
的改动不会触发任何的视图更新
所有如果我们后面还需要用到 property,一开始它是空或者不存在,那么我们可以设置一些初始值
例如:
data: {newTodoText: '',visitCount: 0,hideCompletedTodos: false,todos: [],error: null
}
不过还有方法可以阻值修改现有的 property,那就是 Object.freeze()
意味着响应系统无法再追踪变化
除了数据 property,Vue 实例还暴露了一些有用的实例 property 与方法
其实就是内置的 property,Vue 自动挂载到实例上的工具属性和方法
它们都有前缀 $
,以便与用户定义的 property 区分开来
比如说:
var data = { a: 1 }
var vm = new Vue({el: '#example',data: data
})
// 访问 data 对象
vm.$data === data // => true
// 访问根 DOM 元素
vm.$el === document.getElementById('example') // => true// $watch 是一个实例方法,监听数据变化
vm.$watch('a', function (newValue, oldValue) {// 这个回调将在 `vm.a` 改变后调用
})
API 参考,可以通过链接查阅到完整的实例 property 和方法的列表
实例生命周期钩子
每个 Vue 实例在被创建时都要经过一系列的初始化过程
例如:
- 需要设置数据监听
- 编译模板
- 将实例挂载到 DOM 并在数据变化时更新 DOM 等
同时在这个过程中也会运行一些叫做生命周期钩子的函数
这样我们可以在不同阶段添加自己的代码
比如:created
钩子可以用来在一个实例被创建之后执行代码
还有一些其他钩子,在实例生命周期的不同阶段被调用
如: mounted
、updated
和 destroyed
生命周期钩子的 this
上下文指向调用它的 Vue 实例
❗注意
不要在选项 property 或回调上使用箭头函数
比如
created: () => console.log(this.a)
或vm.$watch('a', newValue => this.myMethod())
因为箭头函数并没有
this
,this
会作为变量一直向上级词法作用域查找,直至找到为止,经常导致Uncaught TypeError: Cannot read property of undefined
或Uncaught TypeError: this.myMethod is not a function
之类的错误
模板编译
我这里简单讲解一下模板编译
模板编译通常分为三个核心阶段,分别是解析、优化和代码生成
- 解析
- 步骤
- 使用 HTML 解析器分析模板结构
- 识别 Vue 特有的语法(指令、插值、组件标签等)
- 生成 抽象语法树(Abstract Syntax Tree, AST)
- 步骤
举个例子,解析 <div>{{ message }}</div>
输出示例:
{type: 1, // 元素节点tag: 'div',children: [{type: 2, // 文本节点expression: '_s(message)' // 插值表达式转换后的代码}]
}
-
优化
- 通常会遍历 AST(抽象语法树),标记静态节点
- 通过复用静态节点可以减少内存消耗
-
代码生成
-
输入:优化后的 AST
-
过程:
- 将 AST 转换为可执行的 JS 代码
- 生成
render
函数字符串
-
输出示例:
function render() {return _c('div', [_v(_s(message))]) }
-
编译后,生成的 render
函数会在以下场景执行:
- 首次渲染:生成虚拟 DOM → 映射为真实 DOM
- 数据变更:重新执行
render
生成新虚拟 DOM → Diff 算法比对差异 → 更新真实 DOM
生命周期图示
下面就来到了面试官爱问的问题,Vue 的生命周期是怎么样的
下图展示了实例的生命周期
英文的看着有点累,再上个中文的
END
本文主要介绍 Vue 实例,包括如何创建一个 Vue 实例、实例中的数据和方法、实例生命周期钩子以及生命周期的图示,实例的数据和方法主要涉及数据 data 对象,在实例生命周期钩子中简单讲解了模板编译