一、概念类
- vue.js是什么?
vue.js是一个构建用户界面的渐进式框架。 - 怎么理解渐进式?
主张少,没有那么多硬性规定。例如:angular必须使用它的模块机制,依赖注入、react的函数式编程理念。 - 什么是MVVM?
MVVM是Model View ViewModel的缩写,Model是数据模型,View是视图,它们之间没有联系,是通过ViewModel来交互的。ViewModel层不需要我们去维护,由Vue统一管理。Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
image.png
什么是MVC?
View 传送指令到 Controller ---> Controller 完成业务逻辑后,要求 Model 改变状态 ----> Model 将新的数据发送到 View,用户得到反馈
image
二、vue生命周期
什么是Vue的生命周期
从vue开始创建实例到销毁的这个过程就是叫vue的生命周期。包括开始创建、初始化数据、渲染页面、销毁都是vue的生命周期。vue生命周期的作用
在这个生命周期的过程中会有很多生命周期函数,可以通过操作这些生命周期函数来控制逻辑。生命周期函数
创建前/后, 载入前/后,更新前/后,销毁前/销毁后。
beforeCreate("new Vue之前")、created("new Vue之后")、beforeMounted("el之前")、mounted("有了el之后")、beforedUpdate("更新数据之前")、updated("更新数据之后")、beforeDestroy("销毁之前")、destoryed("销毁之后")第一次页面加载会触发哪几个钩子?
会触发beforeCreate("new Vue之前")、created("new Vue之后")、beforeMounted("el之前")、mounted("有了el之后")DOM在哪个钩子函数中完成?
在mounted中已经完成。什么是vue的双向数据绑定?
当我更新视图的数据也跟着改变,当我更新数据视图也跟着改变,例如当我文本框中输入了内容,则数据也发生了改变,当我改变数据,文本框内容也随之改变。-
vue的双向数据绑定原理是什么?
vue的双向数据绑定是用数据劫持和发布者-订阅者模式结合来实现的。通过用Object.defineProprety对data中的每个属性的set和get进行劫持。当数据发生变化,发消息给订阅者,订阅者执行回调函数来更新视图
image.png
a、实现一个数据监听器Observer,能够对vue中data里的所有属性进行监听,如有变动可拿到最新值并通知订阅者;因为属性可能是多个,所以会有多个订阅者,故我们需要一个消息订阅器Dep来专门收集这些订阅者。
b、实现一个订阅者Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图;
c、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,初始化视图;
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果
三、vue组件间传值
- 父组件给子组件怎么传?
在父组件中给子组件身上绑定属性,然后在子组件中用props接受数据; - 子组件给父组件怎么传?
在子组件中通过$emit
方法传递参数,在父组件中通过执行子组件抛出的方法获取数据 - 非父子组件传值?
可以通过总线的方式,通过在子组件1中this.bus.$emit('send',msg)
,触发事件,在子组件2中通过this.bus.$on('send',val=>{this.msg = val})
- 可以利用vuex来进行组件之间的传值
三、单页面vs多页面
SPA(单页面应用):指的就是只有一个主页面的应用,浏览器在一开始就必须加载所有的html,js,css,所有的页面内容都包含在这个主页面中,但是在写的时候还是会分开写(页面片段,例如.vue文件),在交互的时候通过路由(vue-router)动态加载,单页面的页面跳转,仅局部刷新页面。多应用于pc端,利于前后端分离
MPA(多页面应用):指的就是一个应用中有多个页面,页面跳转是整个页面刷新
SPA优缺点:
优点:页面切换快
缺点:首屏时间稍慢,SEO慢(首屏展示除了请求一次html还需要发js请求,都请求好了才会展示出来了,搜索引擎只认HTML,不认识js的内容,但是单页应用的内容都是靠js渲染出来的,不会给网页一个好的排名,在谷歌,但是可以通过vue提供的一些服务器渲染的内容改变单页的缺点)
页面跳转—>JS渲染
Js会感知到URL的变换,可以用js动态的把当前页面的内容清除掉,然后把另一个页面的内容挂到页面上,路由是由前端来控制,而不是后台来控制,所以每次切换的不会每次都请求http 请求了。
MPA优缺点:
优点:首屏时间快,SEO效果好(搜索引擎)
缺点:页面切换慢(因为每次切换的时候都会发一个http 请求)
页面跳转—>返回HTML
五、Vue-router
为了构建SPA(单页面应用),需要引入前端路由系统,这也就是Vue-router存在的意义,它的原理是通过改变网址,来实现页面的局部刷新。
两种模式:hash模式(默认)、history模式
- hash模式 —— 地址栏有#
比如:http://localhost:8080/#/Home,hash 的值为#/Home。它的特点在于:hash 虽然出现URL中,但不会被包含在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面。
2、history模式 —— 这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。比如:http://yoursite.com/user/id
不过这种模式还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id
就会返回 404,这就不好看了。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html
页面,这个页面就是你 app 依赖的页面。
六、Vue-router钩子函数
主要分为三类:全局钩子(全局守卫)、单个路由独享的、或者组件内的。
1.全局钩子函数一般用来判断权限,以及页面丢失时候需要执行的操作;
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
router.afterEach((to, from) => {
// ...
})
to: Route
: 即将要进入的目标 路由对象from: Route
: 当前导航正要离开的路由
-
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
2.单个路由共享的主要用于写某个指定路由跳转时需要执行的逻辑
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
},
beforeLeave: (to, from, next) => {
// ...
},
}
]
})
3.组件内的钩子
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不能获取组件实例 `this`
// 因为当钩子执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
},
beforeRouteEnter 钩子 不能 访问 this,因为钩子在导航确认前被调用,因此组件还没被创建。
不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}
你可以 在 beforeRouteLeave 中直接访问 this。这个 leave 钩子通常用来禁止用户在还未保存修改前突然离开。可以通过 next(false) 来取消导航。同时注意必须有这个next()。
七、vuex是什么?怎么使用?
Vuex通俗来讲就是用来管理所有组件之间的通信。相当于一个中间仓库。
首先新建store-->index.js,然后在main.js中引入index.js,挂载到Vue实例中。
index.js
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
const state = {
count: 1
}
const mutations = { //管理同步
add(state) {
state.count += 1;
},
reduce(state,n) {
state.count -= n
}
}
const actions = { //异步操作
add({ commit }) {
commit("add")
},
reduce(context, n) {
context.commit("reduce", n)
},
odd({ commit }) {
if (state.count % 2 == 0) {
commit('add')
}
},
sync({ commit }) {
setTimeout(function(){
commit('add')
},1000)
}
}
const getters = { //计算属性
count(state) {
return state.count += 10;
}
}
export default new Vuex.Store({
state,
mutations,
// getters,
actions
})
state,唯一的数据源,不可以直接修改,唯一方法是提交 mutation
mutations,必须是同步函数
actions,异步操作
getters,相当于计算属性,每次都会执行
在其他页面中可以用计算属性来获取state得值和getters的值,可以通过
this.$store.commit("add",参数)
来提交同步方法,可以通过this.$store.dispatch("add",参数)
来提交异步方法
八、vue中如何自定义指令
九、keep-alive
keep-alive是 Vue 内置的一个组件,可以缓存组件,使被包含的组件保留状态,或避免重新渲染。
在vue 2.1.0 版本之后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。
- 利用include、exclude属性
<keep-alive include="bookLists">
<router-view></router-view>
</keep-alive>
<keep-alive exclude="indexLists">
<router-view></router-view>
</keep-alive>
include属性表示只有bookLists的组件会被缓存,(注意是组件的名字,不是路由的名字)其它组件不会被缓存;exclude属性表示indexLists的组件不会被缓存,其它组件都会被缓存
2.利用meta属性
export default[
{
path:'/',
name:'home',
components:Home,
meta:{
keepAlive:true //需要被缓存的组件
},
{
path:'/book',
name:'book',
components:Book,
meta:{
keepAlive:false //不需要被缓存的组件
}
]
<keep-alive>
<router-view v-if="this.$route.meta.keepAlive">
<!-- 这里是会被缓存的视图组件,比如 Home! -->
</router-view>
</keep-alive>
<router-view v-if="!this.$route.meta.keepAlive">
<!-- 这里是不被缓存的视图组件,比如 Book! -->
</router-view>
应用场景:当我们在列表页的时候滑动到中间部分,退出去在返回来还希望保持在刚才查看的中间部分而不是顶部。