1. mvc和mvvm模式的区别
- mvc包括view视图层、controller控制层、model数据层。各部分之间的通信都是单向的。
过程是这样的,首先view传送指令到controller完成业务逻辑后,要求model改变状态,model将新的数据发送到view,用户得到反馈
- MVVM是Model-View-ViewModel的缩写
- Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑
- View代表ui组件,它负责将数据模型转化成UI展现出来
- 本来View和model之间并没有直接的联系,而是通过ViewModel进行交互,view和viewmodel以及model和viewmodel之间的通信是双向的,因此view数据的变化会同步到model中,而model数据的变化也会立即反应到view上;ViewModel的作用是监听模型数据的改变和控制视图行为、处理用户交互,连接Model和View。
- ViewModel通过双向数据绑定把view层和model层连接起来,而view和model之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动去操作DOM。不需要关注数据状态的同步问题,这就是vue框架为我们做的事情。
2. vue实现双向数据绑定的原理?
答:Vue是采用数据劫持结合发布/订阅模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter这两个访问器属性,所谓的访问器属性就是可以获取值和设置值的函数,在数据变动时发布消息给订阅者,触发相应的监听回调,从而实现双向数据绑定。个人的理解就是,我们在new vue的时候,在数据监听器Observe中通过Object.defineProperty()达到数据劫持,监听所有数据的getter和setter这两个访问器属性,在每次触发setter的时候,数据监听器Observer发布消息给Dep,Dep就像一个依赖管理,来通知Watcher,而这个Watcher能够连接数据监听器Observer和Compile模板解析器之间的桥梁,当Observer监听到数据发生变化的时候,通过Watcher中调用自身的Updater()方法来通知Compile来绑定响应的更新回调函数,同时向Dep添加订阅者,更新view视图从而实现双向绑定。
可参考:https://www.cnblogs.com/canfoo/p/6891868.html
3. v-if和v-show区别
答:v-if和v-show在页面都展示为显示隐藏,但是两者有区别:
- v-if当值为true时,显示绑定了指令的元素,当值为false的时候,该元素消失,我们打开控制台查看代码的时候,可以看到代码也会消失,相当于将代码删除了,当从false变为true时,页面会重新渲染绑定了该指令的元素。
- v-show 控制隐藏的出现,只是将绑定了该指令的元素的css属性设置为了display:none
由此我们可以知道,v-if有更高的切换消耗,不适合做频繁的切换;v-show 有更高的初始渲染消耗,适合做频繁的切换,但对页面初始加载的速度有影响
4. export与export default的区别
这两个都是导出的方式,均可以导出模块、函数等。
- 在一个文件中,export可以有多个,但是export default仅有一个
- export方式导出,在导入时要加{},export default默认导出的就是一个对象,所以不需要加{}
5. vue和react有哪些不同,说说你对这两者框架的看法
- vue是双向数据绑定,而react是单项数据绑定
- 组件写法不一样,vue组件的写法是将html、css、js写在同一个vue文件中,即单文件组件格式;而react是将html、css全部写进javascript
- 在vue中,state对象不是必须的,;而react中的state对象是不可变的,需要使用setState()方法更新状态
- 虚拟Dom不一样,vue会追踪每一个组件的依赖关系,当不需要重新渲染整个组件树的时候会复用,而react每当应用的状态被改变时,全部组件都会重新渲染
- vue主要适用于pc端和移动端,但是react除了适用于pc端移动端,同时几乎兼容所有需要前端界面的端
相同点:都支持组件化,都是数据驱动view视图层的变化
看法:
- vue上手容易,react上手难度较难,也因此vue能在短期内完成较高的开发效率
- 当工程规模较大时,双向数据绑定会很难维护,vue不太适合大型的工程的开发
6. vue的生命周期
- 什么是vue的生命周期
答:vue实例从创建到销毁的过程,就称之为vue的生命周期。 - vue生命周期的作用是什么
答:它的生命周期有多个生命周期钩子函数,可以让我们在控制整个vue实例的过程时更容易形成好的逻辑 - vue生命周期总共粉来几个阶段?
答:它可以总共分为8各阶段,创建前/创建后,挂载前/挂载后,更新前/更新后,销毁前/销毁后 - 第一次页面加载会触发那几个钩子?
答:会触发beforeCreat、creat、beforeMounted、mounted - created()和mounted()的区别
答:created()最早使用data中的数据,而mounted()最早操作dom节点的函数 - DOM渲染在那个周期中就已经完成?
- 答:DOM渲染在mounted中就已经完成
beforeCreate
创建实例之前
在初始化的时候调用了beforeCreate,完成了vue实例的生命周期、相关属性的初始化以及事件的 初始化。这个时候还不能直接访问data中的属性及method中的方法
created
实例创建好了,可以访问数据模型中的数据
在初始化完毕以后,完成了vue的数据注入及数据监听操作,该钩子的执行意味着vue实例创建 完毕,可以进行数据的访问操作
beforeMount
挂载之前
在created之后,vue会判断实例中是否含有el属性,如果没有会调用vm.$mount(el) ,接着会判 断是否含有template属性,如果有将其解析为一个render function ,如果没有将el绑定到指定的 外部html进行解析。这里只是完成了模板的解析但是数据并没有绑定到模板中
mounted
挂载之后
创建vm.$el替换el,实际上这里完成的是数据和dom节点的绑定操作,在期间执行了render函数,将模板进 行了解析,将数据进行了动态绑定
beforeUpdate
当data中的数据发生改变的时候会被调用,内存中的数据已经发生改变,但是页面还是旧的
更新虚拟dom节点
updated
更新好了
内存中的数据已经和页面同步起来,完成了页面的重新渲染
beforeDestroy
vue实例销毁之前
销毁之前调用,此时还是可以访问vue实例的
destroyed
vue实例销毁完毕
完成了监听器,子组件,事件监听等移除,销毁vue实例对象
7. vue组件间的参数传递
- 父组件与子组件传值
答:
- 父组件传给子组件时通过子组件props属性来接收父组件传递过来的值
具体实现:父组件通过import引入子组件,并注册,在子组件标签上添加要传递的属性,子组件通过props属性接受,接受有了两种两种形式,第一个是通过数组形式[“要接受的属性”],而是通过对象的形式{}来接受,对象形式可以设置要传递的数据类型和默认值,而数组只是简单的接受从父组件传递过来的数据
- 子组件传给父组件:通过$emit来实现
在子组件通过绑定事件触发函数,在其中设置this.$emit(“要派发的自定义事件”,要传递的值),第一个参数为要派发的自定义事件,第二个参数放要传递给父组件的数据。
- 非父子组件间的数据传递,兄弟组件之间的传值
答:
- 通过eventBus,eventBus就是创建一个事件中心,用它来传递事件和接受事件即通过传递事件的传参和接受数据参数要实现数据的传递,即,我们可以这样创建一个空的vue并暴露出去,这个作为公共的bus,即当做这两个组件的桥梁,在两个兄弟组件中分别引入刚才创建好的bus,在组件A中通过bus. e m i t ( " 自 定 义 事 件 名 " , 要 传 递 的 数 据 ) 发 送 数 据 , 在 组 件 B 中 通 过 b u s . emit("自定义事件名",要传递的数据)发送数据,在组件B中通过bus. emit("自定义事件名",要传递的数据)发送数据,在组件B中通过bus.on(“自定义事件名”,function(v){//v即为要接受的值})接受数据
- 我喜欢用vuex来,通过state管理数据,利用…mapGetters()映射函数来拿到vuex管理的数据
8. css只在当前组件起作用
答:在style标签中写入scoped即可,例如<style scoped></style>
9. r o u t e 和 route和 route和router的区别
答: r o u t e 是 " 路 由 信 息 对 象 " , 包 括 p a t h 、 p a r a m s 、 h a s h 、 q u e r y 、 f u l l P a t h 等 路 由 信 息 参 数 。 而 route是"路由信息对象",包括path、params、hash、query、fullPath等路由信息参数。而 route是"路由信息对象",包括path、params、hash、query、fullPath等路由信息参数。而router是"路由实例"对象包括了路由的跳转方法、钩子函数等
10.vue.js的两个核心?
答:数据驱动、组件系统
11.vue常用的修饰符?
答:
- .prevent 表示提交事件不再重载页面;
- .stop 表示阻止单击事件冒泡
- .self 表示当事件发生在该元素本身而不是子元素的适合会触发
12.vue中key值得作用?
答:当vue.js用v-for正在更新已经渲染过得元素列表时,它默认用"就地复用"策略。所以key得作用主要时为了高效得更新虚拟DOM
13.keep-alive的了解?
答:当组件在切换的时候都会重新创建组件,但是有些时候我们希望组件实例能够被 在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 <keep-alive>
元素将其 动态组件包裹起来,keep-alive是vue内置的一个组件,可以使得包含的组件保留状态,或避免重新渲染。
keep-alive有两个属性
- include(包含的组件缓冲) 参数值可以为字符串或者正则表达式,只有名称匹配的组件会被缓存
- exclude(排除的组件不缓存) 参数值可以为字符串或正则表达式,任何名称匹配的组件都不会被缓冲
<keep-alive include="include_components" exclude="exclude_components">
<component></component>
</keep-alive>
14.vue中的data为什么必须是一个函数?
答:Objcet是引用数据类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了那么其他的也会跟着改变。;而
data是一个函数时,每个组件实例都有自己的作用域,即函数作用域,每个实例相互独立,不会相互影响。
15.watch、computed和methods的区别
答:
- computed 表示计算属性,它俄共多用于计算值的场景,computed的值在getter执行后是会被缓存的,只有在它依赖的属性值改变之后,才会冲新计算,可以利用setter函数来修改data中的数据
- watch 表示监听属性,更多的时观察的作用,类似于某些的监听回调,用于观察组件等的值,当数据变换时来执行回调进行后续操作,结果不会缓存
基于上述,可以知道:当我们需要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed属性,如果需要在某个数据变化时做一些事件,使用watch来观察这个数据的变化 - method 表示事件方法,调用一次就会执行一次,结果不会缓存
16.Vuex?
答:
-
定义:vuex是一个专为vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以响应的规则保证状态以一种可预测的方式发生变化。而我的理解就是vuex就是管理组件之间公共数据的数据仓库,我们可以从这个仓库拿取组件所需要的公共状态数据。
-
优点:当你在state中定义了一个数据之后,可以在所在的项目中的任何一个组件里获取、进行修改,并且你的修改可以得到全局的响应变更。
-
vuex的运行机制:在组件中通过this.$store.dispatch来调用action中的方法,在action中通过commit来调用mutataions中的方法,在mutataion的方法中操作state中的数据,数据只要更新就会立即响应到组件上。
-
核心:
- state:定义初始数据
- getters:可以对state进行计算操作,类似computed属性。
- mutations:更改vuex中的store中的状态的唯一方法就是提交mutation
- actions:可以通过dispatch来分发action中的方法,异步操作初始数据,其实就是调用了mutataions里面的方法。
- module:面对复杂应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块
modules: { // 子vuex状态模块注册
namespaced: true, // 为了解决不同模块命名冲突的问题
app,
bus
}
17.vue路由模式
答:在vue-router路由对象中,路由有两种模式:hash和history,默认的时hash模式
- hash路由原理:
通过onhashchange来检测hash的变化,然后通过location.hash来获取当前的hash值,从而根据hash的变化来控制元素的显示和隐藏
- history路由原理:
通过onpopstate来检测浏览器历史堆栈的变化,然后通过history.pushState(“路径”,null,“参数”)向历史堆栈中添加信息
18.vue-router传递参数
比如在路由配置对象中有这样一个路由为:
{
path:'/demo',
name:'demo',
component:demo
}
答:
(1)编程式的导航,通过router.push
来实现
-
- 命名路由搭配params,传递的参数不会显示在地址栏中,传递的数据在刷新页面会丢失,具体实现:
在路由配置了路由命名,如
name:'demo'
,这时候传递参数就可以使用params来传递,在传递参数的这个路由中调用路由对象的push方法this.$router.push({name:'demo',params:{id:15}})
,在接受参数的路由中调用路由信息对象this.$route.params.id
来获取到传递过来的id值
- 查询参数搭配query,传递的参数会显示在地址栏中,刷新页面数据不会丢失。具体实现:
在传递参数的这个路由中调用路由对象的push方法
this.$router.push({path:'demo',query:{id:15}})
,在接受参数的路由中调用路由信息对象this.$route.query.id
来获取传递过来的id值
- 在配置路由对象的path上使用动态参数如,
path:/login/:id
,在调用路由对象中push方法this.$router.push({path:
/login/${id}})
来传递参数,在需要接受参数的路由中调用路由信息对象中this.route.params.id
来获取传递过来的值。会暴露参数值在地址栏中
(2)声明式的导航 <router-link>
这种方式和编程式的导航传递参数类似,只是将参数传递放在了<router-link>
中的to
属性上
-
<router-link :to="{ name: 'news', params: { id: 15}}">click to news page</router-link>
,在跳转的路由中调用路由信息对象this.$route.params.id
来获取传递过来的id值
-
<router-link :to="{ path: '/news', query: { id: 15}}">click to news page</router-link>
,在跳转的路由中调用路由信息对象this.$route.query.id
来获取传递过来的id值
19.v-for与v-if的优先级
答:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其当需要渲染很小一部分的时候。
20.vue指令
-
v-bind
:给元素绑定属性 -
v-on
:给元素绑定事件 -
v-model
:数据双向绑定 -
v-for
:遍历数组 -
v-show
:条件渲染指令,将不符合条件的数据隐藏(display:none)
-
v-if
:条件渲染指令,动态在DOM内添加或删除DOM元素 -
v-else
:条件渲染指令,必须跟v-if成对使用 -
v-else-if
:判断多层条件,必须跟v-if成对使用 -
v-once
:只渲染元素或组件一次 -
v-html:给元素绑定数据,且该指令可以解析html标签
-
v-text:给元素绑定数据,但不解析标签
21.vue-router有哪几种导航钩子
答:vue-router提供的导航守卫主要用来跳转或取消的方式守卫导航。导航表示路由正在发生变化;有多种方式植入路由导航的过程:
这些路由导航守卫,都具有三大参数:to
表示即将要进入的目标路由对象;from
表示当前导航正要离开的路由;next
一定要调用该方法来resolve(解析)
- 全局守卫:一般用来判断权限,以及页面丢失式需要执行的操作;
- beforeEach() 全局前置守卫,表示每次路由进入之前执行的函数
- afterEach() 全局后置守卫,表示每次路由进入之后执行的函数
- 组件内守卫:在路由组件内直接定义路由导航守卫称之为组件内守卫
- beforeRouterEnter()
- beforeRouterUpdate()
- beforeRouteLeave() 这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过next(false)来取消
- 路由独享守卫 :指某个指定路由跳转时需要执行的逻辑。即在路由配置上直接定义beforeEach()或afterEach()
22.如何解决vue的跨域问题
答:我是使用http-proxy-middleware
这个中间件,即在用vue-cli脚手架搭建的vue项目中,找到vue.confihg.js
这个文件,先导入这个中间件,然后在中这样设置
module.exports = {
devSever:{
proxy:"要转发到的实际的url地址"
}
}
设置完成后,重启服务即可生效。
23. v-if和v-for一起使用的弊端以及解决办法
由于v-for的优先级比v-if高,所以导致每循环一次都会去v-if一次。而v-if是通过创建和销毁dom元素来控制元素的显示和隐藏的,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。
- 解决办法:在v-for的外层或内层包裹一个元素来使用v-if