从头学习Vue:持续更新中...
- Level 1 Vue的基础
- Level 2 Vue的组件化构建
-
- 组件树
- 子组件和父组件的通信
- Level 3 Vue和CSS
- Level 4 Vue的原理
-
- MVVM模型
- vue实例的创建和data属性
- Vue的计算属性、方法和侦听器原理
-
- 计算属性
- Vue的生命周期
2021年4月1日更新
Level 1 Vue的基础
数据和DOM(不仅是文本、还有属性和DOM结构)建立了关联,所有东西都是响应式的!即数据绑定以及双向数据绑定。
- 如何创建vue实例
var vm = new Vue({
// 选项
data:{},//数据属性
computed:{},//计算属性
methods: {},
...
})
-
知道以下指令如何使用以及区别。
v-bind、v-model、v-on
v-if、v-for、v-show
- Vue模版语法:建议看官方文档
Level 1的水平:你现在知道了vue框架实现了数据绑定,甚至也知道了这个数据绑定的原理是数据劫持加上发布者订阅者模式,就可以完成一个利用Vue框架实现的双向数据绑定的网站了(我自己本科课程设计的项目,其实只用到了数据双向绑定)
虽然但是,还是建议先了解完Vue的原理再做项目,不然出现bug很麻烦的,不知道原理的话,都不知道哪出错了。而且,如果不了解原理就做项目的话,会让自己有一种自己就是会Vue了的错觉,然后面试官就会让你看清现实的。。。
Level 2 Vue的组件化构建
使用小型、独立和可复用的组件来构建大型应用。在一个大型应用中,有必要将整个应用程序划分为组件,以使开发更易管理。
-
注册组件
一个组件实际上是Vue实例,可以预定义选项(注意所有的组件本质上都是一个vue实例)。
// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
template: '<li>这是个待办项</li>'
})
var app = new Vue(...)
组件树
一个 todo 应用的组件树可以是这样的:
根实例
└─ TodoList
├─ TodoItem
│ ├─ TodoButtonDelete
│ └─ TodoButtonEdit
└─ TodoListFooter
├─ TodosButtonClear
└─ TodoListStatistics
子组件和父组件的通信
- 父组件传递到子组件:使用prop属性。子单元通过 prop 接口与父单元进行了良好的解耦。在子组件中提供更复杂的模版和逻辑不会影响到父组件。
示例解释:todo-item是一个子组件,它的父组件是app7,现在想把父组件中的groceryList传递给子组件显示出来如何实现呢?,那就是在子组件里加一个 props 属性 todo,将这个属性用v-bind绑定起来,当子组件要求遍历groceryList时,v-bind找到todo属性,将groceryList中的item放入,于是子组件就获得了groceryList数据。
//这是一个子组件
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
//这是父组件
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
<div id="app-7">
<ol>
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
- 子组件传递到父组件:利用$emit方法。
Level 3 Vue和CSS
Class 与 Style 绑定
Level 4 Vue的原理
MVVM模型
-
MVVM、MVC、MVP的对比
这篇博客的介绍简单直接,可以参考。
vue实例的创建和data属性
对应的问题有:
- 当一个vue实例被创建时,发生了什么?
- 为什么我们可以用this.xxx,而不用用this.$data.xxx?
面试官会用类似这样的问题来考察你对Vue框架原理的认识,不是知道一个数据劫持+发布者订阅者模式就能回答的。
1. 当一个vue实例被创建时,发生了什么?
- 当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
- 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等,这就涉及到了Vue的生命周期。
2. 为什么我们可以用this.xxx,而不用用this.data.xxx?
这是面试腾讯的时候面试官问我的一个问题,这里鞭尸一下当时的对话。。。
完全没看过源代码,开发者文档也没仔细看的我当时懵了一会儿,回答说是因为this的指向(不确定的语气)。 然后面试官问this指向什么呢?我说的是vue的根实例。
面试官:“this是会一直指向根实例吗?”
我:“不是的,可以改变this的指向。”
面试官:“怎么改变呢?”
我:“用call、apply、bind方法。”
后面面试官就开始问我这三个方法的区别了。
我一开始看到的是这篇文章,但评论有反对意见
这篇文章说的是:
当一个Vue实例被创建时,this指向Vue实例,然后赋值给了vm,vm作为参数向下传递。
在初始化data时,data 函数执行的时候用call方法,让 vm 继承了 data 的属性和方法,也就是 this 继承了 this.$option.data 的属性和方法, 所以我们可以使用 this.xxx。
call 知识点:call 是 Function 对象自带的一个方法,可以改变函数体内部的 this 指向,第一个参数就是this要指向的对象,也就是想指定的上下文,后面的参数它会按顺序传递进去。它的函数会被立即调用。
但我看了另外一篇文章指出了这篇文章的错误,点这里,文章指出,可以使用this.xxx来访问data并不是因为call函数做到的,而是Vue实例代理了data上的所有属性。(这与开发者文档的描述是相符的)
总结一下:
当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。data可能是一个函数也可能是一个对象,Vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。
具体来说,Vue实例遍历了我们之前所取到的data,对其中每一个属性都进行了proxy(vm,_data, key)调用。Object.defineProperty()方法在proxy中被使用,给Vue实例定义了新的属性,也就是说,proxy利用Object.defineProperty()方法将data中的属性绑定在了Vue实例上。通过在Vue实例上创建新的属性,以及set、get属性描述符,可以使得每一次数据改变都作用于vm._data上。
开发者文档原文
DATA是Vue 实例的数据对象。Vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的 key/value 对):浏览器 API 创建的原生对象,原型上的属性会被忽略。大概来说,data 应该只能是数据 - 不推荐观察拥有状态行为的对象。
Vue的计算属性、方法和侦听器原理
- 计算属性和方法的区别?
- 计算属性缓存是什么意思?
- 如何观察和响应vue实例上的变动?侦听属性
计算属性
你可以像绑定普通 property 一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。
Vue的生命周期
创建前后、挂载前后、更新前后以及销毁前后八个阶段,每个阶段有自己对应的钩子函数,具体如图所示(来自官方文档):
参考来源:
[1]Vue.js官方文档教程
备注一下,虽然标了原创,但是本文章属于梳理知识点,代码和文本可能是从官方文档里粘过来的哈
前端小白,有任何错误欢迎指教o( ̄▽ ̄)d