vue专题我爱编程

vue前端面试

2018-04-15  本文已影响375人  5df463a52098

1、vue的生命周期函数

2、vue MVVM模式

 > MVVM介绍:
    MVVM分为三个部分:分别是M(Model,模型层 ),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看作为控制器)
1、 M:模型层,主要负责业务数据相关;
2、 V:视图层,顾名思义,负责视图相关,细分下来就是html+css层;
3、 VM:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向绑定的要点;

MVVM支持双向绑定,意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之修改V层则会通知M层数据进行修改,以此也实现了视图与模型层的相互解耦;

3、<keep-alive></keep-alive>的作用

<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。

prop:
include: 字符串或正则表达式。只有匹配的组件会被缓存。
exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。

常见用法:

export default {
 name: 'test-keep-alive',
 data () {
     return {
        includedComponents: "test-keep-alive"
     }
   }
}
<keep-alive include="test-keep-alive">
       <!-- 将缓存name为test-keep-alive的组件 -->
       <component></component>
</keep-alive>
 
<keep-alive include="a,b">
       <!-- 将缓存name为a或者b的组件,结合动态组件使用 -->
       <component :is="view"></component>
</keep-alive>
 
 <!-- 使用正则表达式,需使用v-bind -->
<keep-alive :include="/a|b/">
       <component :is="view"></component>
</keep-alive>
 
<!-- 动态判断 -->
<keep-alive :include="includedComponents">
       <router-view></router-view>
</keep-alive>
 
<keep-alive exclude="test-keep-alive">
       <!-- 将不缓存name为test-keep-alive的组件 -->
       <component></component>
</keep-alive>
结合router,缓存部分页面

使用$route.meta的keepAlive属性:

<keep-alive>
     <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>

需要在router中设置router的元信息meta:

 routes: [
   {
    path: '/',
    name: 'Hello',
    component: Hello,
    meta: {
      keepAlive: false // 不需要缓存
      }
     },
   {
    path: '/page1',
    name: 'Page1',
    component: Page1,
    meta: {
      keepAlive: true // 需要被缓存
    }
   }
   ]
})

keep-alive生命周期钩子函数:activated、deactivated
使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。

案例:首页是A页面;B页面跳转到A,A页面需要缓存;C页面跳转到A,A页面不需要被缓存
A的路由

{
 path: '/',
 name: 'A',
 component: A,
 meta: {
  keepAlive: true // 需要被缓存
 }
}

B组件

export default {
 data() {
  return {};
 },
 methods: {},
 beforeRouteLeave(to, from, next) {
   // 设置下一个路由的 meta
  to.meta.keepAlive = true; // B 跳转到 A 时,让 A 缓存,即不刷新
  next();
 }
};

C组件

export default {
 data() {
  return {};
 },
 methods: {},
 beforeRouteLeave(to, from, next) {
  // 设置下一个路由的 meta
  to.meta.keepAlive = false; // C 跳转到 A 时让 A 不缓存,即刷新
  next();
 }
};

4、Vue.js引入组件的步骤

1.可以作用到Vue.component 这个全局注册方法里, 可以在任意vue模板里使用<apple>组件
var apple = Vue.extend({
....
})
Vue.component('apple',apple)
2.可以作用到vue实例或者某个组件中的components属性中并在内部使用apple组件
new Vue({
components:{
apple:apple
}
})

5、Vue.js使用插件的步骤

vue-cli脚手架中:npm安装插件,然后在main.js里import引入,Vue.use(插件名)

6、Vue-router有哪几种导航钩子

1.全局导航钩子

beforeEach
beforeResolve
afterEach

const router = new VueRouter({ 
    mode: 'history', // 路由使用history模式 
    routes, 
    linkActiveClass: 'active', // 设置当前路由的className }); 
// 全局导航钩子 直接挂载在router实例上的 
router.beforeEach((to, from, next) => { 
    document.title = to.meta.title || 'demo' 
    if (!to.query.url && from.query.url) {    
       to.query.url = from.query.url 
    } next() 
})
 router.afterEach(route => { }) 
2.某个路由独享的导航钩子

beforeEnter

{ path: '/', 
  component: App, 
  children: [ { 
      path: 'apply', 
      name: 'apply', 
      component: Apply, 
      children: [ { 
          path: 'launch', 
          name: 'apply-launch-list', 
          component: applyList, 
        // 直接在router的路由配置中使用 
        beforeEnter (to, from, next) { 
            // 如果isBack为true时,证明是用户点击了回退,执行slide-right动画 
            let isBack = this.$store.state.transferBack;
            if (isBack) { 
                  this.transitionName = 'slide-right'; 
            } else {
                 this.transitionName = 'slide-left'; 
            } 
  // 做完回退动画后,要设置成前进动画,否则下次打开页面动画将还是回退                 
            this.$router.isBack = false; 
            next() 
         } 
        }, 
       { 
          path: 'draft',
          name: 'apply-draft-list', 
          component: draftList
       } ] 
  } ]
 } 
3.路由组件上的导航钩子

beforeRouteEnter
beforeRouteUpdate (2.2 新增)
beforeRouteLeave

// 定义一个vue模板,这个模板被router的配置文件的component使用 
const Qux = { 
    data () {
       return {
         msg: null 
      }
   },
   template: `<div>{{ msg }}</div>`, 
// 路由组件上的导航钩子beforeRouteEnter 
   beforeRouteEnter (to, from, next) { 
      setTimeout(() => {
         next(vm => { vm.msg = 'Qux' }) 
      }, 300) } 
    } 
const router = new VueRouter({ 
    mode: 'history', 
    base: __dirname, 
    routes: [ 
      { path: '/', component: Home }, 
      // 某个路由独享的导航钩子 beforeEnter 
      { path: '/foo', component: Foo, beforeEnter: guardRoute }, 
      { path: '/bar', component: Bar, meta: { needGuard: true }},
       // 在这里使用Qux
      { path: '/qux', component: Qux }, 
      { path: '/qux-async', component: resolve => { 
              setTimeout(() => { 
                  resolve(Qux) 
              }, 0) 
          } 
        }, 
      { path: '/quux/:id', component: Quux } 
    ] 
}) 

7、vue的data为什么要return返回

在简单的vue实例中看到的Vue实例中data属性是如下方式展示的:
let app= newVue({
    el:"#app",
    data:{
        msg:''
    },
    methods:{

    }
})
在使用组件化的项目中使用的是如下形式:
export default{
    data(){
        return {

        }
    },
    methods:{

    }
}

不使用return包裹的数据会在项目的全局可见,会造成变量污染 ,使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件。
在创建或注册模板的时候,传入一个data属性作为用来绑定的数据。但是在组件中,data必须是一个函数,而不能直接把一个对象赋值给它。
从js原型链理解:

var MyComponent = function() {}
MyComponent.prototype.data = {
  a: 1,
  b: 2,
}
// 上面是一个虚拟的组件构造器,真实的组件构造器方法很多
var component1 = new MyComponent()
var component2 = new MyComponent()
// 上面实例化出来两个组件实例,也就是通过<my-component>调用,创建的两个实例
component1.data.a === component2.data.a // true
component1.data.b = 5
component2.data.b != 5

如果两个实例同时引用一个对象,那么当你修改其中一个属性的时候,另外一个实例也会跟着改,所以两个实例应该各有各的域。这都是因为js本身的特性带来的,跟vue本身设计无关

var MyComponent = function() {
  this.data = this.data()
}
MyComponent.prototype.data = function() {
  return {
    a: 1,
    b: 2,
  }
}

8、vuex

Vuex采用和Redux类似的单向数据流的方式来管理数据。用户界面负责触发动作(Action)进而改变对应状态(State),从而反映到视图(View)上。

State负责存储整个应用的状态数据,一般需要在使用的时候在跟节点注入store对象,后期就可以使用this.$store.state直接获取状态,当然,也可以利用vuex提供的mapState辅助函数将state映射到计算属性中去
Mutations的中文意思是“变化”,利用它可以更改状态,本质就是用来处理数据的函数,其接收唯一参数值state。store.commit(mutationName)是用来触发一个mutation的方法。需要记住的是,定义的mutation必须是同步函数,否则devtool中的数据将可能出现问题,使状态改变变得难以跟踪。或者使用辅助函数mapMutations直接将触发函数映射到methods上
Actions也可以用于改变状态,不过是通过触发mutation实现的,重要的是可以包含异步操作。其辅助函数是mapActions与mapMutations类似,也是绑定在组件的methods上的。如果选择直接触发的话,使用this.$store.dispatch(actionName)方法
有些状态需要做二次处理,就可以使用getters。通过this.$store.getters.valueName对派生出来的状态进行访问。或者直接使用辅助函数mapGetters将其映射到本地计算属性中去。
Plugins插件就是一个钩子函数,在初始化store的时候引入即可。比较常用的是内置的logger插件,用于作为调试使用。

9、vue常用指令

v-if//v-show//v-else//v-for//v-bind//v-on

10、vue的组件继承

11、vue组件之间的通信方式

12、vue的底层原理

推荐博文

13、实现Vue SSR

14、另一种方式实现Vue的响应式原理

15实现数据双向绑定的做法

①发布者-订阅者模式:
一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set('property', value),
②脏值检查:
angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,angular只有在指定的事件触发时进入脏值检测:
DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
XHR响应事件 ( $http )
浏览器Location变更事件 ( $location )
Timer事件( $timeout , $interval )
执行 $digest() 或 $apply()
③数据劫持:
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

16、vue父子组件通信以及非父子组件通信

①父传子
父组件:

<parent>
    <child :child-msg="msg"></child> //这里必须要用 - 代替驼峰
</parent>
data(){
    return {
        msg: [1,2,3]
    };
}

子组件:

//方式一
props: ['childMsg']
//方式二
props: {
    childMsg: Array //这样可以指定传入的类型,如果类型不对,会警告
}
//方式三
props: {
    childMsg: {
        type: Array,
        default: [0,0,0] //这样可以指定默认的值
    }
}

②子传父(vue只允许单向数据传递,我们可以通过触发事件来通知父组件改变数据,从而达到改变子组件数据的目的.)
子组件:

<template>
    <div @click="up"></div>
</template>

methods: {
    up() {
        this.$emit('upup','hehe'); //主动触发upup方法,'hehe'为向父组件传递的数据
    }
}

父组件:

<div>
    <child @upup="change" :msg="msg"></child> //监听子组件触发的upup事件,然后调用change方法
</div>
methods: {
    change(msg) {
        this.msg = msg;
    }
}

③非父子组件

var bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
// ...
})

event bus 只适于某些不复杂的场景,在需要频繁进行组件通信的情况下,还是应该尽量使用 Vuex ,不仅使用上更加简单,同时数据流的流向也会相对清晰。

上一篇 下一篇

猜你喜欢

热点阅读