1.Vue介绍
Vue是渐进式的JavaScript框架,Vue的设计非常注重灵活性和“可以被逐步集成”这个特点。这意味着你可以根据项目需求逐渐采用 Vue 的不同部分,而不是强制性地采用整个框架。你可以采用渐进采用的方式,逐步将 Vue 引入到你的项目中。也可以选择在一个小部分页面中使用 Vue,而不是马上将整个项目迁移到 Vue。这种灵活性使得 Vue 非常适合在现有项目中逐步采用。Vue 的核心库(Vue.js)只关注视图层的渲染,但它还提供了一些可选的插件和库,如 Vue Router(用于处理路由)、Vuex(用于状态管理)等,你也可以选择性地使用这些工具,以构建完整的前端应用。
总之,Vue 的渐进式特性意味着它不会强加给你一种开发方式,而是提供了灵活性,以满足不同项目的需求。这也是 Vue 成为许多开发者和团队的首选框架的原因之一。你可以根据具体项目的情况选择使用 Vue 的哪些部分,而不必承担不必要的复杂性。
在vue官网这样描述到:这就是为什么我们将 Vue 称为“渐进式框架”:它是一个可以与你共同成长、适应你不同需求的框架。这意味着,在开发的过程中,你可以随着对Vue的了解,而逐步在项目使用Vue。
2.Vue的特点——响应式
Vue是基于数据驱动的响应式框架,只要通过正确的方式进行数据的更改,就一定会造成页面视图的变化。数据驱动DOM元素的变化。之所以能够实现这样的效果,就不得不提一下Vue的实现原理
M:model数据模型,可以理解成数据
V:view 视图 vue中的模板代码,生成的DOM元素
VM:viewModel 视图模型即生成的Vue实例
其中VM是Vue.js的核心,它是一个Vue实例,它通过两个工具,让 Model 与 View 产生联系,使DOM元素与数据保持同步,如图所示,
DOM Listeners:负责监听页面上的数据,如果数据被改动,将同步更新到 Model 内
Data Bindings:当 Model 内数据发生改变时,页面上对应的 DOM 会重新渲染
通过VM,我们程序员可以免去对DOM元素的操作,使自己专注于项目的业务逻辑和页面的实现,大大提高项目开发的效率和效果。
3.Vue中的数据代理
vue中的数据代理是通过defineProperty()方法来实现,通过向Vue实例上添加绑定data中的数据,来做数据代理和劫持。具体体现见下图:
<body>
<!-- 数据代理:通过一个对象代理对另一个对象中属性的操作(读/写) -->
<!-- 在这里通过obj2代理对obj1.x的操作 -->
<script type="text/javascript">
//创建Vue实例
let data = {x:100};
let obj2 = vm;
Object.defineProperty(obj2,"x",{
get(){
return obj1.x;
},
set(value){
obj1.x = value
}
})
</script>
</body>
4.Vue中DOM元素复用、更新的判断——diff算法
每一次数据更改,Vue都会进行模板的重新渲染,生成DOM元素。如果每次渲染都生成新的DOM元素,那么对于Vue来说压力有点大,并且过于消耗资源。所以在Vue底层设计了一套diff算法,用来进行比较是否生成新的DOM元素。而diff语法的关键在于key的标识。在v-for指令中我们可以进行制定,但是在其他情况下,Vue会帮我们自动进行标识。以下是key的原理和作用的具体介绍
key的原理
虚拟DOM节点 对比文本节点和真实的标签节点(diff算法进行比较的就是虚拟DOM节点)
真实DOM节点 用户所操作的都是真实的DOM,对于用户所输入的内容,会残留到真实的DOM中
1. 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key,则创建新的真实DOM,随后渲染到到页面。
3. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
4. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
5.Vue生命周期
Vue生命周期:
又名:生命周期回调函数、生命周期函数、生命周期钩子。
是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
生命周期函数中的this指向是vm 或 组件实例对象。
我们从上面看起,Vue的生命周期按照从上到下的顺序依次执行,其中beforeCreate、created、beforeMount、mounted、beforeDestory、destoryed都是执行一次,beforeUpdate、updated随着数据的变动执行多次。
在beforeCreate阶段,此时我们无法访问data中的数据、methods中的方法,因为此时Vue还没有进行数据检测和代理。在created阶段,此时Vue已经可以通过vm访问到data中的数据,methods中的方法。之后,Vue会速度进行模板的解析,现在内存中生成虚拟DOM元素,页面还不能进行正常的显示。在beforeMounted阶段,页面仍呈现的是未经编译的DOM结构,此时对所有的DOM操作都是不奏效的,因为造成的一切DOM操作都会被编译好的DOM结构所覆盖。在mounted阶段,页面显示编译好的DOM结构,此时Vue的工作初步完成。beforeUpdate和updated这两个阶段,随着用户的操作,页面和数据不断地进行更新,完成数据和页面的同步。beforeDestory阶段,是Vue组件销毁前触发的。destoryed阶段执行时,代表Vue对象已经被销毁了,生命结束了。
常用的生命周期钩子:
1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
6.vm与vc的区别
原型的一些知识点:
原型是Javascript中的继承的基础,JavaScript的继承就是基于原型的继承。
构造函数名.prototype叫做显式原型属性
构造函数new出来的对象名.__proto__ 隐式原型属性
我们可以通过显式原型属性和隐式原型属性来访问原型对象
我们一般通过构造函数名.prototype向原型对象中添加属性,通过__proto__来获取原型对象中的属性,由于原型链的设定,我们一般不需要书写__proto__,我们访问对象中的属性的时候,一旦发现对象中没有我们要获取的属性,JS会自动沿着隐式原型链,向上游的原型寻找。
//定义一个构造函数
function Demo(){
this.a = 1
this.b = 2
}
//创建一个Demo的实例对象
const d = new Demo()
console.log(Demo.prototype)//显式原型属性
console.log(d.__proto__)//隐式原型属性
//程序员一般通过显示原型属性操作原型对象,追加一个x属性。值为99
Demo.prototype.x = 99
//只有(构造)函数身上才会有显示原型对象,实例身上有隐式原型对象,二者通过显式和隐式属性指向同一个原型对象
实例的隐式原型属性永远指向自己缔造者的原型对象
VueComponent.prototype.__proto__ = Vue.prototype
VueComponent.prototype.__proto__==Vue.prototype
vm的原型指向vc,本质上是为了代码进行代码复用
通过这样的原型链设计,可以让组件的实例对象vc访问到Vue原型上的属性、方法。
7.组件间通信常用的通信方式
父传子:props配置
子传父:通过给子组件绑定自定义事件,将回调函数写到父组件里面,在子组件中触发事件。
任意组件间通信:
- 全局事件总线(底层实现和组件自定义事件相似,不同的是全局事件需要配置,并且绑定到了vm原型上,通过原型链,使每一个vm实例对象都可以访问到绑定的全局事件总线bus)绑定是this.$bus.$on("事件名",返回的数据);触发是this.$bus.$emit("事件名",传递的数据)。我们如果使用全局事件总线的话,最好在beforeDestory钩子中用$off解绑当前组件所用到的事件,优化内存,毕竟是在原型上面绑定的数据。
- 消息订阅与发布(通过使用pubsub-js(publish subscribe)第三方库来实现消息订阅与发布)在需要订阅和发布消息的组件引入import pubsub from 'pubsub-js'第三方库。在接收数据的组件内订阅消息,订阅的回调函数留在组件自身。在提供数据的组件身上绑定pubsub.publish('xxx',数据),进行消息的发布。同样的,如果我们使用消息订阅与发布,最好在beforeDestroy钩子中,用PubSub.unsubscribe(this.pid)去取消订阅。
- Vuex
8.Vuex
简单地说:Vuex解决多个组件数据共享的问题
复杂地来说:在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
上图是Vuex的流程运行图,Vue组件一般通过dispatch来调用actions中配置的方法,actions再通过commit来调用mutations中的方法,mutations通过mutate直接对数据进行更改操作,最后重新渲染state中的数据,完成Vue组件的更新。若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit
9.路由导航
9.1基础路由配置
路由是Vue学习中的重点和难点,如果对路由部分生疏的小伙伴,可以考虑看VueRouter的官方文档:Vue Router | Vue.js 的官方路由 (vuejs.org)
通过VueRouter我们可以快速完成单页面网站的构建,Vue进行路由的跳转有两种方式:
- <router-link>标签 router-link标签上手容易,但是应用范围有限,最终会被解析成a标签。
- 编程式路由导航,通过this.$router来调用push()、replace()等API进行路由调用,更加灵活,应用广泛。
9.2导航守卫
作用:对路由进行权限控制
分类:全局守卫、独享守卫、组件内守卫
路由元信息,meta:{XXX:xx,YYY:yy}
正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航【是否进行成功的跳转】。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
注意:参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。
对于配置导航守卫中的next方法,一定要谨慎编写,保证一个路由中只执行一次,否则会陷入一个死循环。
10.第三方组件库
这是组件编程比较强大、舒服的地方,可以快速引入第三方库,提高开发效率,降低开发难度。以下推荐几个比较好用的第三方库: