什么是MVVM?
在MVVM框架下 视图和模型是不能直接通信 的,只能通过ViewModel进行交互,它能够监 听到数据的变化,然后通知视图进行自动更新,而当用户操作视图时,VM也能监听到视图 的变化,然后通知数据做相应改动,这实际上就实现了数据的 双向绑定 。并且V和VM可以 进行通信。
即模型-视图-视图模型,模型(Model)指
的是后端传递的数据,视图(View)指的是所看到的页面,视图模型(ViewModel)是 mvvm 模式的核
心,它是连接 view 和 model 的桥梁。
2、为什么data是一个函数
组件的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一分新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
Vue组件通讯有哪些方式?
1、props和emit触发事件来做到的。
2.$refs 获取组件实例。
获取dom元素this.$refs.name,获取子组件中的data,
this.$refs.myRef.name,myRef绑定在父组件中的son标签上
3.vuex
Vue的生命周期方法有哪些?一般在哪一步发送请求?
beforeCreate 在实例初始化之后,数据观测(data observe)和 event/watcher 事件配置之前被调用。在当前阶段 data、methods、computed 以及 watch 上的数据和方法都不能被访问。
created 实例已经创建完成之后被调用。在这一步,实例已经完成以下的配置:数据观测(data observe ),属性和方法的运算,watch/event 事件回调。这里没有 nextTick 来访问 DOM。
beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted 在挂载完成后发生,在当前阶段,真实的 Dom 挂载完毕,数据完成双向绑定,可以访问到 Dom节点。
beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁 (patch)之前。可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。(数据修改页面未修改)
updated 发生在更新完成之后,当前阶段组件 Dom 已经完成更新。要注意的是避免在此期间更新数据,因为这个可能导致无限循环的更新,该钩子在服务器渲染期间不被调用。
beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。我们可以在这时进行 善后收尾工作,比如清除定时器。
destroyed Vue实例销毁后调用。调用后,Vue实例指示的东西都会解绑定,所有的事件监听器会被移除,左右的子实例也会被销毁,该钩子在服务器端渲染不被调用。
activated keep-alive 专属,组件被激活时调用
deactivated keep-alive 专属,组件被销毁时调用
设置了 keep-alive 缓存的组件,会多出两个生命周期钩子(activated与deactivated
在某些场景下不需要让页面重新加载时我们可以使用keepalive
当我们从首页–>列表页–>商详页–>再返回,这时候列表页应该是需要keep-alive
异步请求在哪一步发起?
可以在钩子函数 created、beforeMount、mounted 中进行异步请求,因为在这三个钩子函数中,data已经创建,可以将服务器端返回的数据进行赋值。
如果异步请求不需要依赖 DOM 推荐加载 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
能更快获取到服务端数据,减少页面loading时间; 如果依赖DOM元素:需要再mounted里面进行请求
v-if 和 v-show 的区别
v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。元素销毁和重建控制显示隐藏
v-show 会被编译成指令,条件不满足时控制样式将此节点隐藏(display:none) css样式控制
computed 和 watch 的区别和运用的场景
computed 是计算属性,依赖其它属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容,他可以设置getter和setter。
watch 监听到值的变化就会执行回调,在回调中可以进行一系列的操作。
计算属性一般用在模板渲染中,某个值是依赖其它响应对象甚至是计算属性而来;
而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。
v-if 和 v-for 为什么不建议一起使用
性能方面的浪费(每次渲染都会先循环再进行条件判断) 这样写:
<template v-if="isShow">
<p v-for="item in items">
</template>
Vue 2.0 响应式数据的原理(常问)
整体思路是 数据劫持 + 观察者模式 Vue 在初始化数据时 ,会使用 Object.defineProperty 重新定义 data 中的所有属性 ,当页面 使用对 应 属性时,首先会进行 依赖收集 (收集当前组件的 watcher ),如果属性 发生变化 会通知相关 依赖进行 更新操作( 发布订阅 )
Vue2.x 采用 数据劫持结合发布订阅模式 (PubSub 模式)的方式,通过 Object.defineProperty 来劫 持 各个属性 的 setter、getter ,在 数据变动时 发 布消息给订阅者 , 触发相应的监听回 调。
v-model 双向绑定的原理是什么?
v-model 本质 就是 : value + input 方法的语法糖 。可以通过 model 属性的 prop 和 event 属性来进行自定义。原生的 v-model,会根据标签的不同生成不同的事件和属性。
以输入框为例,当用户在输入框输入内容时,会触发 input 事件,从而更新 value。而 value 的改变同样会更新视图,这就是 vue 中的双向绑定。
hash模式和history模式
首先是在 URL 的展示上,hash 模式有“#”,history 模式没有
location.has 的值实际就是 URL 中 # 后面的东西。它的特点在于: hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中 hash监听 window.addEventListener("hashchange",funcRef,false)
history实际采用了HTML5中提供的API来实现,主要有history.pushState()和history.replaceState()。
vuex
状态管理器 使用方法
在 main.js 引入 store,注入。只用来读取的状态集中放在 store 中, 改变状态的方式是提交
mutations,这是个同步的事物,异步逻辑应该封装在 action 中。
State:定义了应用状态的数据结构,可以在这里设置默认的初始化状态。
Getter:允许组件从Store中获取数据,mapGetters 辅助函数仅仅是将 store 中的getter 映射到局部计算属性。
Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步请求。
Module:允许将单一的 Store 拆分更多个 store 且同时保存在单一的状态树中。
store.commit('mutations中的方法',value).
nextTick 的作用是什么?他的实现原理是什么
作用 :vue 更新 DOM 是异步更新的,数据变化,DOM 的更新不会马上完成, nextTick的回调是在下次 DOM 更新循环结束之后执行的延迟回调 。
change() {
this.msg = '被更新了'
this.$nextTick(() => {
// DOM更新了
console.log('$nextTick:' + this.$refs.msgp.innerHTML)
}) }
原型和原型链
每当定义一个对象(函数也是对象),对象中都会包含一些预定义的属性。其中每个 函数 (对象) 都会有一个 prototype 属性(是一个指针),它指向 一个对象-- 通过该函数创建的实例对象的原型,所以叫原型对象。
原型包含了特定类型的所有实例共享的属性和方法,每一个对象都会从原型继承这些属性、方法。所以,原型对象的好处是:可以让所有的实例对象共享它所包含的属性和方法。
路由
$router是VueRouter的一个对象,通过Vue.use(VueRouter)和Vue构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。
$route是一个跳转的路由对象,每一个路由都会有一个$route对象,是一个局部的对象,可以获取对应的name,path,params,query等
-
全局守卫:
beforeEach和afterEach。 -
独享路由守卫:
beforeEnter。 -
组件内路由守卫:
beforeRouteEnter、beforeRouteUpdate和beforeRouteLeave。
全局守卫分为全局前置守卫和全局后置守卫。
router.beforeEach(async(to, from, next) => {
nprogress.start()
if (store.getters.token) {
// 存在token
if (to.path === '/login') {
// 跳转到主页
next('/') // 中转到主页
// next(地址)并没有执行后置守卫
nprogress.done()
} else {
// 判断是否获取过资料
if (!store.getters.userId) {
const { roles } = await store.dispatch('user/getUserInfo')
// console.log(roles.menus) // 数组 不确定 可能是8个 1个 0个
// console.log(asyncRoutes) // 数组 8个
const filterRoutes = asyncRoutes.filter(item => {
// return true/false
return roles.menus.includes(item.name)
}) // 筛选后的路由
store.commit('user/setRoutes', filterRoutes)
router.addRoutes([...filterRoutes, { path: '*', redirect: '/404', hidden: true }]) // 添加动态路由信息到路由表
// router添加动态路由之后 需要转发一下
next(to.path) // 目的是让路由拥有信息 router的已知缺陷
} else {
next() // 放过
}
}
} else {
// 没有token
if (whiteList.includes(to.path)) {
next()
} else {
next('/login') // 中转到登录页
nprogress.done()
}
}
})
vue中对象新增新属性渲染到页面上,$set
使用$set去添加属性,然后赶紧去试了一下this.$set(this.myInfo, 'age', 24),果真可以了。
向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。
它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性
(比如 this.myObject.newProperty = 'hi')