Vue.js是目前业界流行的前端技术之一。它有什么优点让它在各种前端框架中脱颖而出,结合代码简单介绍一下对vue.js的主要关键技术的理解。
以下是几个关键技术点的简介。
1.渐进式框架
2.声明式渲染
3.响应式更新
4.选项式和组合式API
Vue.js是一种渐进式框架。
Vue是一个渐进式(真正用到才引用)的JavaScript框架与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,与现代化的工具以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
1.Vue的主要特性如下:
● 可扩展的数据绑定
● 将普通的 JS 对象作为 model
● 简洁明了的 API
● 组件化 UI 构建
● 配合别的库使用
我对渐进式的理解其实就两个字:自由。
当我们要用Angular框架时要知道它是强主张的,必须要遵循以下三条规则:
必须使用它的模块机制
必须使用它的依赖注入
必须使用它的特殊形式定义组件(这一点每个视图框架都有,难以避免)
而React的主张主要是函数式编程的理念,比如说,你需要知道什么是副作用,什么是纯函数,如何隔离副作用。它的侵入性看似没有Angular那么强,主要因为它是软性侵入。
但是Vue就比较自由了你想把你的页面分的更加具体,分成更小的可控单元,那就用组件系统其他可以不用,当然声明式渲染我们还是得用的,应为我们都希望DOM的更新是自动的,而非手动去更新的。
3.对比其他框架
React
React 和 Vue 有许多相似之处,它们都有:
● 使用 Virtual DOM
● 提供了响应式(reactive)和可组合的视图组件(composable view component)。
● 将注意力集中保持在核心库,同时也关注路由和负责处理全局状态管理的辅助库。
但是在功能模板选择上,Vue相对更简单,Vue 的路由库和状态管理库都是由官方维护支持且与核心库同步更新的。React 则是选择把这些问题交给社区维护
AngularJS
Vue 的一些语法和 AngularJS 的很相似,但两者相比,在 API 与设计两方面上 Vue.js 都比 AngularJS 1 简单得多;Vue.js 是一个更加灵活开放;在 Vue 中指令和组件分得更清晰。
Ember
Vue 在普通 JavaScript 对象上建立响应,提供自动化的计算属性。在 Ember 中需要将所有东西放在 Ember 对象内,并且手工为计算属性声明依赖。在性能上,Vue 比 Ember 具有优势,即使是 Ember 2.x 的最新 Glimmer 引擎。Vue 能够自动批量更新,而 Ember 在关键性能场景时需要手动管理。
4.Vue 组件:
使用 Vue 组件的项目结构;
一个 .Vue 文件,除了包含通常的 HTML 标签外、CSS 样式和 JS 脚本外,还能使用模板标签;
.Vue 文件的 JS 脚本中,能定义供模板使用的模板变量;.vue 文件的一个架构示例,如图:
在 .Vue 文件中,能定义方法和组件的生命周期方法;
总而言之,vue 比市面上的其他框架功能更完善,性能更高效。
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
这是vue官网对声明式渲染的定义,那么什么是声明式呢?
命令式渲染 : 命令我们的程序去做什么,程序就会跟着你的命令去一步一步执行
声明式渲染 : 我们只需要告诉程序我们想要什么效果,其他的交给程序来做。
来看个例子,可能就更加理解声明式和命令式
输出的结果其实是相同的
我们在官网会看到这么一张图,但根本就看不懂。
这样就会好很多。
vue.js官方文档:https://cn.vuejs.org/v2/api/#provide-inject
官方的说明大家可以打开上面的链接去看,说通俗点,就是可以用来父辈们给祖孙传值,请看清楚,这里说的是可以隔代传值,传统的props只能父传子,不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,这就是它最大的特性。
provide 选项应该是:一个对象或返回一个对象的函数
inject 选项应该是:一个字符串数组,或 一个对象,对象的 [key] 是本地的绑定名
代码执行顺序:
data
provide
created//在这个阶段$el还未生成,在这先处理privide的逻辑,子孙组件才可以取到inject值
mounted
首先假设我们在祖辈传入进来是个动态的数据,官方不是说如果你传入了一个可监听的对象,那么其对象还是可响应的么?
parent父页面:
export default {
data(){
return { fonnB: 'old word '}
},
provide() {
return { foo: this.fonnB }
},
created() {
setTimeout(()=>{
this.fonnB = 'new words'; // 这里仅仅foonB变化了,foo没有变化
this._provided.foo="new words"; // 这里foo变化了,但子组件获得的foo 依旧是old words
console.log( this._provided);
},1000)
},
}
child子页面:
export default {
inject:['foo'],
data(){
return { chilrfoo: this.foo }
},
created() {
setTimeout(()=>{
// 子组件获得的foo 依旧是old words
console.log( this.foo)
},2000)
}
}
通过上面方式,经过验证,子组件页面都没办法实现响应更新this.foo的值。可能我们对官方理解还是有误,下面通过网上资料和自己构思实现了响应式数据更新
示例(结果仍不可行)
很明显上面再父组件定时器内我们是改变了数据源,这个时候我们就在想,我们改变的数据到底有没有传入到子孙组件中,那么要验证这个问题,我们不妨可以在子孙组件中手动写set 函数,computed 本身就只相当于一个get函数,当然,也可以试试watch
把js对象传入一个vue实例作为data项,进行遍历,使用Object.defineProperty把这些属性转为getter/setter。
Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
每个vue实例都有一个watcher实例,它会在实例渲染时记录这些属性,并在setter触发时重新渲染。
Vue 不能检测数组和对象的变化
Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property
由于 Vue 不允许动态添加根级响应式属性,所以你必须在初始化实例前声明所有根级响应式属性,哪怕只是一个空值。
如果你未在 data 选项中声明 message,Vue 将警告你渲染函数正在试图访问不存在的属性。
vue更新dom时是异步执行的
数据变化、更新是在主线程中同步执行的;在侦听到数据变化时,watcher将数据变更存储到异步队列中,当本次数据变化,即主线成任务执行完毕,异步队列中的任务才会被执行(已去重)。
如果你在js中更新数据后立即去操作DOM,这时候DOM还未更新;vue提供了nextTick接口来处理这样的情况,它的参数是一个回调函数,会在本次DOM更新完成后被调用。
什么是选项 API : 在 vue2.x 项目中使用的就是 选项API 写法
代码风格:date选项写数据,methods选项写函数、、、、,一个功能逻辑的代码分散
优点:易于学习和使用,写代码的位置已经约定好了
缺点:代码组织性差,相似的逻辑代码不便于复用,逻辑复杂代码多了不好阅读。
虽然提供了 mixins 用来封装逻辑,但是出现数据函数覆盖的概率很大,不好维护
什么是组合 API : 在 vue3 中使用的就是 组合API 写法
代码风格:一个功能逻辑的代码组织在一起(包括数据,函数、、、)
优点:功能逻辑复杂繁多情况下,各个功能逻辑代码组织再一起,便于阅读和维护
缺点:需要有良好的代码组织能力和拆分逻辑能力 (在 vue3 中也可以支持 vue2 选项API 写法)
1. 组合式 API 的目的是增强,不是取代选项式 API , vue3 对两种 API 都支持
2. 简单的场景使用选项式 API 更加简单方便
3. 需要强烈支持 TS 的项目首选组合式 API
4. 需要大量逻辑复用的场景首选组合式 API