文章目录

  • 1.vue双向绑定的原理
  • 2.解释单向数据流和双向数据绑定
  • 3.如何去除url中的“#”(history模式和hash模式的区别)
  • 4.对MVC、MVVM的理解
  • 5.介绍虚拟DOM树
  • 6.vue生命周期(4个阶段,8个钩子函数)
  • 7.组件间通信
  • 8.vue-router路由实现
  • 9.v-if 和 v-show 的区别
  • 10.$route 和 $router 的区别
  • 11.vue组件data为什么必须是函数
  • 12.计算属性computed和事件methods有什么区别
  • 13.jQuery和vue的区别
  • 14.vue中怎么自定义指令
  • 1)全局注册
  • 2)局部注册
  • 15.vue中怎么自定义过滤器
  • 16.对keep-alive的了解
  • 17.active-class
  • 18.嵌套路由
  • 19.路由跳转
  • 1) 声明式
  • 2) 编程式
  • 20.懒加载(按需加载路由)
  • 问题:
  • 原因:
  • 解决方案:
  • 1) 配置打包工具,将组件分别打包到不同的js代码块中
  • 2)当路由请求到该组件时,才动态加载组件的内容
  • 21.vuex
  • 22.Vue.use(Vuex)
  • 23.vue-router导航钩子
  • 24.vue自定义指令
  • 25.vue的双向绑定原理


1.vue双向绑定的原理

vue 面试题 axios vue面试题2020_vue

2.解释单向数据流和双向数据绑定

  • 单向数据流:
    data改变页面会自动改变,页面改变不影响data
  • 双向数据绑定
    data改变页面会自动改变,页面改变影响data自动改变

3.如何去除url中的“#”(history模式和hash模式的区别)

vue-router默认使用hash模式,所以在路由加载时,项目中的URL会自带#;
如果不想使用#,可以使用vue-router的另一种模式history

new Router({
                mode:'history',
                routes: []
            })

4.对MVC、MVVM的理解

vue 面试题 axios vue面试题2020_前端_02

5.介绍虚拟DOM树

虚拟DOM树:
仅包含 可能变化的节点 和 可能变化的属性 的树结构。
虚拟DOM树内容较真实DOM树内容少,便于快速遍历比较不同。
当data中模型变量改变时,会通知虚拟DOM树 ==> 虚拟DOM树先缓存本次的修改在元素对象上 ==> 将一批修改生成新的DOM子树,和原虚拟DOM树做对比 ==> 一旦发现不同的元素或内容,就只更新有修改的元素 ==> 虚拟DOM树中,封装了传统DOM API:createElement() appendChild() .innerHTML,避免了大量重复的代码

6.vue生命周期(4个阶段,8个钩子函数)

  • beforeCreate() 在实例创建之间执行,数据未加载状态
  • created() 在实例创建,数据加载之后,能初始化数据,DOM渲染之前执行
  • beforeMount() 虚拟dom树已创建完成,在数据渲染前最后一次更改数据
  • mounted() 页面、数据渲染完成,真实dom树挂载完成
  • beforeUpdate() 重新渲染之前触发
  • updated() 数据已经更改完成,dom也重新render完成,更改数据会陷入死循环
  • beforeDestory() 销毁前执行,实例仍然完全可用
  • destoryed() 销毁后执行

7.组件间通信

组件间通信

8.vue-router路由实现

9.v-if 和 v-show 的区别

10.$route 和 $router 的区别

11.vue组件data为什么必须是函数

12.计算属性computed和事件methods有什么区别

13.jQuery和vue的区别

14.vue中怎么自定义指令

1)全局注册

2)局部注册

15.vue中怎么自定义过滤器

16.对keep-alive的了解

17.active-class

是 vue-router 模块的 router-link 组件,定义router-link在点击时的样式

18.嵌套路由

代码如下

// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import home from '@/views/home'
import index from '@/views/index'
import details from '@/views/details'
import login from '@/views/login'

Vue.use(Router)

export default new Router({
  linkExactActiveClass:'link-active',
  routes: [
    {
      path: '/',
      name: 'home',
      component: home,
      children: [
          {
              path: '/',
              name: 'index',
              component: index,
          },
          {
            path: '/details',
            name: 'details',
            component: details,
        }
      ]
    },
    {
        path: '/login',
        name: 'login',
        component: login
    }
  ]
})
<!-- App.vue -->
<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>


export default {
  name: 'App'
}
</script>

<style>
.link-active {
    color:brown
}
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
<!-- myheader.vue -->
<template lang="">
    <div>
        <h1>页头</h1>
        <ul>
            <li>
                <router-link to="/">首页</router-link>
            </li>
            <li>
                <router-link to="/details">详情页</router-link>
            </li>
            <li>
                <router-link to="/login">登陆页</router-link>
            </li>
        </ul>
        <hr>
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>
<!-- home.vue -->
<template lang="">
    <div>
        <my-header></my-header>
        <router-view></router-view>
    </div>
</template>
<script>
import myHeader from '@/components/myheader.vue'
export default {
    components: {
        myHeader
    }
}
</script>
<style lang="">
    
</style>
<!-- index.vue -->
<template lang="">
    <div>
        <h2>这里是首页</h2>
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>
<!-- details.vue -->
<template lang="">
    <div>
        <h2>这里是详情页</h2>
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>
<!-- login.vue -->
<template lang="">
    <div>
        <h1>登录页</h1>
        <router-link to="/">返回首页</router-link>
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>

19.路由跳转

1) 声明式

<!-- myheader.vue -->
<template lang="">
    <div>
        <h1>页头</h1>
        <ul>
            <li>
                <router-link to="/">首页</router-link>
            </li>
            <li>
                <router-link to="/details">详情页</router-link>
            </li>
            <li>
                <router-link to="/login">登陆页</router-link>
            </li>
        </ul>
        <hr>
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>

2) 编程式

$router.push('index')

20.懒加载(按需加载路由)

问题:

vue首屏加载非常慢

原因:

当打包应用时,将所有JavaScript代码打包在一个文件中,导致js代码非常庞大,从而严重影响页面加载速度

解决方案:

1) 配置打包工具,将组件分别打包到不同的js代码块中

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    chunkFilename: '[name].js', // 实现懒加载 build/webpack.base.conf.js
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  // ...
  }

2)当路由请求到该组件时,才动态加载组件的内容

路由字典中,路由配置和以前完全一样
但是在引入组件对象时,

import login from '@/views/login'

要改为

const login = ()=>{import('@/views/login')} // 仅定义函数,不执行,所以暂时未从内存中引入

当用户在vue中请求当前组件对应的路由地址时,由vue-router自动调用加载函数,动态请求login.vue组件对象

21.vuex

vue 面试题 axios vue面试题2020_Vue_03

vue框架中状态管理。在main.js引入store.js,注入
应用场景:单页应用中,组件之间的状态,或者是否登陆
vuex中有5中属性,分别是
1. state,保存模型变量,相当于仓库
2. getter 相当于计算属性,
3. mutation 保存对单个模型变量的操作,譬如修改或者读取
4. action 调用mutation中的操作实现比较复杂的功能
5. module 当vuex中维护的数据比较庞大时,可以用module对vuex进行分组维护

// Store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        n: 0,
    },
    mutations: {
        nadd(state){
            state.n++
        },
        nminus(state){
            state.n--
        },
    },
    actions: {
        calc(context){
            context.commit('nadd')
            context.commit('nadd')
            context.commit('nminus')
        }
    }
        
})
// main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
// ...

22.Vue.use(Vuex)

如下所示,Vue.use(Vuex)做了什么

// Store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        n: 0,
    },
    mutations: {
        nadd(state){
            state.n++
        },
        nminus(state){
            state.n--
        },
    },
    actions: {
        calc(context){
            context.commit('nadd')
            context.commit('nadd')
            context.commit('nminus')
        }
    }
        
})

Vue.use(Vuex) 方法执行的是install方法,它实现了vue实例对象的init方法和注入,使传入的store对象能设置到vue上下文环境的store中,因此在vue组件中的任意地方都能够通过this.store访问到该store

23.vue-router导航钩子

24.vue自定义指令

25.vue的双向绑定原理

vue.js是采用 数据劫持 结合 发布者-订阅者模式 的方式,通过Object.defineProperty()来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

具体步骤:

  1. 需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到数据变化
  2. compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
  3. watcher订阅者是observer和compile之间通信的桥梁,主要做的事情是:
  • 在 自身实例化时往属性订阅器(dep)里面添加自己
  • 自身必须有个update方法
  • 待属性变动dep.notice()通知时,能调用自身的update()方法,并触发compile中绑定的回调
  1. MVVM作为数据绑定的入口,整合 observer、compile、和watcher三者,通过observer来监听自己的model数据变化,通过compile来解析模板指令,最终利用watcher来搭起observer和compile之间的通信桥梁,达到 数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果