什么是MVVM?
MVVM详解
mvvm和mvc区别?它和其它框架(jquery)的区别是什么?哪些场景适合?
mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
区别:vue数据驱动,通过数据来显示视图层而不是节点操作。
场景:数据操作比较多的场景,更加便捷
vue的优点是什么?
- 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
- 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
- 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
- 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
- vue两大特点:响应式编程、组件化
- vue的优势:轻量级框架、简单易学、双向数据绑定、组件化、视图、数据和结构的分离、虚拟DOM、运行速度快
组件之间的传值?
父组件与子组件传值
父组件通过标签上面定义传值
子组件通过props方法接受数据
子组件向父组件传递数据
子组件通过$emit方法传递参数
路由之间跳转
声明式(标签跳转) 编程式( js跳转)
vue.cli中怎样使用自定义的组件?有遇到过哪些问题吗?
- 第一步:在components目录新建你的组件文件(indexPage.vue),script一定要export default {}
- 第二步:在需要用的页面(组件)中导入:import indexPage from '@/components/indexPage.vue'
- 第三步:注入到vue的子组件的components属性上面,components:{indexPage}
第四步:在template视图view中使用,
例如有indexPage命名,使用的时候则index-page
vue如何实现按需加载配合webpack设置
webpack中提供了require.ensure()来实现按需加载。以前引入路由是通过import 这样的方式引入,改为const定义的方式进行引入。
不进行页面按需加载引入方式:import home from '../../common/home.vue'
进行页面按需加载的引入方式:const home = r => require.ensure( [], () => r (require('../../common/home.vue')))
vuex面试相关
(1)vuex是什么?怎么使用?哪种功能场景使用它?
vue框架中状态管理。在main.js引入store,注入。新建一个目录store,….. export 。场景有:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车
(2)vuex有哪几种属性?
有五种,分别是 State、 Getter、Mutation 、Action、 Module
-
vuex的State特性
A、Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于一般Vue对象里面的data
B、state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新
C、它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
-
vuex的Getter特性
A、getters 可以对State进行计算操作,它就是Store的计算属性
B、 虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用
C、 如果一个状态只在一个组件内使用,是可以不用getters
-
vuex的Mutation特性
Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态;Action 可以包含任意异步操作。
(3)不用Vuex会带来什么问题?
- 可维护性会下降,想修改数据要维护三个地方;
- 可读性会下降,因为一个组件里的数据,根本就看不出来是从哪来的;
- 增加耦合,大量的上传派发,会让耦合性大大增加,本来Vue用Component就是为了减少耦合,现在这么用,和组件化的初衷相背。
v-show和v-if指令的共同点和不同点
- v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏
- v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果
如何让CSS只在当前组件中起作用
将当前组件的<style>修改为<style scoped>
的作用是什么?
<keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
Vue中引入组件的步骤?
1)采用ES6的import ... from ...语法或CommonJS的require()方法引入组件
2)对组件进行注册,代码如下
// 注册
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
3)使用组件
<my-component></my-component>
指令v-el的作用是什么?
提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标.可以是 CSS 选择器,也可以是一个 HTMLElement 实例
在Vue中使用插件的步骤
- 采用ES6的import ... from ...语法或CommonJS的require()方法引入插件
- 使用全局方法Vue.use( plugin )使用插件,可以传入一个选项对象Vue.use(MyPlugin, { someOption: true })
请列举出3个Vue中常用的生命周期钩子函数
- created: 实例已经创建完成之后调用,在这一步,实例已经完成数据观测, 属性和方法的运算, watch/event事件回调. 然而, 挂载阶段还没有开始, $el属性目前还不可见
- mounted: el被新创建的 vm.el 也在文档内。
- activated: keep-alive组件激活时调用
active-class是哪个组件的属性?
vue-router模块的router-link组件。
怎么定义vue-router的动态路由以及如何获取传过来的动态参数?
在router目录下的index.js文件中,对path属性加上/:id。
使用router对象的params.id。
vue-router有哪几种导航钩子?
三种,一种是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。
第二种:组件内的钩子;
第三种:单独路由独享组件
生命周期相关面试题
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
- 创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el还没有。
- 载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
- 更新前/后:当data变化时,会触发beforeUpdate和updated方法。
- 销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
(1)、什么是vue生命周期
答: Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
(2)、vue生命周期的作用是什么
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
(3)、vue生命周期总共有几个阶段
答:可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后
(4)、第一次页面加载会触发哪几个钩子
答:第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
(5)、DOM 渲染在 哪个周期中就已经完成
答:DOM 渲染在 mounted 中就已经完成了。
(6)、简单描述每个周期具体适合哪些场景
答:生命周期钩子的一些使用方法:
- beforecreate : 可以在这加个loading事件,在加载实例时触发
- created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
- mounted : 挂载元素,获取到DOM节点
- updated : 如果对数据统一处理,在这里写上相应函数
- beforeDestroy : 可以做一个确认停止事件的确认框
- nextTick : 更新数据后立即操作dom
说出至少4种vue当中的指令和它的用法?
v-if:判断是否隐藏;v-for:数据循环;v-bind:class:绑定一个属性;v-model:实现双向绑定
vue-loader是什么?使用它的用途有哪些?
解析.vue文件的一个加载器。
用途:js可以写es6、style样式可以scss或less、template可以加jade等
scss是什么?在vue.cli中的安装使用步骤是?有哪几大特性?
答:css的预编译。
使用步骤:
第一步:先装css-loader、node-loader、sass-loader等加载器模块
第二步:在build目录找到webpack.base.config.js,在那个extends属性中加一个拓展.scss
第三步:在同一个文件,配置一个module属性
第四步:然后在组件的style标签加上lang属性 ,例如:lang=”scss”
特性:
- 可以用变量,例如($变量名称=值);
- 可以用混合器,例如()
- 可以嵌套
为什么使用key?
当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。
二十四、为什么避免 v-if 和 v-for 用在一起
当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级,通过v-if 移动到容器元素,不会再重复遍历列表中的每个值。取而代之的是,我们只检查它一次,且不会在 v-if 为否的时候运算 v-for。
二十五、VNode是什么?虚拟 DOM是什么?
Vue在 页面上渲染的节点,及其子节点称为“虚拟节点 (Virtual Node)”,简写为“VNode”。“虚拟 DOM”是由 Vue 组件树建立起来的整个 VNode 树的称呼。
对vue的理解
Vue是一套用于构建用户界面的渐进式框架,轻量级,没有强主张(主张性少), 也能完美地驱动复杂的单页应用。vue.js在设计上也使用 mvvm模式。
渐进式框架个人理解:不做职责之外的事情。
Vue的生命周期
创建:
beforeCreate(创建前) 在数据观测和初始化事件还未开始
created(创建后) 完成数据观测,属性和方法的运算,初始化事件,el属性还没有显示出来。挂载:beforeMount(载入前)在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。mounted(载入后)在el被新创建的vm. el属性还没有显示出来。挂载:beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。mounted(载入后) 在el 被新创建的 vm.el属性还没有显示出来。挂载:beforeMount(载入前)在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。mounted(载入后)在el被新创建的vm.el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
修改:
beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
销毁:
beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
1.什么是vue生命周期?
答: Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。
2.vue生命周期的作用是什么?
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
3.vue生命周期总共有几个阶段?
答:它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。
4.第一次页面加载会触发哪几个钩子?
答:会触发 下面这几个beforeCreate, created, beforeMount, mounted 。
5.DOM 渲染在 哪个周期中就已经完成?
答:DOM 渲染在 mounted 中就已经完成了。
四.Vue实现双向数据绑定的原理
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。
对 MVC、MVP 、MVVM 的理解
MVC 模式的意思是,软件可以分成三个部分。
视图(View):用户界面。
控制器(Controller):业务逻辑。
模型(Model):数据保存。
各部分之间的通信方式如下。View 传送指令到 Controller,Controller 完成业务逻辑后,要求 Model 改变状态,Model 将新的数据发送到 View,用户得到反馈,所有通信都是单向的(逆时针)。
MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。各部分之间的通信,都是双向的(顺时针)。View 与 Model 不发生联系,都通过 Presenter 传递。View 非常薄,不部署任何业务逻辑,称为 “被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。唯一的区别是,它采用双向绑定(data-binding):View 的变动,自动反映在 ViewModel,反之亦然。Angular 和 Ember 都采用这种模式。
如何理解 Vue 是异步执行 DOM 更新的 ?
Vue 是异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环 tick 中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。例如,当你设置 vm.someData = ‘new value’ ,该组件不会立即重新渲染。
当刷新队列时,组件会在事件循环队列清空时的下一个 tick 更新。多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着 “数据驱动” 的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。
v-if和v-show有什么区别
v-if用于操作Dom是否渲染,而v-if操作的则是display属性,v-if的有更高的切换开销,v-show有更大的初始渲染开销,所以,如果需要频繁切换,使用v-show比较好,而如果渲染条件改变次数少,则v-if更好
计算属性和watch的区别及使用场景
computed计算属性是用来声明式的描述一个值依赖了其它的值。当你在模板里把数据绑定到一个计算属性上时,Vue 会在其依赖的任何值导致该计算属性改变时更新 DOM。这个功能非常强大,它可以让你的代码更加声明式、数据驱动并且易于维护。 // 计算属性computed,计算的是Name依赖的值,它不能计算在data中已经定义过的变量。
watch监听的是你定义的变量,当你定义的变量的值发生变化时,调用对应的方法。// 当num的值发生变化时,就会调用num的方法,方法里面的形参对应的是num的新值和旧值
- 一个数据属性在它所依赖的属性发生变化时,也要发生变化,这种情况下,我们最好使用计算属性。
- watch函数适用于,当数据发生变化时,执行异步操作或较大开销操作的情况。
双向绑定 – Object.defineProperty()
vue实现数据双向绑定主要是:
采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty() 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue追踪依赖,在属性被访问和修改时通知变化。
vue路由hash模式与history模式的区别
- hash模式
-
路由的哈希模式其实是利用了window可以监听onhashchange事件,也就是说你的url中的哈希值(#后面的值)如果有变化,前端是可以做到监听并做一些响应(搞点事情),这么一来,即使前端并没有发起http请求他也能够找到对应页面的代码块进行按需加载。
后来人们给他起了一个霸气的名字叫前端路由,成为了单页应用标配。
- history模式
-
我们先介绍一下H5新推出的两个神器:pushState与replaceState
具体自行百度,简而言之,这两个神器的作用就是可以将url替换并且不刷新页面,好比挂羊头卖狗肉,http并没有去请求服务器该路径下的资源,一旦刷新就会暴露这个实际不存在的“羊头”,显示404。
那么如何去解决history模式下刷新报404的弊端呢,这就需要服务器端做点手脚,将不存在的路径请求重定向到入口文件(index.html),前后端联手,齐心协力做好“挂羊头卖狗肉”的完美特效。
总之,pushState方法不会触发页面刷新,只是导致history对象发生变化,地址栏会有反应。
history模式下,build之后本地 index.html 打开是无效的。
hash模式下,build之后本地 index.html 打开正常!
大牛回答:hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。那么什么时候要用history模式呢?如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传。当然其功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人员配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦。
$route 和 $router的区别
- $route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
- 而$router是“路由实例”对象包括了路由的跳转方法,钩子函数等
路由跳转
- 编程式( js跳转)this.$router.push()
- 声明式(标签跳转)
<router-link to=""></router-link>
路由的懒加载
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const routes = [
{
path:'/',
component:resolve => require(['@/components/First'],resolve)
},
{
path:'/first',
component:resolve => require(['@/components/First'],resolve)
},
{
path:'/second',
component: resolve => require(['@/components/Second'],resolve)
}
]
//最后创建router 对路由进行管理,它是由构造函数 new vueRouter() 创建,接受routes 参数。
const router = new VueRouter({
routes
})
export default router;
按需加载会在页面第一次请求的时候,把相关路由组件块的js添加上;非按需加载则会把所有的路由组件块的js包打在一起。当业务包很大的时候建议用路由的按需加载(懒加载)。
vue-router解决的问题
- 监听URL的变化,并在变化前后执行相应的逻辑
- 不同的URL对应不同的组件
- 提供多种方式改变URL的API(URL的改变不能导致浏览器刷新)
v-if 和 v-show 的区别
- v-if按照条件是否渲染,v-show是display的block或none;
- v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
在Vue中使用插件的步骤
- 采用ES6的import … from …语法或CommonJS的require()方法引入插件
- 使用全局方法Vue.use( plugin )使用插件,可以传入一个选项对象Vue.use(MyPlugin, { someOption: true })
vue-cli 工程技术集合介绍
使用技术
- vue.js:vue-cli工程的核心,主要特点是 双向数据绑定 和 组件系统。
- vue-router:vue官方推荐使用的路由框架。
- vuex:专为 Vue.js 应用项目开发的状态管理器,主要用于维护vue组件间共用的一些 变量 和 方法。
- axios( 或者 fetch 、ajax ):用于发起 GET 、或 POST 等 http请求,基于 Promise 设计。
- vuex等:一个专为vue设计的移动端UI组件库。
- 创建一个emit.js文件,用于vue事件机制的管理。
- webpack:模块加载和vue-cli工程打包器。
vue-cli配置反向代理
vue-cli提供了配置反向代理的接口,即设置config/index.js中的proxyTable。配置如下:
dev: {
......
proxyTable: {
'/api':{ //将www.exaple.com印射为/apis
target:'https://www.exaple.com', //跨域地址
changeOrigin:true, //是否跨域
secure:false, //是否使用https
pathRewrite: {
'^/api': '/api' //匹配以/api为开头的请求地址,并使用/api替换
}
}
}
}
对反向代理解决跨域过程的理解
通过伪造请求使得http请求为同源的,然后将同源的请求发送到反向代理服务器上,由反向代理服务器去请求真正的url,这样就绕过直接请求真正的url导致跨域问题。
Vue 组件 data 为什么必须是函数
- 每个组件都是 Vue 的实例。
- 组件共享 data 属性,当 data 的值是同一个引用类型的值时,改变其中一个会影响其他
v-if和v-for可以一起使用吗?为什么?
可以是可以,但是不推荐,一起使用会导致性能上的下降;因为v-for比v-if具有更高的权重,所以会先解析v-for,然后在进行v-if判断,这就导致每一次循环迭代都要进行一次判断;解决方案:可以在父元素进行v-if判断,或者使用计算属性将数组进行过滤。
在页面来回切换之间,怎么让页面不重复发生网络请求?
可以使用keep-alive标签包裹在router-view路由出口里
指令keep-alive
在vue-router写着keep-alive,keep-alive的含义:
如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。为此可以添加一个keep-alive指令
<component :is='curremtView' keep-alive></component>
Vue.js特点
简洁:页面由HTML模板+Json数据+Vue实例组成
数据驱动:自动计算属性和追踪依赖的模板表达式
组件化:用可复用、解耦的组件来构造页面
轻量:代码量小,不依赖其他库
快速:精确有效批量DOM更新
vue-router 有哪几种导航钩子?
全局导航钩子
router.beforeEach(to, from, next),
router.beforeResolve(to, from, next),
router.afterEach(to, from ,next)
组件内钩子
beforeRouteEnter,
beforeRouteUpdate,
beforeRouteLeave
单独路由独享组件
beforeEnter
vuex 的mutation和action的特性是什么?有什么区别?
mutation用于修改state的数据,是同步的。
action 类似于 muation, 不同在于:action 提交的是 mutation,而不是直接变更状态
action 可以包含任意异步操作
computed 和 watched 的区别:
computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容。
watch 监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。
所以一般来说需要依赖别的属性来动态获得值的时候可以使用 computed,对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用 watch。