vue
什么是 MVVM?
MVVM 是 Model-View-ViewModel 的缩写。 MVVM 是一种设计思想。 Model 层代表数据模型, 也可以在 Model 中定义数据修改和操作的业务逻辑; View 代表 UI 组件, 它负责将数据模型转化成 UI 展现出来, ViewModel 是一个同步 View 和Model 的对象。在MVVM 架构下, View 和 Model 之间并没有直接的联系, 而是通过 ViewModel进行交互, Model 和 ViewModel 之间的交互是双向的, 因此 View 数据的变化会同步到 Model中而 Model 数据的变化也会立即反应到 View 上。ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑, 不需要手动操作 DOM, 不需要关注数据状态的同步问题, 复杂的数据状态 维护完全由 MVVM 来统一管理。
mvvm 和 mvc 区别? 它和其它框架(jquery) 的区别是什么? 哪些场景适合?
mvc 和 mvvm 其实区别并不大。 都是一种设计思想。 主要就是 mvc 中 Controller
演变成 mvvm 中的 viewModel。 mvvm 主要解决了 mvc 中大量的 DOM 操作使页面渲
染性能降低, 加载速度变慢, 影响用户体验。
区别: vue 数据驱动, 通过数据来显示视图层而不是节点操作。
场景: 数据操作比较多的场景, 更加便捷。
对比 jQuery , Vue 有什么不同
jQuery 专注视图层, 通过操作 DOM 去实现页面的一些逻辑渲染; Vue 专注于数据层, 通过数据的双向绑定, 最终表现在 DOM 层面, 减少了 DOM 操作。Vue 使用了组件化思想, 使得项目子集职责清晰, 提高了开发效率, 方便重复利用, 便于协同开发。
Vue 的双向数据绑定原理是什么?
vue.js 是采用数据劫持结合发布者-订阅者模式的方式, 通过 Object.defineProperty()来劫持各个属性的 setter, getter, 在数据变动时发布消息给订阅者, 触发相应的监听回调。
具体步骤:
第一步: 需要 observe 的数据对象进行递归遍历, 包括子属性对象的属性, 都加上 setter和 getter这样的话, 给这个对象的某个值赋值, 就会触发 setter, 那么就能监听到了数据变化
第二步: compile 解析模板指令, 将模板中的变量替换成数据, 然后初始化渲染页面视图,
并将每个指令对应的节点绑定更新函数, 添加监听数据的订阅者, 一旦数据有变动, 收到通
知, 更新视图
第三步: Watcher 订阅者是 Observer 和Compile之间通信的桥梁, 主要做的事情是:
1、 在自身实例化时往属性订阅器(dep)里面添加自己
2、 自身必须有一个 update()方法
3、 待属性变动 dep.notice()通知时, 能调用自身的 update()方法, 并触发 Compile 中绑定的回调, 则功成身退。
第四步: MVVM 作为数据绑定的入口, 整合 Observer、Compile 和 Watcher 三者, 通过 Observer来监听自己的 model 数据变化, 通过 Compile 来解析编译模板指令, 最终利用 Watcher 搭起Observer和Compile之间的通信桥梁, 达到数据变化 -> 视图更新; 视图交互变化(input) -> 数据 model 变更的双向绑定效果。
vue的优点
低耦合。 视图(View) 可以独立于 Model 变化和修改, 一个 ViewModel 可以绑定
到不同的"View"上, 当 View 变化的时候 Model 可以不变, 当 Model 变化的时候
View 也可以不变。
可重用性。 你可以把一些视图逻辑放在一个 ViewModel 里面, 让很多 view 重用
这段视图逻辑。
独立开发。 开发人员可以专注于业务逻辑和数据的开发(ViewModel), 设计人员
可以专注于页面设计。
可测试。 界面素来是比较难于测试的, 而现在测试可以针对 ViewModel 来写。\
watch,methods,computed的区别
定义
-
computed :计算属性出现的目的是解决模板中放入过多的逻辑会让模板过重且难以维护的问题,计算属性是根据data中已有的属性,计算得到一个新的属性.计算属性是基于他的依赖缓存的(所依赖的还是
data中的数据)。一个计算属性所依赖的数据发生变化时,他才会重新取值,只要相关依赖没有改变,对此访问计算属性得到的是之前缓存的结果,不会多次执行。所以说,在进行大量耗时计算的时候,建议使用计算属性来完成. -
watch : 侦听器就是侦听
data中的数据变化,如果数据一旦发生变化就通知侦听器所绑定方法,来执行相应的操作。从这一点上,与计算属性是非常类似的.watch是允许异步操作的,并且在我们得到最终的结果前,可以设置中间状态,这些都是计算属性无法做到的 使用场景: 执行异步或开销较大的操作
区别
第一点、 语境上的差异。
watch适合一个值发生了变化,对应的要做一些其它的事情,适 合一个值影响多个值的情形。而计算属性
computed:一个值由其它的值得来,其它值发生了变化,对应的值也会变化,适合做多个值影响一个值的情形。
第二点、计算属性有缓存性。
由于这个特点,我们在实际的应用中,能用计算属性的,会首先考虑先使用计算属性
第三点、侦听器选项提供了更加通用的方法,适合执行异步操作或者较大开销操作。
Vue生命周期
定义
每个Vue实例在被创建时都要经过一系列的初始化过程,例如:需要设置数据的监听,编译模板,将实例挂载到DOM上,并且在数据变化时更新DOM等,这些过程统称为Vue实例的生命周期。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
- 挂载(初始化相关属性,例如
watch属性,method属性)
1. `beforeCreate`
2. `created`
3. `beforeMount`
4. `mounted`
- 更新(元素或组件的变更操作)
1. `beforeUpdate`
2. `updated`
- 销毁(销毁相关属性)
1. `beforeDestroy`
2. `destroyed`
注意
1.页面首次加载会触发beforeCreate, created, beforeMount, mounted
2.created表示完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来
3.Vue 实例从创建到销毁的过程,就是生命周期
4.在执行created的时候,所有的状态都初始化完成,我们也完全可以在该阶段发送异步的ajax请求,获取数据,在created方法中,是无法获取到对应的的$el选项,也就是无法获取Dom
5.template参数的优先级比外部HTML的优先级要高
总结
beforeCreate( )// 该钩子函数执行时,组件实例还未创建.
created()//组件初始化完毕,各种数据可以使用,可以使用ajax发送异步请求获取数据
beforeMounted()// 未执行渲染,更新,虚拟DOM完成,真实DOM未创建
mounted()// 初始化阶段结束,真实DOM已经创建,可以发送异步请求获取数据,也可以访问dom元素
beforeUpdate()//更新前,可用于获取更新前各种状态数据
updated()//更新后执行该钩子函数,所有的状态数据是最新的。
beforeDestroy() // 销毁前执行,可以用于一些定时器的清除。
destroyed()//组件已经销毁,事件监听器被移除,所有的子实例也会被销毁。
vue中key值的作用
使用key来给每个节点做唯一标识,key的作用主要是为了高效的更新虚拟Dom,另外vue中使用相同标签名元素的过渡切换,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换内部属性而不会触发过渡效果。
vue组件中的data为什么必须是函数
当data选项是一个函数的时候,每个实例可以维护一份被返回对象的的独立的拷贝,这样各个实例中的data 不会相互影响,是独立的。
v-for与v-if的优先级
v-for的优先级比v-if高
说出四种vue的指令和它的用法
v-if (判断是否隐藏)
v-for(把数据遍历出来)
v-bind(绑定属性)
v-model(实现双向绑定)
组件化
特点
可复用、维护、可组合
可复用:每个组件都是具有独立功能的,它可以被使用在多个场景中。
可组合:一个组件可以和其它的组件一起使用或者可以直接嵌套在另一个组件内部。
可维护:每个组件仅仅包含自身的逻辑,更容易被理解和维护。
基本使用
Vue.component('index', {
template: '<div>我是首页的组件</div>'
})
//第一个参数指定了所创建的组件的名字,第二个参数指定了模板
//组件创建好以后,具体的使用方式如下:
<div id="app">
<index></index>
</div>
//注意:1. 模板template中只能有一个根节点;2. 组件的名字,如果采用驼峰命令的话,
//在使用的时候,就要加上 “-”,比如组件名字叫indexA,那么在使用的时候就叫index-a。
Vue.component('componentA', {
template: "<div>创建一个新的组件</div>"
})
// 组件的使用
<component-a></component-a>
在Vue实例中所使用的选项,在组件中都可以使用 ,但是要注意data,在组件中使用时必须是一个函数。
注意
第一点:data必须是一个函数
第二:组件模板中必须有一个跟元素。
第三:组件模板内容可以使用模板字符串。
局部组件注册
可以在一个组件中,再次注册另外一个组件,这样就构成了父子关系。
Vue.component('father', {
template: '<div><p>我是父组件</p><son></son></div>',
` components`: {
// 创建一个子组件
son: {
template: '<p>我是子组件</p>'
}
}
})
组件的使用
<div id="app">
<father></father>
</div>
组件通信
父组件向子组件传递数据
第一:子组件内部通过props接收传递过来的值。
Vue.component('menu-item',{
props:['title'] // props后面跟一个数组,数组中的内容为字符串,这个字符串可以当做属性类使用。
template:'<div>{{title}}</div>'
})
第二: 父组件通过属性将值传递给子组件
<menu-item title="向子组件传递数据"> </menu-item>
<menu-item :title="title"></menu-item> <!--可以使用动态绑定的方式来传值-->
第三: 完整代码
// 创建一个父组件
Vue.component('father', {
// 2、在使用子组件的地方,通过v-bind指令来给子组件中的props赋值。
template: '<div><p>我是父组件</p><son :myName="mySonName"></son></div>',
data() {
return {
mySonName: '小强'
}
},
components: {
// 创建一个子组件
// 1.声明props,它的作用是:用来接收父组件传递过来的数据。
// props可以跟一个数组,数组里面的内容可以是字符串,这个字符串可以当属性来使用。
son: {
props: ['myName'],
template: '<p>我是子组件,我的名字叫{{myName}}</p>'
}
}
})
var vm = new new Vue({
el: '#app',
data: {
}
})
如果在props中使用驼峰形式,模板中需要短横线的形式,如下代码案例所示:
Vue.component('menu-item',{
//在JavaScript中是驼峰形式
props:['menuTitle'],
template:'<div>{{menuTitle}}</div>'
})
<!--在html中是短横线方式--->
<menu-item menu-title="hello world"></menu-item>
props 可以接收各种类型的值:字符串(String),数值(Number),布尔值(Boolean),数组(Array),对象(Object)
vue中子组件调用父组件的方法
一、 直接在子组件中通过this.$parent.event来调用父组件的方法。
二、 在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了。
三、 是父组件把方法传入子组件中,在子组件里直接调用这个方法。
vue中父组件调用子组件的方法
一、父组件利用ref属性操作子组件方法。
二、通过组件的on方法
keep-alive内置组件的作用
可以让当前组件或者路由不会经历创建和销毁,而是进行缓存,凡是被keep-alive组件包裹的组件,除了第一次以外。不会经历创建和销毁的。第一次创建后会缓存到缓存当中。
include - 字符串或正则表达式, 只有名称匹配的组件会被缓存
exclude - 字符串或正则表达式, 任何名称匹配的组件都不会被缓存\
子组件向父组件传递数据
第一:子组件通过自定义事件向父组件传递信息。
<button v-on:click='$emit("countSum")'> 计算</button>
第二:父组件监听子组件的事件
<menu-item v-on:countSum='sum+=1'></menu-item>
兄弟组件的数据传递
兄弟组件传值,通过事件总线完成。
// 创建一个空的vue实例,作为事件总线
var eventbus = new Vue()
完成代码
// 创建一个空的vue实例,作为事件总线
var eventbus = new Vue()
Vue.component('father', {
template: '<div><son></son><daughter></daughter></div>',
components: {
son: {
data() {
return {
mySisterName: ''
}
},
template: '<div>我妹妹叫{{mySisterName}}</div>',
mounted() {
// 通过eventbus的$on()方法去监听兄弟节点发射过来的事件
// $on有两个参数,一个是事件名称,一个是函数,该函数的默认值就是传递过来的数据
eventbus.$on('tellBroMyName', data => {
this.mySisterName = data
})
}
},
daughter: {
data() {
return {
myName: '小雪'
}
},
template: '<button @click="emitMyName">告诉哥哥我叫{{myName}}</button>',
methods: {
emitMyName() {
// 通过事件总线发射一个事件名称和需要传递的数据
eventbus.$emit('tellBroMyName', this.myName)
}
}
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
})
组件插槽应用
我们可以在父组件中使用子组件,同时由于在子组件中创建插槽slot,也就是相当于预留了空间,这时在父组件中使用子组件时,可以传递不同的内容
基本使用方式
第一:确定插槽的位置
Vue.component('alert-box',{
template:`
<div class="demo-alert-box">
<strong>子组件</strong>
<slot></slot>
</div>
`
})
第二:插槽内容
//向插槽中传递内容。
<alert-box>Hello World</alert-box>
具名插槽
<div id="app">
<base-layout>
<p slot="header">头部内容</p>
<p>主要内容1</p>
<p>主要内容2</p>
<p slot="footer">底部信息</p>
</base-layout>
</div>
<script src="./vue.js"></script>
<script>
Vue.component("base-layout", {
template: `
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`,
});
const vm = new Vue({
el: "#app",
data: {},
});
</script>
在实际的应用中,有可能需要向插槽中插入大量的内容,这时就需要用到template标签。
作用域插槽
模板虽然是在父级作用域(父组件)中渲染的,却能拿到子组件的数据
为什么要使用插槽
组件的最大特性就是复用性,而用好插槽能大大提高组件的可复用能力。组件的复用性常见情形如在有相似功能的模块中,他们具有类似的UI界面,通过使用组件间的通信机制传递数据,从而达到一套代码渲染不同数据的效果。
然而这种利用组件间通信的机制只能满足在结构上相同,渲染数据不同的情形;假设两个相似的页面,他们只在某一模块(区域)有不同的UI效果(例如,前面所做的列表,发现可以显示不同的ui效果),以上办法就做不到了。可能你会想,使用 v-if 和 v-else来特殊处理这两个功能模块,不就解决了?很优秀,解决了,但不完美。极端一点,假设我们有一百个这种页面,就需要写一百个v-if、v-else-if、v-else来处理?那组件看起来将不再简小精致,维护起来也不容易。而 插槽 “SLOT”就可以完美解决这个问题
什么情况下使用插槽
顾名思义,插槽即往卡槽中插入一段功能块。还是举刚才的例子。如果有一百个基本相似,只有一个模块功能不同的页面,而我们只想写一个组件。可以将不同的那个模块单独处理成一个卡片,在需要使用的时候将对应的卡片插入到组件中即可实现对应的完整的功能页。而不是在组件中把所有的情形用if-else罗列出来(这里还是体会用户列表的案例)
可能你会想,那我把一个组件分割成一片片的插槽,需要什么拼接什么,岂不是只要一个组件就能完成所有的功能?思路上没错,但是需要明白的是,卡片是在父组件上代替子组件实现的功能,使用插槽无疑是在给父组件页面增加规模,如果全都使用拼装的方式,和不用组件又有什么区别(例如,用户列表案例中需要其他的显示方式,需要在父组件中进行添加)。因此,插槽并不是用的越多越好。
插槽是组件最大化利用的一种手段,而不是替代组件的策略,当然也不能替代组件。如果能在组件中实现的模块,或者只需要使用一次v-else, 或一次v-else-if,v-else就能解决的问题,都建议直接在组件中实现。
你能谈一下对Vue组件化的理解吗?
定义:组件是可复用的Vue实例,准确讲它是VueComponent的实例,继承自Vue
优点:组件化可以增加代码的复用性,可维护性和可测试性。
使用场景:什么时候使用组件?以下分类可以作为参数
第一:通用组件:实现最基本的功能,具有通用性,复用性。例如按钮组件,输入框组件,布局组件等。(Element UI组件库就是属于这种通用的组件)
第二:业务组件,用于完成具体的业务,具有一定的复用性。例如登录组件,轮播图组件。
第三:页面组件,组织应用各部分独立内容,需要时在不同页面组件间切换,例如:商品列表页,详情页组件。
如何使用组件
- 定义:
Vue.component(),components选项 - 分类:有状态组件(有data属性),
functional - 通信:
props,$emit()/$on(),provide/inject - 内容分发:
<slot>,<template>,v-slot - 使用及优化:
is,keep-alive,异步组件
组件的本质
vue中的组件经历如下过程 组件配置 =>VueComponent实例 => render()=> Virtual DOM=> DOM 所以组件的本质是产生虚拟DOM
Vue常用的API
Vue.set
向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且会触发视图更新。
使用方法:Vue.set(target,propertyName,value)
Vue.delete
删除对象的属性,如果对象是响应式的,确保删除能触发更新视图。
使用方式:Vue.delete(target,propertyName)
如果使用delete obj['property'] 是不能更新页面的。
以上两个方法Vue.set()和Vue.delete()等同于以下两个实例方法
vm.$set()
vm.$delete()
v-model的实现原理
v-model就是v-bind与v-on的语法糖。
为什么避免 v-if 和 v-for 用在一起?
当 Vue 处理指令时, v-for 比 v-if 具有更高的优先级, 通过 v-if 移动到容器元素, 不会再
重复遍历列表中的每个值。 取而代之的是, 我们只检查它一次, 且不会在 v-if 为否的时候运算 v-for。
聊聊你对 Vue.js 的 template 编译的理解?
简而言之, 就是先转化成 AST 树, 再得到的 render 函数返回 VNode(Vue 的虚拟 DOM 节点)
详情步骤:
首先, 通过 compile 编译器把 template 编译成 AST 语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形式), compile 是 createCompiler 的返回值, createCompiler 是用以创建编译器的。 另外 compile 还负责合并 option。
然后, AST 会经过 generate(将 AST 语法树转化成 render funtion 字符串的过程) 得到 render函数, render 的返回值是 VNode, VNode 是 Vue 的虚拟 DOM 节点, 里面有(标签名、 子节点、 文本等等)
vue 等单页面应用(spa) 及其优缺点
优点: Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件, 核心
是一个响应的数据绑定系统。 MVVM、 数据驱动、 组件化、 轻量、 简洁、 高效、 快速、 模块
友好; 即第一次就将所有的东西都加载完成, 因此, 不会导致页面卡顿。
缺点: 不支持低版本的浏览器, 最低只支持到 IE9; 不利于 SEO 的优化(如果要支持 SEO,
建议通过服务端来进行渲染组件); 第一次加载首页耗时相对长一些; 不可以使用浏览器的
导航按钮需要自行实现前进、 后退。
自定义指令( v-check、 v-focus) 的方法有哪些? 它有哪些钩子函数? 还有哪些钩子函数参数?
全局定义指令: 在 vue 对象的 directive 方法里面有两个参数, 一个是指令名称, 另外一个是
函数。 组件内定义指令: directives
钩子函数: bind( 绑定事件触发)、 inserted(节点插入的时候触发)、 update( 组件内相关更
新)
钩子函数参数: el、 binding。
简述一下 Sass、 Less, 且说明区别?
他们是动态的样式语言, 是 CSS 预处理器,CSS 上的一种抽象层。 他们是一种特殊的语法语言而编译成 CSS。变量符不一样, less 是@, 而 Sass 是$;Sass 支持条件语句, 可以使用 if{}else{},for{}循环等等。 而 Less 不支持;Sass 是基于 Ruby 的, 是在服务端处理的,而 Less 是需要引入 less.js 来处理 Less 代码输出Css 到浏览器。
vuex-router
怎么定义 Vue—router的动态路由?怎么获取传过来的值
动态路由的创建,主要是使用path属性过程中,使用动态路径参数,以冒号开头,
{ path: '/user/:id', component: Details }
访问 details 目录下的所有文件, 如果 details/a, details/b 等, 都会映射到 Details 组件上。匹配到/details 下的路由时, 参数值会被设置到 this.route.params.id
vue-router 有哪几种路由守卫
全局守卫
就是所有的路由都会经过全局守卫来进行检测
beforeEach、afterEach、beforeResolve
路由独享守卫
如果项目比较简单,路由规则定义的比较少,可以将守卫定位到某个路由规则内。这就是路由独享守卫
beforeEnter
组件内守卫
beforeRouteEnter、
beforeRouteUpdate、
beforeRouteLeave
每个钩子方法接收三个参数:
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。 执行效果依赖 next 方法的调用参数。
router 的区别是什么?
$router 为 VueRouter 的实例, 是一个全局路由对象, 包含了路由跳转的方法、 钩子函数等。
$route 是路由信息对象||跳转的路由对象, 每一个路由都会有一个 route 对象, 是一个局部对象包含path,params,hash,query,fullPath,matched,name 等路由信息参数。
页面导航方式
声明式导航beforeEnter:通过点击链接实现导航的方式,叫做声明式导航 例如:普通网页中的 <a></a> 链接 或 vue 中的 <router-link></router-link>
编程式导航:通过调用JavaScript形式的API实现导航的方式,叫做编程式导航 例如:普通网页中的 location.href
编程式导航基本用法
常用的编程式导航 API 如下
this.$router.push('hash地址')
this.$router.go(n)
router.push() 方法的参数规则
// 字符串(路径名称)
router.push('/home')
// 对象
router.push({ path: '/home' })
// 命名的路由(传递参数)
router.push({ name: '/user', params: { userId: 123 }})
// 带查询参数,变成 /register?uname=lisi
router.push({ path: '/register', query: { uname: 'lisi' }})
Hash模式与History模式
表现形式上的区别:
Hash模式:hash模式中路径带有#, #后面的内容作为路由地址。可以通过问号携带参数。
当然这种模式相对来说比较丑,路径中带有与数据无关的符号,例如#与?
History模式:是一个正常的路径的模式,如果要想实现这种模式,还需要服务端的相应支持
原理上的区别:
Hash模式是基于锚点,以及onhashchange事件。
通过锚点的值作为路由地址,当地址发生变化后触发onhashchange事件。
History模式是基于HTML5中的History API
也就是如下两个方法
history.pushState( ) IE10以后才支持
history.replaceState( )
active-class 是哪个组件的属性? 嵌套路由怎么定义?
vue-router 模块的 router-link 组件的属性。
嵌套路由:
嵌套路由顾名思义就是路由的多层嵌套。
重构 router/index.js 的路由配置, 需要使用 children 数组来定义子路由 .
路由定义:
{\
path: '/me',\
name: 'Me',\
component: Me,\
children: [\
{\
path: 'collection',\
name: 'Collection',\
component: Collection\
},\
{\
path: 'trace',\
name: 'Trace',\
component: Trace\
}\
]\
}\
以“/”开头的嵌套路径会被当作根路径, 所以子路由上不用加“/”;\
在生成路由时, 主路由上的 path 会被自动添加到子路由之前, 所以子路由上的 path 不用在\
重新声明主路由上的 path 了。\
在外层路由组件中, 如下写法。\
<template>\
<div class="me">\
<div class="tabs">\
<ul>\
<!--<router-link :to="{name: 'Default'}" tag="li" exact>默认内容</router-link>-->\
<router-link :to="{name: 'Collection'}" tag="li" >我的收藏</router-link>\
<router-link :to="{name: 'Trace'}" tag="li">我的足迹</router-link>\
</ul>\
</div>\
<div class="content">\
<router-view></router-view>\
</div>\
</div>\
vuex
什么是vuex
不适用vuex会带来什么问题
一、 可维护性会下降, 你要想修改数据, 你得维护三个地方
二、 可读性会下降, 因为一个组件里的数据, 你根本就看不出来是从哪来的
三、 增加耦合, 大量的上传派发, 会让耦合性大大的增加, 本来 Vue 用 Component 就是为了减少耦合, 现在这么用, 和组件化的初衷相背。
vuex有哪几种属性
有五种, 分别是 State、 Getter、 Mutation 、 Action、 Module。
State
一、 Vuex 就是一个仓库, 仓库里面放了很多对象。 其中 state 就是数据源存放地, 对应于与一般 Vue 对象里面的 data。
二、state 里面存放的数据是响应式的, Vue 组件从 store 中读取数据, 若是 store中的数据发生改变, 依赖这个数据的组件也会发生更新。
三、 它通过 mapState 把全局的 state 和 getters 映射到当前组件的 computed 计算属性中。
Getter
一、 getters 可以对 State 进行计算操作, 它就是 Store 的计算属性
二、 虽然在组件内也可以做计算属性, 但是 getters 可以在多组件之间复用
三、 如果一个状态只在一个组件内使用, 是可以不用 getters
Mutation
状态数据的修改必须提交Mutaion,并且Mutaion的修改必须是同步执行的
Action
如果需要执行异步操作,我们需要通过Action来完成。如果异步执行完毕后,需要修改状态,需要提交Mutation来修改State状态。因为所有的状态的修改都需要通过Mutation来完成
一、 Action 类似于 mutation, 不同在于:
二、 Action 提交的是 mutation, 而不是直接变更状态。
三、 Action 可以包含任意异步操作
Module
如果我们把所有的状态都存储到了State中,后期会变得非常难维护,Store也就变得非常臃肿,为了解决这个问题,Vuex允许我们将Store分隔成模块。每一个模块都有自己的State,Mutation,Action,Getter等。当状态内容非常多的时候,Module是非常有用的.
Vue.js 中 ajax 请求代码应该写在组件的 methods 中还是 vuex 的 actions 中?
一、 如果请求来的数据是不是要被其他组件公用, 仅仅在请求的组件内使用, 就不需要放入 vuex 的 state 里。
二、 如果被其他地方复用, 这个很大几率上是需要的, 如果需要, 请将请求放入action 里, 方便复用, 并包装成 promise 返回, 在调用处用 async await 处理返回的数据。 如果不要复用这个请求, 那么直接写在 vue 文件里很方便。
虚拟DOM
VNode 是什么? 虚拟 DOM 是什么?
包括几个步骤:
1、用 JavaScript 对象结构表示 DOM 树的结构, 然后用这个树构建一个真正的 DOM 树,插到文档当中;
2、当状态变更的时候, 重新构造一棵新的对象树, 然后用新的树和旧的树进行比较, 记录两棵树差异;
3、把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上, 视图就更新了。\
Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。 可以类比 CPU 和硬盘, 既然硬盘这么慢, 我们就在它们之间加个缓存: 既然 DOM 这么慢, 我们就在它们 JS 和 DOM 之间加个缓存。 CPU(JS) 只操作内存(Virtual DOM), 最后的时候再把变更写入硬盘(DOM)。
Vue 在 页面上渲染的节点, 及其子节点称为“虚拟节点 (Virtual Node)”, 简写为“VNode”。“虚拟 DOM” 是由 Vue 组件树建立起来的整个 VNode 树的称呼。
说下对 Virtual DOM 算法的理解
vue 脚手架(vue.cli)
请说出 vue.cli 项目中 src 目录每个文件夹和文件的用法?
assets 文件夹是放静态资源;
components 是放组件;
router 是定义路由相关的配置;
view 视图;
app.vue 是一个应用主组件;
main.js 是入口文件
vue.cli 中怎样使用自定义的组件? 有遇到过哪些问题吗?
第一步: 在 components 目录新建你的组件文件(smithButton.vue), script 一定要 export default
{ 第二 步 : 在 需 要 用 的 页 面 ( 组 件 ) 中 导 入 : import smithButton from ‘ …
/components/smithButton.vue’
第三步: 注入到 vue 的子组件的 components 属性上面,components:{smithButton}
第四步: 在 template 视图 view 中使用,
问题有: smithButton 命名, 使用的时候则 smith-button。\
.vue-cli 创建自定义组件
1、 新建一个.vue 文件 (一般 IDE 会自动生成 script export default )
2、 编写 dom, 组件的 name 使用短横线分隔(component-name) 方式。
3、 在需要的页面 import componentName from ‘…’
4、 组件注册, compontens :{ [componentName.name]: componentName}
5、 在需要的页面 template 中显示\