聊聊对vue的理解
vue是一个渐进式的JS框架。他易用,灵活,高效; 可以把一个页面分隔成多个组件;当其他页面有类似功能时,直接让封装的组件进行复用; 他是构建用户界面的声明式框架,只关心图层;不关心具体是如何实现的
V-model的是什么?
Vue的双向数据绑定是由数据劫持结合发布者订阅者实现的。 数据劫持是通过Object.defineProperty()来劫持对象数据的setter和getter操作。 在数据变动时作你想做的事
- 通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化->视图更新 在初始化vue实例时,遍历data这个对象,给每一个键值对利用Object.definedProperty对data的键值对新增get和set方法,利用了事件监听DOM的机制,让视图去改变数据
谈谈对生命周期的理解
- beforeCreate阶段:vue实例的挂载元素el和数据对象data都是undefined,还没有初始化。
- created阶段:vue实例的数据对象data有了,可以访问里面的数据和方法,未挂载到DOM,el还没有
- beforeMount阶段:vue实例的el和data都初始化了,但是挂载之前为虚拟的dom节点
- mounted阶段:vue实例挂载到真实DOM上,就可以通过DOM获取DOM节点
- beforeUpdate阶段:响应式数据更新时调用,发生在虚拟DOM打补丁之前,适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器
- updated阶段:虚拟DOM重新渲染和打补丁之后调用,组成新的DOM已经更新,避免在这个钩子函数中操作数据,防止死循环
- beforeDestroy阶段:实例销毁前调用,实例还可以用,this能获取到实例,常用于销毁定时器,解绑事件
- destroyed阶段:实例销毁后调用,调用后所有事件监听器会被移除,所有的子实例都会被销毁
VUE和REACT有什么区别?
react整体是函数式的思想,把组件设计成纯组件,状态和逻辑通过参数传入,所以在react中,是单向数据流;
vue的思想是响应式的,也就是基于是数据可变的,通过对每一个属性建立Watcher来监听,当属性变化的时候,响应式的更新对应的虚拟dom。
vuex的流程
页面通过mapAction异步提交事件到action。action通过commit把对应参数同步提交到mutation。
mutation会修改state中对于的值。 最后通过getter把对应值跑出去,在页面的计算属性中
通过mapGetter来动态获取state中的值
vuex有哪几种状态和属性
- state中保存着共有数据,数据是响应式的
- getter可以对state进行计算操作,主要用来过滤一些数据,可以在多组件之间复用
- mutations定义的方法动态修改state中的数据,通过commit提交方法,方法必须是同步的
- actions将mutations里面处理数据的方法变成异步的,就是异步操作数据,通store.dispatch来分发actions,把异步的方法写在actions中,通过commit提交mutations,进行修改数据。
- modules:模块化vuex
vue路由的两种模式
- hash ——即地址栏URL中的#符号(此hsah 不是密码学里的散列运算) hash 虽然出现URL中,但不会被包含在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面。
- history ——利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法
这两个方法应用于浏览器的历史记录站,在当前已有的back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改是,虽然改变了当前的URL,但你浏览器不会立即向后端发送请求。
vue中 key 值的作用
当 Vue.js 用v-for正在更新已渲染过的元素列表时,它默认用“就地复用”策略。 如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
key的作用主要是为了高效的更新虚拟DOM。
$route
和$router
的区别
- $route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
- $router是“路由实例”对象包括了路由的跳转方法,钩子函数等。
vue-router守卫
- 导航守卫 router.beforeEach 全局前置守卫
- to: Route: 即将要进入的目标(路由对象)
- from: Route: 当前导航正要离开的路由
- next: Function: 一定要调用该方法来 resolve 这个钩子。(一定要用这个函数才能去到下一个路由,如果不用就拦截) 执行效果依赖 next 方法的调用参数。
- next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
- next(false): 取消进入路由,url地址重置为from路由地址(也就是将要离开的路由地址)。
// main.js 入口文件
import router from './router'; // 引入路由
router.beforeEach((to, from, next) => {
next();
});
router.beforeResolve((to, from, next) => {
next();
});
router.afterEach((to, from) => {
console.log('afterEach 全局后置钩子');
});
路由独享的守卫 你可以在路由配置上直接定义 beforeEnter 守卫
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
组件内的守卫 你可以在路由组件内直接定义以下路由导航守卫
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用,我们用它来禁止用户离开
// 可以访问组件实例 `this`
// 比如还未保存草稿,或者在用户离开前,
将setInterval销毁,防止离开之后,定时器还在调用。
}
}
axios是什么?怎么使用?描述使用它实现登录功能的流程?
请求后台资源的模块。
$ npm install axios -S装好
然后发送的是跨域,需在配置文件中config/index.js进行设置。后台如果是Tp5则定义一个资源路由。 js中使用import进来,然后.get或.post。返回在.then函数中如果成功,失败则是在.catch函数中
vue修饰符
- stop:阻止事件的冒泡
- prevent:阻止事件的默认行为
- once:只触发一次
- self:只触发自己的事件行为时,才会执行
vue项目中的性能优化
1.不要在模板里面写过多表达式
2.循环调用子组件时添加key
3.频繁切换的使用v-show,不频繁切换的使用v-if
4.尽量少用float,可以用flex
5.按需加载,可以用require或者import()按需加载需要的组件
6.路由懒加载
vue.extend和vue.component
- extend 是构造一个组件的语法器。 然后这个组件你可以作用到Vue.component这个全局注册方法里 还可以在任意vue模板里使用组件。 也可以作用到vue实例或者某个组件中的components属性中并在内部使用apple组件。
- Vue.component 你可以创建 ,也可以取组件。
Vue组件间的参数传递
父组件与子组件传值
父组件传给子组件:子组件通过
props
方法接受数据;
- 子组件传给父组件:
$emit
方法传递参数
非父子组件间的数据传递,兄弟组件传值
eventBus
,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。项目比较小时,用这个比较合适(虽然也有不少人推荐直接用VUEX
,具体来说看需求)
Vue的路由实现:hash模式 和 history模式
hash
模式:在浏览器中符号“#”
,#以及#后面的字符称之为hash
,用window.location.hash
读取。特点:hash
虽然在URL
中,但不被包括在HTTP
请求中;用来指导浏览器动作,对服务端安全无用,hash
不会重加载页面。history
模式:history
采用HTML5
的新特性;且提供了两个新方法:pushState()
,replaceState()
可以对浏览器历史记录栈进行修改,以及popState
事件的监听到状态变更
v-if 和 v-show 区别
v-if
按照条件是否渲染,v-show
是display
的block
或none
keep-alive
的作用是什么
- 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染
比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用``进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染
指令v-el的作用是什么
提供一个在页面上已存在的
DOM
元素作为Vue
实例的挂载目标.可以是 CSS 选择器,也可以是一个HTMLElement
实例,
在Vue中使用插件的步骤
- 采用
ES6
的import ... from ...
语法或CommonJS
的require()
方法引入插件 - 使用全局方法
Vue.use( plugin )
使用插件,可以传入一个选项对象Vue.use(MyPlugin, { someOption: true })
vue的优点是什么?
- 低耦合。视图(
View
)可以独立于Model
变化和修改,一个ViewModel
可以绑定到不同的"View"
上,当View变化的时候Model可以不变,当Model
变化的时候View
也可以不变 - 可重用性。你可以把一些视图逻辑放在一个
ViewModel
里面,让很多view
重用这段视图逻辑 - 可测试。界面素来是比较难于测试的,而现在测试可以针对
ViewModel
来写
路由之间跳转?
声明式(标签跳转)
<router-link :to="index">
编程式( js跳转)
router.push('index')
Vue 组件 data 为什么必须是函数
- 每个组件都是
Vue
的实例。 - 组件共享
data
属性,当data
的值是同一个引用类型的值时,改变其中一个会影响其他
怎么快速定位哪个组件出现性能问题
用
timeline
工具。 大意是通过timeline
来查看每个函数的调用时常,定位出哪个函数的问题,从而能判断哪个组件出了问题
extend 能做什么
这个
API
很少用到,作用是扩展组件生成一个构造器,通常会与$mount
一起使用。
// 创建组件构造器
let Component = Vue.extend({
template: '<div>test</div>'
})
// 挂载到 #app 上
new Component().$mount('#app')
// 除了上面的方式,还可以用来扩展已有的组件
let SuperComponent = Vue.extend(Component)
new SuperComponent({
created() {
console.log(1)
}
})
new SuperComponent().$mount('#app')
mixin 和 mixins 区别
mixin
用于全局混入,会影响到每个组件实例,通常插件都是这样做初始化的
Vue.mixin({
beforeCreate() {
// ...逻辑
// 这种方式会影响到每个组件的 beforeCreate 钩子函数
}
})
- 虽然文档不建议我们在应用中直接使用
mixin
,但是如果不滥用的话也是很有帮助的,比如可以全局混入封装好的ajax
或者一些工具函数等等。 mixins
应该是我们最常使用的扩展组件的方式了。如果多个组件中有相同的业务逻辑,就可以将这些逻辑剥离出来,通过mixins
混入代码,比如上拉下拉加载数据这种逻辑等等。- 另外需要注意的是
mixins
混入的钩子函数会先于组件内的钩子函数执行,并且在遇到同名选项的时候也会有选择性的进行合并,具体可以阅读 文档。
computed 和 watch 区别
computed
是计算属性,依赖其他属性计算值,并且computed
的值有缓存,只有当计算值变化才会返回内容。watch
监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。- 所以一般来说需要依赖别的属性来动态获得值的时候可以使用
computed
,对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用watch
。 - 另外
computer
和watch
还都支持对象的写法,这种方式知道的人并不多。
vm.$watch('obj', {
// 深度遍历
deep: true,
// 立即触发
immediate: true,
// 执行的函数
handler: function(val, oldVal) {}
})
var vm = new Vue({
data: { a: 1 },
computed: {
aPlus: {
// this.aPlus 时触发
get: function () {
return this.a + 1
},
// this.aPlus = 1 时触发
set: function (v) {
this.a = v - 1
}
}
}
})
Proxy 相比于 defineProperty 的优势
- 数组变化也能监听到
- 不需要深度遍历监听
let data = { a: 1 }
let reactiveData = new Proxy(data, {
get: function(target, name){
// ...
},
// ...
})