vue相关知识点总结

263 阅读9分钟

vue和react的区别?

**1.**监听数据变化的实现原理不同

1.Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能

2.React 默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的VDOM的重新渲染

为什么 React 不精确监听数据变化呢?这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而React更强调数据的不可变。所以应该说没有好坏之分,Vue更加简单,而React构建大型应用的时候更加鲁棒。

因为一般都会用一个数据层的框架比如 Vuex 和 Redux,所以这部分不作过多解释,在最后的 vuex 和 redux的区别 中也会讲到。

**2.**数据流不同

大家都知道Vue中默认是支持双向绑定的。在Vue1.0中我们可以实现两种双向绑定:

父子组件之间,props 可以双向绑定

组件与DOM之间可以通过 v-model 双向绑定

在 Vue2.x 中去掉了第一种,也就是父子组件之间不能双向绑定了(但是提供了一个语法糖自动帮你通过事件的方式修改),并且 Vue2.x 已经不鼓励组件对自己的 props 进行任何修改了。
所以现在我们只有 组件 <--> DOM 之间的双向绑定这一种。

然而 React 从诞生之初就不支持双向绑定,React一直提倡的是单向数据流,他称之为 onChange/setState()模式。

不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。

3.Hoc****和mixins

在 Vue 中我们组合不同功能的方式是通过 mixin,而在React中我们通过 HoC (高阶组件)。

React 最早也是使用 mixins 的,不过后来他们觉得这种方式对组件侵入太强会导致很多问题,就弃用了 mixinx 转而使用 HoC

而 Vue 一直是使用 mixin 来实现的。

**4.**组件通讯的区别

在Vue 中有几种方式可以实现组件通信:

1. 父组件通过props给子组件传值 或者 父组件通过$ref给子组件传值

2. 子组件通过$parent给父组件传值

3. 兄弟之间传值通过eventBus

4. 通过 V2.2.0 中新增的 provide/inject 来实现父组件向子组件注入数据,可以跨越多个层级

在 React 中,也有对应的几种方式:

1. 父组件通过 props 可以向子组件传递数据或者回调

2. 兄弟:利用 redux 实现。

3. 所有关系都通用的方法:利用PubSub.js订阅

React 本身并不支持自定义事件,Vue中子组件向父组件传递消息有两种方式:事件和回调函数,而且Vue更倾向于使用事件。但是在 React 中我们都是使用回调函数的,这可能是他们二者最大的区别。

**
5.**模板渲染方式的不同

语法不同:

1. React 是通过JSX渲染模板

2. 而Vue是通过一种拓展的HTML语法进行渲染

原理不同:

1. React是在组件JS代码中,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的

2. Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现

对这一点,我个人比较喜欢React的做法,因为他更加纯粹更加原生,而Vue的做法显得有些独特,会把HTML弄得很乱。举个例子,说明React的好处:

react中render函数是支持闭包特性的,所以我们import的组件在render中可以直接调用。但是在Vue中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以我们import 一个组件完了之后,还需要在 components 中再声明下,这样显然是很奇怪但又不得不这样的做法。

**
6.vuex****和redux的区别**

从表面上来说,store 注入和使用方式有一些区别;

在 Vuex 中,$store 被直接注入到了组件实例中,因此可以比较灵活的使用:

1. 使用 dispatch 和 commit 提交更新

2. 通过 mapState 或者直接通过 this.$store 来读取数据

在 Redux 中,我们每一个组件都需要显示的用 connect 把需要的 props 和 dispatch 连接起来。

另外 Vuex 更加灵活一些,组件中既可以 dispatch action 也可以 commit updates,而 Redux 中只能进行 dispatch,并不能直接调用 reducer 进行修改。

从实现原理上来说,最大的区别是两点:

1、Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改

2、Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,而Vuex其实和Vue的原理一样,是通过 getter/setter来比较的(如果看Vuex源码会知道,其实他内部直接创建一个Vue实例用来跟踪数据变化)

而这两点的区别,其实也是因为 React 和 Vue的设计理念上的区别。React更偏向于构建稳定大型的应用,非常的科班化。相比之下,Vue更偏向于简单迅速的解决问题,更灵活,不那么严格遵循条条框框。因此也会给人一种大型项目用React,小型项目用 Vue 的感觉。

Vue生命周期有哪些?

beforeCreate、created

beforeMount、mounted

beforeUpdate、updated

beforeDestroy、destroyed

Vue 中常见的生命周期钩子函数总共有八个:

(1)创建阶段
BeforeCreate:该函数在 Vue 实例初始化后,组件创建、数据监测(data observer)、watch/event 事件配置前调用。此时不能访问 data、ref,Vue 实例对象上仅有生命周期函数及部分默认事件。

Created:该函数在 Vue 组件创建完成后调用。此时数据监测、事件配置已完成,data 对象已可访问,但组件尚未被渲染成 HTML 模板,ref 仍为 undefined,$el 尚不可用。

如此阶段要对 DOM 进行操作,就应将操作放在 Vue.nextTick 的回调函数中。因为此阶段 DOM 尚未被渲染,无法执行 DOM 操作。Vue.nextTick 会在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后可以获取更新后的 DOM。

(2)挂载阶段
BeforeMount:该函数在组件挂载前调用,此时 HTML 模板编译已完成,虚拟 DOM 已存在,$el 为可用状态,但 ref 仍不可用。

一般在此阶段进行初始数据的获取操作。

Mounted:该函数在组件挂载完成后调用。此时el元素已被vm.el元素已被vm.el替代,ref可进行操作。

一般在此阶段进行异步请求的发送操作。mounted 不会保证所有的子组件也都一起被挂载。如果希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick。

(3)更新阶段
BeforeUpdate:该函数在数据更新、虚拟 DOM 打补丁前调用。

此阶段适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。

Updated:该函数在数据更新、虚拟 DOM 打补丁完成后调用。

(4)卸载阶段
BeforeDestory:该函数在实例销毁前调用,此时实例完全可用,ref 仍然存在。

一般在此阶段进行性能优化操作,如清除定时器,防止内存泄露。

Destroyed:该函数在实例销毁后调用,此时 Vue 里的所有指令均被解绑,所有事件监听器已被移除,ref 状态为 undefined。

组件销毁时,先销毁父组件,再销毁子组件。

针对 keep-alive 组件还有两个钩子函数:

activated:在被 keep-alive 缓存的组件激活时调用。

deactivated:在被 keep-alive 缓存的组件停用时调用。

还有一个错误处理捕获函数:
errorCaptured**:**在捕获到一个来自子孙组件的错误时调用。

Vue 双向绑定原理是什么?

vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的;

首先是2.0的双向绑定首先要深克隆一份data数据,通过Object.defineProperty监听data里面的每个属性,通过get/set方法达到双向绑定数据

3.0通过Proxy监听整个对象,现实无须克隆数据,且能够深度监听的效果。

vue****的响应式基本原理:

简单回答:

1、vue会遍历此data中对象所有的属性,

2、并使用Object.defineProperty把这些属性全部转为getter/setter,

3、而每个组件实例都有watcher对象,

4、它会在组件渲染的过程中把属性记录为依赖,

5、之后当依赖项的 setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。

亮点回答:

1、在生命周期的initState方法中将data,prop,method,computed,watch中的数据劫持, 通过observe方法与Object.defineProperty方法将相关对象转为换Observer对象。

2、然后在initRender方法中解析模板,通过Watcher对象,Dep对象与观察者模式将模板中的 指令与对象的数据建立依赖关系,使用全局对象Dep.target实现依赖收集。

3、当数据变化时,setter被调用,触发Object.defineProperty方法中的dep.notify方法, 遍历该数据依赖列表,执行器update方法通知Watcher进行视图更新。

4、 vue是无法检测到对象属性的添加和删除,但是可以使用全局Vue.set方法(或vm.$set实例方法)。

5、 vue无法检测利用索引设置数组,但是可以使用全局Vue.set方法(或vm.$set实例方法)。

6、 无法检测直接修改数组长度,但是可以使用splice

Vue 的双向数据绑定原理是什么?

Vue 采用数据劫持+订阅发布模式实现双向绑定。通过 Object.defineProperty()方法来为组件中 data 的每个属性添加 get 和 set 方法,在数据变动时,触发 set 里相应的监听回调函数,将变动信息发布给订阅者。主要有以下步骤:
(1)组件初始化时:
a. 创建一个dep 对象作为观察者(依赖收集、订阅发布的载体);
b. 通过Object.defineProperty()方法对 data 中的属性及子属性对象的属性,添加 getter 和 setter 方法; 调用 getter 时,便去 dep 里注册函数。调用 setter 时,便去通知执行刚刚注册的函数。
(2)组件挂载时:
a. compile解析模板指令,将其中的变量替换成数据。然后初始化渲染页面视图,并将每个指令对应的节点绑定上更新函数、监听函数。后续一旦数据发生变化,便会更新页面。页面发生变化时也会相应发布变动信息;
b. 组件同时会定义一个watcher 类作为订阅者,watcher 可以视作 dep 和组件之间的桥梁。其在实例化时会向 dep 中添加自己,同时自身又有一个 update 方法,待收到 dep 的变动通知时,便会调用自己的 update 方法,触发 compile 中的相应函数完成更新。

Vue 框架的优点是什么?缺点是什么?

Vue优点:

(1) 轻量级框架:只关注视图层,大小只有几十Kb;

(2) 简单易学:文档通顺清晰,语法简单;

(3) 数据双向绑定,数据视图结构分离,仅需操作数据即可完成页面相应的更新;

(4) 组件化开发:工程结构清晰,代码维护方便;

(5) 虚拟 DOM加载 HTML 节点,运行效率高。

vue的缺点:

1、Vue 不缺入门教程,可是很缺乏高阶教程与文档。同样的还有书籍。

2、VUE不支持IE8

3、生态环境差不如angular和react

4、社区不大

什么是 MVVM?

MVVM 是Model-View-ModelView的缩写,是一种脱胎于 MVC 模式的设计模式
Model 代表数据层,负责存放业务相关的数据;
View 代表视图层,负责在页面上展示数据;
ViewModel 是的作用是同步 View Model 之间的关联,其实现同步关联的核心是DOM Listeners和 Data Bindings两个工具。DOMListeners 工具用于监听 View 中 DOM 的变化,并会选择性的传给 Model;Data Bindings 工具用于监听 Model 数据变化,并将其更新给 View。

Vue 中组件之间传值的方法有哪些?

父组件向子组件传值:

1、父组件通过props给子组件传值

2、父组件通过$ref给子组件传值(父组件通过ref 获取到在子组件里定义的属性和方法,通过调用方法给子组件传递数据)

3、父组件通过$children给子组件传值(children为当前组件的直接子组件,是一个无序的数组)

4.父组件通过provide/inject给子孙组件传值(provide/inject 组合以允许一个祖先组件向其所有子孙后代组件注入一个依赖(属性和方法),不论组件层次有多深,并在其上下游关系成立的时间里始终生效,从而实现跨级父子组件通信,主要在开发高阶插件/组件库时使用)

props和refref和children和provide/inject的主要区别:

1、props 侧重于数据的传递,并不能获取子组件里的属性和方法,适用于自定义内容的使用场景

2、$ref 侧重于获取子组件里的属性和方法,并不是太适合传递数据,并且 ref 常用于获取dom元素,起到选择器的作用

3、$children 侧重于获取所有的直接子组件,得到的是一个无序的数组,并不太适合向多个子组件传递数据

4、provide/inject 侧重于在开发高阶插件/组件库时使用,并不推荐用于普通应用程序代码中

子组件向父组件传值:

1、子组件通过触发emit事件给父组件传值(emit事件给父组件传值(emit 的第一个参数为自定义的事件,第二个参数为要传递给父组件的值,父组件在子组件标签上绑定自定义事件来接收子组件传递的数据)

2、子组件通过$parent给父组件传值

兄弟组件之间传值:

1、兄弟之间传值通过eventBus(eventBus 就是一个vue实例来作为全局的事件总线,//子组件A通过eventBus.$emit触发自定义事件给子组件B传值)
2、通过vuex

为什么 Vue 组件中 data 必须是一个函数?

如果 data 是一个对象,当复用组件时,因为 data 都会指向同一个引用类型地址,其中一个组件的 data 一旦发生修改,则其他重用的组件中的 data 也会被一并修改。
如果 data 是一个返回对象的函数,因为每次重用组件时返回的都是一个新对象,引用地址不同,便不会出现如上问题。

Vue 中 v-if 和 v-show 有什么区别?

v-if 在进行切换时,会直接对标签进行创建或销毁,不显示的标签不会加载在 DOM 树中。v-show 在进行切换时,会对标签的 display 属性进行切换,通过 display 不显示来隐藏元素。
一般来说,v-if 的性能开销会比 v-show 大,切换频繁的标签更适合使用 v-show。

Vue 中 computed 和 watch 有什么区别?

计算属性 computed
(1)支持缓存,只有依赖数据发生变化时,才会重新进行计算函数;

(2)计算属性内不支持异步操作

(3)计算属性的函数中都有一个 get(默认具有,获取计算属性)和 set(手动添加,设置计算属性)方法;
(4)计算属性是自动监听依赖值的变化,从而动态返回内容。

侦听属性 watch

(1)不支持缓存,只要数据发生变化,就会执行侦听函数;
(2)侦听属性内支持异步操作
(3)侦听属性的值可以是一个对象,接收 handler 回调,deep,immediate 三个属性
(4)监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些其他事情

watch: {

obj: {

//handler接收两个参数(newVal:新值,oldVal:旧值

handler: function(newVal, oldVal){

console.log(newVal);

},

deep: true,//设置为true时会监听对象内部值的变化;

immediate: true//设置为true时会立即以表达式的当前值触发回调;

}

}

使用 immediate 可以优化以下场景:组件创建的时候立即获取一次列表的数据,同时监听框,每当发生变化的时候重新获取一次筛选后的列表。

//优化前

created(){

this.fetchPostList()

},

watch: {

searchInputValue(){ this.fetchPostList() }

}

//优化后

watch: {

searchInputValue:{ handler: 'fetchPostList', immediate: true }

}

$nextTick 是什么?

Vue 实现响应式并不是在数据发生后立即更新 DOM,使用 vm.$nextTick 是在下次 DOM 更新循环结束之后立即执行延迟回调。在修改数据之后使用,则可以在回调中获取更新后的 DOM

v-for 中 key 的作用是什么?

key 是 Vue 使用 v-for 渲染列表时的节点标识。使用了 key 之后,当列表项发生变化时,Vue 会基于 key 的变化而重新排列元素顺序,并且移除 key 不存在的元素,提升运行效率

如何动态更新对象或数组的值?

因为 Object.defineProperty()的限制,Vue 无法监听到对象或数组内部某个属性值的变化,因此在直接设置以上两类数据的值时,页面不会实时更新。此时可以通过 this.$set 方法来解决:

//this.set(要改变的数组/对象,要改变的位置/key,要改成的value)this.set(要改变的数组/对象,要改变的位置/key,要改成的value) this.set(this.arr, 0, "OBKoro1");

// 改变数组 this.$set(this.obj, "c", "OBKoro1"); // 改变对象

数组原生方法造成的数据更新,可以被 Vue 监听到。如 splice()push()pop()等。

常用的事件修饰符有哪些?

stop:阻止冒泡;
prevent:阻止默认行为;
self:仅绑定元素自身可触发;
once:只触发一次..

Vue 如何获取 DOM 元素?

首先先为标签元素设置 ref 属性,然后通过 this.$refs.属性值获取。

const dom = this.$refs.test

v-on 如何绑定多个事件?

可以通过 v-on 传入对象来绑定多个事件:

<input type="text" @click="onClick">

Vue 初始化页面闪动问题如何解决?

出现该问题是因为在 Vue 代码尚未被解析之前,尚无法控制页面中 DOM 的显示,所以会看见模板字符串等代码。
解决方案是,在 css 代码中添加 v-cloak 规则,同时在待编译的标签上添加 v-cloak 属性:

[v-cloak] { display: none; }

{{ message }}

Vue 如何清除浏览器缓存?

(1)项目打包的时候给每个打包文件加上 hash 值,一般是在文件后面加上时间戳;
(2)在 html 文件中加入 meta 标签,content 属性设置为no-cache;
(3) 在后端服务器中进行禁止缓存设置。

Vue-router 路由有哪些模式?

一般有两种模式:
(1)hash 模式:后面的 hash 值的变化,浏览器既不会向服务器发出请求,浏览器也不会刷新,每次 hash 值的变化会触发 hashchange 事件。
(2)history 模式:利用了 HTML5 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。

Vue-cli 项目中每个文件夹和文件的用处大致是什么?

(1)bulid 文件夹:存放 webpack 的相关配置以及脚本文件,实际开发中一般用来配置 less、babel 和配置 webpack.base.config.js 文件。

(2)config 文件夹:常用到此文件夹下的 config.js (index.js) 配置开发环境的端口号,是否开启热加载或者设置生产环境的静态资源相对路径、是否开启 gzip 压缩、npm run build 命令打包生成静态资源的名称和路径等。
(3)node_modules 文件夹:存放 npm install 命令下载的开发环境和生产环境的各种依赖。

(4)src 文件夹 :存放组件源码、图片样式资源、入口文件、路由配置等。

Vue-cli 项目中 assets 和 static 文件夹有什么区别?

两者都是用于存放项目中所使用的静态资源文件的文件夹。其区别在于:
** assets 中的文件在运行 npm run build 的时候会打包**,简单来说就是会被压缩体积,代码格式化之类的。打包之后也会放到 static 中。static 中的文件则不会被打包

将图片等未处理的文件放在assets中,打包减少体积。而对于第三方引入的一些资源文件如iconfont.css等可以放在static中,因为这些文件已经经过处理了。

Vuex 是什么?有哪几种属性?

Vuex 是专为Vue设计的状态管理工具,采用集中式储存管理 Vue 中所有组件的状态。

(1)state属性:基本数据
(2)getters属性:从 state 中派生出的数据
(3)mutation属性:**更新 store 中数据的唯一途径,**其接收一个以 state 为第一参数的回调函数;

const store = new Vuex.Store({

state: {

count: 1,

},

mutations: {

increment(state) {

// 变更状态

state.count++;

},

},

});

(4)action 属性提交 mutation 以更改 state,其中可以包含异步操作

const store = new Vuex.Store({

state: {

count: 0,

},

mutations: {

increment(state) {

state.count++;

},

},

actions: {

increment2(context) {

context.commit('increment');

},

fun(context) {

context.dispatch('increment2');

},

},

});

(5)module 属性:用于将 store分割成不同的模块

const moduleA = {

state: () => ({ ... }),

mutations: { ... },

actions: { ... },

getters: { ... }

}

const moduleB = {

state: () => ({ ... }),

mutations: { ... },

actions: { ... }

}

const store = new Vuex.Store({

modules: {

a: moduleA,

b: moduleB

}

})

store.state.a // -> moduleA 的状态

store.state.b // -> moduleB 的状态