呕心沥血60道Vue、Vue-Router、Vuex面试题及详解!

VUE60道面试题总结

生命周期函数

1.什么是 vue 生命周期

  • 我们知道 vue 是通过构建数据驱动的web界面的渐进式框架
  • 所谓周期就是指从一个起点到一个终点的过程,那么生命周期就是指从生命开始到生命结束的过程
  • vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。具体方法有:
  1. beforeCreate (创建前)
  2. created (创建后)
  3. beforeMount (挂载前)
  4. mounted (挂载后)
  5. beforeUpdate (数据更新前)
  6. updated (数据更新后)
  7. beforeDestroy (销毁前)
  8. destroyed (销毁后)

2. vue生命周期的作用是什么

  • 使用vue时, 用到所有功能都是围绕vue生命周期实现的,在生命周期的不同阶段调用对应的钩子函数来实现组件数据管理和DOM渲染两大重要功能

3. 第一次页面加载会触发哪几个钩子

  1. beforeCreate (创建前)
  2. created (创建后)
  3. beforeMount (挂载前)
  4. mounted (挂载后)

4. 简述每个周期具体适合哪些场景

  • beforecreate : 可以在这加个loading事件,在加载实例时触发
  • created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
  • mounted : 挂载元素,获取到DOM节点
  • updated : 如果对数据统一处理,在这里写上相应函数
  • beforeDestroy : 可以做一个确认停止事件的确认框
  • nextTick : 更新数据后立即操作dom
var vm = new Vue({
    
    
el: '#app',
data: {
    
    
  str:'你是个麻瓜'
},
methods: {
    
    },
// vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。
// 加loading事件
beforeCreate() {
    
    
  console.log("beforeCreate" + "-------app1");
},
// vue实例的数据对象data有了,$el还没有
// 结束loading、请求数据为mounted渲染做准备
created() {
    
    
  console.log("created" + "-------app2");
},
// vue实例的$el和data都初始化了,但还是虚拟的dom节点,具体的data.filter还未替换。
beforeMount() {
    
    
  console.log("beforeMount" + "-------app3");
},
// vue实例挂载完成,data.filter成功渲染
mounted() {
    
    
  console.log("mounted" + "-------app4");
},
// data更新前触发
beforeUpdate() {
    
    
  console.log("beforeUpdate" + "-------app5");
},
// data更新时触发
updated() {
    
    
  console.log("updated" + "-------app6");
},
// 组件销毁时触发
beforeDestroy() {
    
    
  console.log("beforeDestroy" + "-------app7");
},
// 组件销毁时触发,vue实例解除了事件监听以及和dom的绑定(无响应了),但DOM节点依旧存在
destroyed() {
    
    
  console.log("beforeDestroy" + "-------app8");
},
});

5.created和mounted的区别

  • created:是在模板渲染成HTML前调用的,此时data已经准备完毕,el仍是undefined,因为没有渲染成HTML,所以不能操作dom节点,它主要用来初始化一些数据;

  • 即使created中的方法没有执行完,mounted也会被调用!

  • mounted:是在模板渲染成HTML之后调用的,此时data,el都已准备好,可以操作html的dom节点,可以通过id什么的来查找页面元素,也可以加载一些组件什么的

6. vue获取数据在哪个周期函数

  • 越早越好(能放created就放created里)

7. 请详细说下你对vue生命周期的理解?

  • 创建前/后: 在beforeCreated阶段,vue实例的挂载元素 e l 和 ‘ 数 据 对 象 ‘ d a t a 都 为 u n d e f i n e d , 还 未 初 始 化 。 在 c r e a t e d 阶 段 , v u e 实 例 的 数 据 对 象 d a t a 有 了 , el和`数据对象`data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了, eldataundefinedcreatedvuedatael还没有。

  • 挂载前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

  • 更新前/后:当data变化时,会触发beforeUpdate和updated方法。

  • 销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在


vue路由面试题 (vue-router)

1. mvvm 框架是什么?

  • M:Model(服务器上的业务逻辑操作)
  • V:View(页面)
  • VM:ViewModel(Model与View之间核心枢纽

详解

2. vue-router 是什么?它有哪些组件

  • 路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。

  • vue-router是vue.js官方路由管理器。vue的单页应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。(传统页面切换是用超链接a标签进行切换)

————详解一————详解二————

<router-link :to='' class='active-class'>   //路由声明式跳转 ,active-class是标签被点击时的样式

<router-view>                  //渲染路由的容器

<keep-alive>                    //缓存组件

3.active-class 是哪个组件的属性?

  • active-class 属于vue-router的样式方法,当routerlink标签被点击时将会应用这个样式
  <router-link to='/' active-class="active" >你是个麻瓜</router-link>

在路由js文件,配置active-class

  const router = new VueRouter({
    
    
    routes,
    linkActiveClass: 'active'
  });

注:在使用时会有一个Bug
首页的active会一直被应用,解决办法,为了解决上面的问题,还需加入一个属性exact,类似也有两种方式:
在router-link中写入exact

<router-link to='/' active-class="active" exact>首页</router-link>

···

4.怎么定义 vue-router 的动态路由?

可以通过qurey、params两种方式

区别:query通过url传参,刷新页面时还在,params刷新页面就不在了

  • params的类型
  1. 配置路由格式:/router/:id
  2. 传递的方式:在path后面跟上对应的值
  3. 传递后形成的路径:/router/123
  <!-- 动态路由params -->
  <!-- 在App.vue中 -->
  <router-link :to="'/user/' + userID"></router-link>
  <!-- 在index.js中 -->
  <script>
    {
     
     
      path:'/user/:userID',
      component:User
    }
  </script>

跳转方法:

// 方法1:
<router-link :to="{ name: 'users', params: { uname: wade }}">按钮</router-link>
<script>
  // 方法2:
  this.$router.push({
     
     name:'users',params:{
     
     uname:wade}})
  // 方法3:
  this.$router.push('/user/' + wade)
</script>

详情

5.vue-router 有哪几种导航钩子?

  • 第一种:全局导航钩子
  1. 前置守卫
//单独设置每个路由的属性:
meta: {
    
     may: true }
router.beforeEach((to, from, next) => {
    
    
  if (to.matched.some(item => item.meta.may)) {
    
    
      let id = window.localStorage.getItem("id")
      if (id) {
    
    
          next()
      } else {
    
    
          next({
    
     name: "login" })
      }
  } else {
    
    
      next()
  }
})

注意:next 方法必须要调用,否则钩子函数无法 resolved

2.后置钩子

router.afterEach((to,from) => {
    
    
	if(to.meta && to.meta.title){
    
    
		document.title = to.meta.title
	}else{
    
    
		document.title = "666"
	}
})
  • 第二种:单独路由独享钩子
{
    
    
  path: '/home',
  name: 'home',
  component: Home,
  beforeEnter(to, from, next) {
    
    
      if (window.localStorage.getItem("id")) {
    
    
          next()
      } else {
    
    
          next({
    
     name: "login" })
      }
  }
}

  • 第三种:组件内的钩子
beforeRouteEnter(to, from, next) {
    
    
    // do someting
    // 在渲染该组件的对应路由被 confirm 前调用
},
beforeRouteUpdate(to, from, next) {
    
    
    // do someting
    // 在当前路由改变,但是依然渲染该组件是调用
},
beforeRouteLeave(to, from ,next) {
    
    
    // do someting
    // 导航离开该组件的对应路由时被调用
}

全局解析守卫

router.beforeResolve 注册一个全局守卫,和 router.beforeEach 类似,

6. $route 和 $router 的区别

  • $route为当前router跳转对象里面可以获取name、path、query、params等

  • r o u t e r 为 V u e R o u t e r 实 例 , 想 要 导 航 到 不 同 U R L , 则 使 用 router为VueRouter实例,想要导航到不同URL,则使用 routerVueRouterURL使router.push方法

  • 返回上一个history也是使用$router.go方法

7. vue-router响应路由参数的变化

  • 当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用

8. vue-router传参 详解

vue-router传递参数分为两大类

  • 编程式的导航 router.push

编程式导航传递参数有两种类型:字符串、对象。

  • 声明式的导航 <router-link>

9. vue-router的两种模式 详解

hash模式

  • #后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。每次 hash 值的变化,会触发hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange来实现更新页面部分内容的操作:

history模式

  • 因为HTML5标准发布,多了两个 API,pushState() 和 replaceState()。通过这两个 API (1)可以改变 url 地址且不会发送请求,(2)不仅可以读取历史记录栈,还可以对浏览器历史记录栈进行修改。

  • 除此之外,还有popState().当浏览器跳转到新的状态时,将触发popState事件.

10.vue-router实现路由懒加载( 动态加载路由 )

  • 当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载.
component: () => import('@/components/Two')
const Index = () => import(/* webpackChunkName: "group-home" */  '@/views/index')
const routers = [
    {
    
    
        path: '/',
        name: 'index',
        component: Index
    }
]

vue 常见面试题

1.vue优点

  • 1.轻量级框架

    • 只关注视图层,是一个构建数据的视图集合,大小只有几十kb
    • Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统
  • 2.双向数据绑定

    • 也就是所谓的响应式数据绑定。这里的响应式不是@media 媒体查询中的响应式布局,而是指vue.js会自动对页面中某些数据的变化做出同步的响应。

    • 也就是说,vue.js会自动响应数据的变化情况,并且根据用户在代码中预先写好的绑定关系,对所有绑定在一起的数据和视图内容都进行修改。而这种绑定关系,就是以input 标签的v-model属性来声明的,因此你在别的地方可能也会看到有人粗略的称vue.js为声明式渲染的模版引擎。

    • 这也就是vue.js最大的优点,通过MVVM思想实现数据的双向绑定,让开发者不用再操作dom对象,有更多的时间去思考业务逻辑。

  • 3.组件化

    • 在前端应用,我们是否也可以像编程一样把模块封装呢?这就引入了组件化开发的思想。

    • Vue.js通过组件,把一个单页应用中的各种模块拆分到一个一个单独的组件(component)中,我们只要先在父级应用中写好各种组件标签(占坑),并且在组件标签中写好要传入组件的参数(就像给函数传入参数一样,这个参数叫做组件的属性),然后再分别写好各种组件的实现(填坑),然后整个应用就算做完了

  • 4.视图,数据,结构分离

    • 使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作
  • 5.虚拟DOM

    • 现在的网速越来越快了,很多人家里都是几十甚至上百M的光纤,手机也是4G起步了,按道理一个网页才几百K,而且浏览器本身还会缓存很多资源文件,那么几十M的光纤为什么打开一个之前已经打开过,已经有缓存的页面还是感觉很慢呢?这就是因为浏览器本身处理DOM也是有性能瓶颈的,尤其是在传统开发中,用JQuery或者原生的JavaScript DOM操作函数对DOM进行频繁操作的时候,浏览器要不停的渲染新的DOM树,导致页面看起来非常卡顿。

    • 而Virtual DOM则是虚拟DOM的英文,简单来说,他就是一种可以预先通过JavaScript进行各种计算,把最终的DOM操作计算出来并优化,由于这个DOM操作属于预处理操作,并没有真实的操作DOM,所以叫做虚拟DOM。最后在计算完毕才真正将DOM操作提交,将DOM操作变化反映到DOM树上

  • 6.运行速度更快

    • 像比较与react而言,同样都是操作虚拟dom,就性能而言,vue存在很大的优势

2.vue父组件向子组件传递数据?

父组件

<template>
  <div id="app">
    <!-- 使用v-bind命令将父组件中的数据绑定到子组件上 -->
    <Child :val_1="value_1" :val_2="value_2"></Child>
  </div>
</template>

<script>
  import Child from './components/Child.vue'

  export default {
     
     
    name: 'App',
    components: {
     
     
      Child
    },
    data: function () {
     
     
      return {
     
     
        value_1: "数据1",
        value_2: "数据2"
      }
    }
  }
</script>

子组件

  • 父组件中完成数据绑定之后,在子组件中的props属性接收一下父组件传递过来的数据,要接收多少数据,就在props属性中写多少数据。比如要接收两条数据
<template>
  <div class="Child">
    <h1>{
   
   { val_1 }}</h1>
    <h1>{
   
   { val_2 }}</h1>
  </div>
</template>

<script>
  export default {
     
     
    name: 'Child',

    // 在props属性里接收父组件传递过来的数据
    props:{
     
     
      val_1:String,
      val_2:String
    }
  }
</script>

3.子组件像父组件传递事件

子组件

<template>
  <div class="container">
    <div class="top">
      <p class="p_left">{
   
   {titleLeft}}</p>
      <p class="p_right" @click="clickAction">{
   
   {titleRight}}</p>
    </div>
    <div class="line"></div>
  </div>
</template>
 
<script>
export default {
     
     
  name: "HelloWorld",
  props:['titleLeft','titleRight'],
  data() {
     
     
    return {
     
     
    };
  },
  methods: {
     
     
      clickAction(){
     
     
        // 子组件需要使用this.$emit 将子组件的事件进行上级传递
        // 第一个参数是自定义事件名 第二个参数就是传递的参数
        this.$emit('clickHeadAction',this.titleRight);
      }
  }
};
</script>

父组件

<div class="message">

      <!-- 父组件需要使用@事件名的方式,接收子组件的事件。 -->
      <ActivityHead :titleLeft="msgLeft" :titleRight="msgRight" @clickHeadAction="clickChild"></ActivityHead>
 
 </div>
 
<script>
import ActivityHead from "./ActivityHead.vue";
import MessageItem from './MessageItem.vue'
export default {
     
     
  name: "HelloWorld",
  components: {
     
     
    ActivityHead,
    MessageItem
  },
  methods: {
     
     
      // msg 就是子组件 传递的数据
      clickChild(msg){
     
     
        console.log(msg);
      }
  }
};
</script>

4.v-show和v-if指令的共同点和不同点

  • 共同点
    • 都能控制元素的显示和隐藏
  • 不同点
    • 实现本质方法不同
      • v-show本质就是通过设置css中的display设置为none,控制隐藏
      • v-if是动态的向DOM树内添加或者删除DOM元素
    • 编译的区别
      • v-show其实就是在控制css
      • v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件
    • 编译的条件
      • v-show都会编译,初始值为false,只是将display设为none,但它也编译了
      • v-if初始值为false,就不会编译了
    • 性能
      • v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。
      • 注意点:因为v-show实际是操作display:" "或者none,当css本身有display:none时,v-show无法让显示

如果要频繁切换某节点时,使用v-show(无论true或者false初始都会进行渲染,此后通过css来控制显示隐藏,因此切换开销比较小,初始开销较大),如果不需要频繁切换某节点时,使用v-if(因为懒加载,初始为false时,不会渲染,但是因为它是通过添加和删除dom元素来控制显示和隐藏的,因此初始渲染开销较小,切换开销比较大)

5.如何让CSS只在当前组件中起作用

在组件中的style前面加上scoped就可以了

  <template>
  
  </template>

  <script>
  
  </script>

  <style scoped>
    .box{
     
     
      color:red;
    }
  </style>

6. <keep-alive></keep-alive>的作用是什么?

  • 官方: <keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。

  • 自我理解: (缓存)比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染

7.如何获取dom

  1. 直接获取(不推荐)
<template>
  <div class="home">
    <p id="text">hello vue</p>
  </div>
</template>

<script>
export default {
     
     
  name: 'Home',

  mounted(){
     
     
    // 原生方法
    let text = document.querySelector('text')
  }
}
</script>

<style>

</style>
  1. 通过ref(推荐)
<template>
  <div class="home">
    <p id="text" ref="txt">hello vue</p>
  </div>
</template>

<script>
export default {
     
     
  name: 'Home',

  mounted(){
     
     
    let txt = this.$refs.txt
  }
}
</script>

<style>

</style>

在获取相应元素之前,必须在mount钩子进行挂载,否则获取到的值为空,如果是给子组件加id并修改自定义属性,则直接会加载改子组件对应的外层div上,并不会改变该子组件原本的自定义属性的值。

8.说出几种vue当中的指令和它的用法?

v-show

设置元素的显示隐藏状态,是css级别的(display)

v-text、v-html

相当于innerText、innerHTML

v-if、v-else-if、v-else

我们可以通过条件判断来决定html是否渲染(在一些页面上,相同的位置,有不同的状态,就可以使用该方法去解决对应的渲染问题)

<div id="app">
  <!-- 当app有数据是渲染数据,没有数据时显示暂无数据 -->
  <div v-if="!arr.length">暂无数据</div>
  <div v-else>{
   
   {arr}}</div>
</div>

<script>
  new Vue({
     
     
    el: "#app",
    data: {
     
     
      arr: []
    }
  })
</script>

v-for

当我们要对数据进行遍历渲染列表时可以使用v-for
v-for一定要添加key,v-for和v-if尽量不要在同一个标签上使用,可以利用template标签

<!-- 
  item是自定义的名字,表示数组中遍历出的每一个单个的内容
  index是下标,也可以自定义名字
  arr是data中的数据的属性名
-->
<div v-for="item in arr"></div>
<div v-for="(item, index) in arr"></div>

<div v-for="(value, key, index) in obj"></div>

v-bind

在页面标签里插入内容用 { {}},如果我们想要在标签属性中插值,可以使用v-bind:属性="动态值"

v-bind可以缩写为:

<img :src="data中相关属性名">

class的绑定

class的绑定有多种用法

<div :class="className"></div>
<div :class="[className1, className2, className3]"></div>
<div :class="{active: activeStatus}"></div>
<div :class="['box', {active: activeStatus}]"></div>

style的绑定

样式的绑定后面跟着的可以是一个对象,对象中包含相关css属性及值

<div :style="{
       
       width: '100px', height: '100px'}"></div>

v-model

v-model是实现双向绑定的指令,v-model支持表单的各种元素。v-model就是为了方便我们获取表单中value值

见到表单元素就添加v-model,并且在data中给单独的表单设置单独的对象,对象中包含的所有属性都是每个表单元素的value

<input v-model="value">

v-on

v-on为了实现事件的绑定

<button @click="methods中的函数名">
<button v-on="{click: mehtods中函数, 其他事件类型: methods中函数}">

v-pre

不让vue进行渲染

v-once

只渲染一次,渲染后会失去和数据之间的管理

v-cloak

需要结合css使用

[v-cloak] {
    
    
  display: none;
}

9.vue-loader是什么?使用它的用途有哪些?

  • 解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理

10.为什么使用key

  • vue中循环需加 :key=“唯一标识” ,唯一标识可以使item里面id index 等,因为vue组件高度复用增加key可以标识组件的唯一性,为了更好地区别各个组件key的作用主要是为了高效的更新虚拟DOM
    key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度

11.axios及安装

  • cmd命令行进入到vue项目下,执行npm i -S axios

引入既可以使用

 import axios from 'axios'

12.axios解决跨域

  1. step1:配置 baseURL
    • 可以自定义一个 js 文件,也可以直接在 main.js 中写。

main.js

import Vue from 'vue'
import App from './App.vue'
// step1:引入 axios
import Axios from 'axios'

Vue.config.productionTip = false

// step2:把axios挂载到vue的原型中,在vue中每个组件都可以使用axios发送请求,
// 不需要每次都 import一下 axios了,直接使用 $axios 即可
Vue.prototype.$axios = Axios

// step3:使每次请求都会带一个 /api 前缀 
Axios.defaults.baseURL = '/api'

new Vue({
    
    
  render: h => h(App),
}).$mount('#app')
  1. step2:修改配置文件(修改后要重启服务)
    • vue 3.0 通过 vue.config.js 文件 修改配置(若没有,则直接在项目路径下新建即可)

vue.config.js

module.exports = {
    
    
    devServer: {
    
    
        proxy: {
    
    
            '/api': {
    
    
                // 此处的写法,目的是为了 将 /api 替换成 https://www.baidu.com/
                target: 'https://www.baidu.com/',
                // 允许跨域
                changeOrigin: true,
                ws: true,
                pathRewrite: {
    
    
                    '^/api': ''
                }
            }
        }
    }
}
  1. step3:修改 axios 使用方式

App.vue

<template>
    <div>
        <button @click="testAxios">TestAxios</button>
    </div>
    <!--App -->
</template>

<script>
    export default {
     
     
        methods: {
     
     
            testAxios() {
     
     
                // 由于 main.js 里全局定义的 axios,此处直接使用 $axios 即可。
                // 由于 main.js 里定义了每个请求前缀,此处的 / 即为 /api/, 
                // 经过 vue.config.js 配置文件的代理设置,会自动转为 https://www.baidu.com/,从而解决跨域问题
                this.$axios.get('/').then(response => {
     
     
                    if (response.data) {
     
     
                        console.log(response.data)
                    }
                }).catch(err => {
     
     
                    alert('请求失败')
                })
            }
        }
    }
</script>

<style>

</style>

13.v-modal的使用

  • v-model指令的本质是: 它负责监听用户的输入事件,从而更新数据,并对一些极端场景进行一些特殊处理。同时,v-model会忽略所有表单元素的value、checked、selected特性的初始值,它总是将vue实例中的数据作为数据来源。 然后当输入事件发生时,实时更新vue实例中的数据
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--引入最新的vue稳定版本-->
    <script type="text/javascript" src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <link rel="stylesheet" href="./css/style.css" type="text/css">
</head>
<body>


<!--input输入框-->
<div id="app">
     <input type="text" v-model="message" placeholder="请输入">
    <p>输入的内容是: {
   
   {message}}</p>
</div>

<script>
    var  vue=new Vue({
     
     
        el:'#app',
        data:{
     
     
           message:''
        }
    });
</script>
</body>
</html>

原理

 <input v-bind:value="message" v-on:input="message = $event.target.value" />
//把input输入框的value属性值和vue实例的message属性进行绑定,同时监听输入事件。

14.scss的安装以及使用

  1. 安装
npm install node-sass --save-dev //安装node-sass 
npm install sass-loader --save-dev //安装sass-loader 
npm install style-loader --save-dev //安装style-loader 有些人安装的是 vue-style-loader 其实是一样的!
  1. 配置文件
  • 在webpack.base.conf.js 文件下的配置 rules
rules:[
  {
    
     
    //从这一段上面是默认的!不用改!下面是没有的需要你手动添加,相当于是编译识别scss!
      test: /\.scss?$/,
      loaders: ["style", "css", "sass"]
  }
]
  1. 在vue模板组件中引用lange=“scss”
  <template></template>
  <script></script>
  <style lang="scss" scoped>
    ···
  </style>

15.请说出vue.cli项目中src目录每个文件夹和文件的用法?

  • assets 文件夹是放静态资源
  • components 是放组件
  • router 是定义路由相关的配置
  • view 视图
  • app.vue 是一个应用主组件
  • main.js 是入口文件

16.分别简述computed和watch的区别、使用场景

computed:通过属性计算而得来的属性

  1. computed内部的函数在调用时不加()。

  2. computed是依赖vm中data的属性变化而变化的,也就是说,当data中的属性发生改变的时候,当前函数才会执行,data中的属性没有改变的时候,当前函数不会执行。

  3. computed中的函数必须用return返回。

  4. 在computed中不要对data中的属性进行赋值操作。如果对data中的属性进行赋值操作了,就是data中的属性发生改变,从而触发computed中的函数,形成死循环了。

  5. 当computed中的函数所依赖的属性没有发生改变,那么调用当前函数的时候会从缓存中读取。

  • 使用场景:当一个值受多个属性影响的时候------------购物车商品结算

watch:属性监听

  1. watch中的函数名称必须要和data中的属性名一致,因为watch是依赖data中的属性,当data中的属性发生改变的时候,watch中的函数就会执行。

  2. watch中的函数有两个参数,前者是newVal,后者是oldVal。

  3. watch中的函数是不需要调用的。

  4. watch只会监听数据的值是否发生改变,而不会去监听数据的地址是否发生改变。也就是说,watch想要监听引用类型数据的变化,需要进行深度监听。“obj.name”(){}------如果obj的属性太多,这种方法的效率很低,obj:{handler(newVal){},deep:true}------用handler+deep的方式进行深度监听。

  5. 特殊情况下,watch无法监听到数组的变化,特殊情况就是说更改数组中的数据时,数组已经更改,但是视图没有更新。更改数组必须要用splice()或者 s e t 。 t h i s . a r r . s p l i c e ( 0 , 1 , 100 ) − − − − − 修 改 a r r 中 第 0 项 开 始 的 1 个 数 据 为 100 , t h i s . set。this.arr.splice(0,1,100)-----修改arr中第0项开始的1个数据为100,this. setthis.arr.splice(0,1,100)arr01100this.set(this.arr,0,100)-----修改arr第0项值为100。

  6. immediate:true 页面首次加载的时候做一次监听。

  • 使用场景:当一条数据的更改影响到多条数据的时候---------搜索框

区别:

  1. 功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。

  2. 是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。

  3. 是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。

  4. 使用场景:computed----当一个属性受多个属性影响的时候,使用computed-------购物车商品结算。watch----当一条数据影响多条数据的时候,使用watch-------搜索框

17.v-on可以监听多个方法吗

可以

  <template>
    <div>
      <button @click="a(),b()">点我ab</button>
    </div>
  </template>

  <script>
    export default {
     
     
      methods:{
     
     
        a() {
     
     
          console.log("a");
        },
        b() {
     
     
          console.log("b");
      }

    }
  </script>

18.$nextTick的使用

  • this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
<template>
  <section>
    <div ref="hello">
      <h1>Hello World ~</h1>
    </div>
    <el-button type="danger" @click="get">点击</el-button>
  </section>
</template>
<script>
  export default {
     
     
    methods: {
     
     
      get() {
     
     
      }
    },
    mounted() {
     
     
      console.log(333);
      console.log(this.$refs['hello']);
      this.$nextTick(() => {
     
     
        console.log(444);
        console.log(this.$refs['hello']);
      });
    },
    created() {
     
     
      console.log(111);
      console.log(this.$refs['hello']);
      this.$nextTick(() => {
     
     
        console.log(222);
        console.log(this.$refs['hello']);
      });
    }
  }
</script>

运行结果

111 undefined
333


222

444

19.vue组件中data为什么必须是一个函数

  • 如果data是一个函数的话,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。

  • 所以说vue组件的data必须是函数。这都是因为js的特性带来的,跟vue本身设计无关。

  • js本身的面向对象编程也是基于原型链和构造函数,应该会注意原型链上添加一般都是一个函数方法而不会去添加一个对象了。

20.vue事件对象的使用

  • 事件无参数
  <template>
    <div>
      <button @click="fun">点我ab</button>
    </div>
  </template>

  <script>
    export default {
     
     
      methods:{
     
     
        // 当事件不携带参数时 函数有一个默认的参数`e` 就是事件对象
        fun(e) {
     
     
         console.log(e);
        }
    }
  </script>
  • 事件有参数
  <template>
    <div>
      <button @click="fun($event,111)">点我ab</button>
    </div>
  </template>

  <script>
    export default {
     
     
      methods:{
     
     
        // 当事件携带参数时 可以通过`$event`获取事件对象 
          // e 就是事件对象 
          // msg 是111
        fun(e,msg) {
     
     
         console.log(e);
         console.log(msg);
        }
    }
  </script>

21. 组件间的通信

组件通信-父子通信

  • 父子通信,利用在父组件模板中,给子组件添加属性的方法进行通信,一旦添加了属性,那么在子组件中可以通过props进行接收

父组件

<template>
  <div>
    {
   
   {msg}}
    <Child :msg="msg"></Child>
  </div>
</template>

<script>
  export default {
     
     
    data () {
     
     
      return {
     
     
        msg: '父组件中的msg'
      }
    }
  }
</script>

子组件

{
    
    
  props: {
    
    
    msg: String
  }
}

组件通信-子父通信

  • 我们需要借助于原生事件去触发自定义事件(在子组件中触发),在父组件模板中找到子组件标签,并且监听该自定义事件,那么事件执行的函数中会有一个参数,这个参数就是触发自定义事件的携带的数据

子组件

const child = {
    
    
  template: `
    <div>
      <button @click="clickHandler">点击传递数据</button>
    </div>
  `,

  methods: {
    
    
    clickHandler () {
    
    
      this.$emit('自定义事件名', 要传递的数据)
    }
  } 
}

父组件

const parent = {
    
    
  template: `
    <div>
      <child @自定义事件名="要执行的函数"></child>
    </div>
  `,

  methods: {
    
    
    要执行的函数 (param) {
    
    
      // 这个参数就是$emit时传递的数据
    }
  }
}

组件通信-非父子通信

  • 非父子通信需要借助一个公共的vue实例(事件总线)

bus.js

const bus = new Vue()

组件1

const com1 = {
    
    
  template: `
    <div>
      <button @click="clickHandler"></button>
    </div>
  `,
  methods: {
    
    
    clickHandler () {
    
    
      bus.$emit('自定义事件名', 数据)
    }
  }
}

组件2

const com2 = {
    
    
  template: `
    <div>
      
    </div>
  `,
  created () {
    
    
    bus.$on('自定义事件名', (data) => {
    
    
      // data就是传递的数据
    })
  }
}

暂就列举三种常用的

22.渐进式框架的理解

  • 渐进式代表的含义是:主张最少。

    • 每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。
  • Vue可能有些方面是不如React,不如Angular,但它是渐进的,没有强主张,你可以在原有大系统的上面,把一两个组件改用它实现,当jQuery用;也可以整个用它全家桶开发,当Angular用;还可以用它的视图,搭配你自己设计的整个下层用。你可以在底层数据逻辑的地方用OO和设计模式的那套理念,也可以函数式,都可以,它只是个轻量视图而已,只做了自己该做的事,没有做不该做的事,仅此而已。
    渐进式的含义,我的理解是:没有多做职责之外的事。

23.Vue中双向数据绑定是如何实现的

  • 根据官方文档的解释,v-model其实是一个语法糖,它会自动的在元素或者组件上面解析为 :value="" 和 @input="", 就像下面这样
<!-- 标准写法 -->
<input v-model="name">

<!-- 等价于 -->
<input :value="name" @input="name = $event.target.value">

<!-- 在组件上面时 -->
<div :value="name" @input="name = $event"></div>
  1. 当在input输入框输入内容时,会自动的触发input事件,更新绑定的name值。

  2. 当name的值通过JavaScript改变时,会更新input的value值

    • 根据上面的原理,vue就通过v-model实现双向数据绑定
  • 看了前面的解释,对于v-model有了一定的理解。下面我们就来实现自己组件上面的v-model吧

  • 需求:实现一个简单的点击按钮,每次点击都自动的给绑定值price加100。 组件名为 AddPrice.vue

<!-- AddPrice.vue -->
<!-- 通过props接受绑定的value参数 -->
<template>
  <div @click="$emit('input',value + 100 )">点击加钱<div>
</template>

<script>
  export default {
     
     
    props: ['value']
  }
    
</script>

<!-- 在父组件中调用 -->
<add-price v-model="price"></add-price>

组件中使用props接受传入的参数值value, 组件点击事件触发并 使用$emit调用父组件上的input事件,实现了自定义的双向绑定

24.单页面应用和多页面应用区别及优缺点

单页面应用(SinglePage Web Application,SPA)

  • 只有一张Web页面的应用,是一种从Web服务器加载的富客户端,单页面跳转仅刷新局部资源 ,公共资源(js、css等)仅需加载一次,常用于PC端官网、购物等网站

多页面应用(MultiPage Application,MPA)

  • 多页面跳转刷新所有资源,每个公共资源(js、css等)需选择性重新加载,常用于 app 或 客户端等

具体对比分析:

单页面应用(SinglePage Web Application,SPA) 多页面应用(MultiPage Application,MPA)
组成 一个外壳页面和多个页面片段组成 多个完整页面构成
资源共用(css,js) 共用,只需在外壳部分加载 不共用,每个页面都需要加载
刷新方式 页面局部刷新或更改 整页刷新
url 模式 a.com/#/pageonea.com/#/pagetwo a.com/pageone.htmla.com/pagetwo.html
用户体验 页面片段间的切换快,用户体验良好 页面切换加载缓慢,流畅度不够,用户体验比较差
转场动画 容易实现 无法实现
数据传递 容易 依赖 url传参、或者cookie 、localStorage等
搜索引擎优化(SEO) 需要单独方案、实现较为困难、不利于SEO检索 可利用服务器端渲染(SSR)优化 实现方法简易
试用范围 高要求的体验度、追求界面流畅的应用 适用于追求高度支持搜索引擎的应用
开发成本 较高,常需借助专业的框架 较低 ,但页面重复代码多
维护成本 相对容易 相对复杂

25.vue中过滤器有什么作用及详解

  • vue中的过滤器分为两种:局部过滤器和全局过滤器
<div id="app">
  <p>{
   
   { msg | msgFormat}}</p>
</div>

<script>
    // 定义一个 Vue 全局的过滤器,名字叫做  msgFormat
    Vue.filter('msgFormat', function(msg) {
     
     
        // 字符串的  replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则
        return msg.replace(/单纯/g, 'xx')
    })
</script>
  • 定义有参全局过滤器
  <div id="app">
      <p>{
   
   { msg | msgFormat('疯狂','--')}}</p>
  </div>

  <script>
    // 定义一个 Vue 全局的过滤器,名字叫做  msgFormat
    Vue.filter('msgFormat', function(msg, arg, arg2) {
     
     
        // 字符串的  replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则
        return msg.replace(/单纯/g, arg+arg2)
    })
  </script>
  • 局部过滤器
    • 局部过滤器的有参和无参的定义和使用方法与全局的过滤器一样。唯一的区别在于局部过滤器是定义在vue的实例中。其作用的区域也是vue实例【#app】控制的区域
  // 创建 Vue 实例,得到 ViewModel
  var vm = new Vue({
    
    
    el: '#app',
    data: {
    
    
        msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的男人'
    },
    methods: {
    
    },
    //定义私用局部过滤器。只能在当前 vue 对象中使用
    filters: {
    
    
        dataFormat(msg) {
    
    
            return msg+'xxxxx';
        }
    }
  });

注意:

  1. 当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!

  2. 一个表达式可以使用多个过滤器。过滤器之间需要用管道符“|”隔开。其执行顺序从左往右

26.v-if和v-for的优先级

  • v-for和v-if不应该一起使用,必要情况下应该替换成computed属性。原因:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。

  • 错误写法

<li
  v-for="user in users"
  v-if="user.isActive"
  :key="user.id"
  >
  {
   
   { user.name }}
</li>
  • 正确写法
<script>
  computed: {
     
     
    activeUsers: function () {
     
     
      return this.users.filter(function (user) {
     
     
        return user.isActive
      })
    }
  }
</script>
<ul>
    <li
          v-for="user in activeUsers"
          :key="user.id"
        >
        {
   
   { user.name }}
    </li>
</ul>

27.assets和static的区别

  • assets和static两个都是用于存放静态资源文件。

  • 放在static中的文件不会进行构建编译处理,也就不会压缩体积,在打包时效率会更高,但体积更大在服务器中就会占据更大的空间

  • 放在assets中的文件会进行压缩体积、代码格式化,压缩后会放置在static中一同上传服务器。

  • 因此建议样式文件放在assets中进行打包,引入的第三方文件放到static中,因为引入的文件已经做过打包处理

28.列举常用的指令

  1. 文本插值:{ { }} Mustache
  2. DOM属性绑定: v-bind
  3. 指令绑定一个事件监听器:v-on
  4. 实现表单输入和应用状态之间的双向绑定:v-model
  5. 控制切换一个元素的显示:v-if 和 v-else
  6. 列表渲染:v-for

29.vue常用的修饰符

  • v-model 修饰符

    • .lazy : 在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步
    • .number : 如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符
    • .trim : 如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符
  • v-on 修饰符

<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

30.数组更新检测

Vue 包含两种观察数组的方法分别如下

  1. 变异方法

    • 顾名思义,变异方法会改变被这些方法调用的原始数组,它们也将会触发视图更新,这些方法如下
  • push()

  • pop()

  • shift()

  • unshift()

  • splice()

  • sort()

  • reverse()

使用举例:example1.items.push({ message: ‘Baz’ })

  1. 非变异方法
  • 非变异方法与变异方法的区别就是,非变异方法不会改变原始数组,总是返回一个新数组,

  • 当使用非变异方法时,可以用新数组替换旧数组,非变异方法大致有:filter(), concat() 和 slice()

  • 使用举例:

由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

  1. 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue

  2. 当你修改数组的长度时,例如:vm.items.length = newLength

vue针对这两个问题给出了相应的解决办法,使用这两种方法,也会触发状态更新

  1. 使用vue全局方法Vue.set() 或者使用vm.$set() 实例方法

  2. 使用 splice,caoncat等修改数组

总结

  • vue能不能检测到数组的变化并更新,取决于原生js的数组方法,

  • 如果原生js方法(vue变异方法)能够修改原数组,那么vue就可以检测到变化并更新(例如push等方法)

  • 如果原生js方法(vue非变异方法)不能够修改原数组,而是返回一个新数组,那么vue也可以检测到变化并更新,前提是使用这些方法时要把新数组返回出来去替换掉旧数组

  • 至于原生js的数组的两个坑,我们一定到注意,直接利用vue提供的方法来解决

31. Vue.set视图更新

Vue.set()动态的新增与修改数据,触发视图更新的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h5FMVrvE-1602938325289)(https://s1.ax1x.com/2020/10/12/0RxhE4.png)]

  • target:要更改的数据源(可以是对象或者数组)

  • key:要更改的具体数据(可以是字符串和数字)

  • value :重新赋的值

用法:向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。

data:{
    
    
  namelist:[
    {
    
    message:"张大仙",id:"1"},
    {
    
    message:"梦泪",id:"2"},
    {
    
    message:"一诺",id:"3"}
  ]
}
Vue.set(this.namelist,1,{
    
    message:"yeluosen",id:"1"})

注:Vue.set()在methods中也可以写成this.$set()

Vue.set()不光能修改数据,还能添加数据

data:{
    
    
  items:[
    {
    
    message:"Test one",id:"1"},
    {
    
    message:"Test two",id:"2"},
    {
    
    message:"Test three",id:"3"}
  ]
},
const itemLen=this.items.length;
Vue.set(this.items,itemLen,{
    
    message:"Test add attr",id:itemLen});

32.自定义指令详解 详解

  • 可以使用Vue.directive( dir_name , {} ) 来定义全局自定义指令
  • 也可以使用 directives{ dir_name : {} } 来定义局部自定义指令

33.vue的两个核心点

  1. 数据驱动
    • 在vue中,数据的改变会驱动视图的自动更新。传统的做法是需要手动改变DOM来使得视图更新,而vue只需要改变数据。
  2. 组件
    • 组件化开发,优点很多,可以很好的降低数据之间的耦合度。将常用的代码封装成组件之后(vue组件封装方法),就能高度的复用,提高代码的可重用性。一个页面/模块可以由多个组件所组成。

34. vue和jQuery的区别

  1. jquery介绍:想必大家都用过jquery吧,这个曾经也是现在依然最流行的web前端js库,可是现在无论是国内还是国外他的使用率正在渐渐被其他的js库所代替,随着浏览器厂商对HTML5规范统一遵循以及ECMA6在浏览器端的实现,jquery的使用率将会越来越低

  2. vue介绍:vue是一个兴起的前端js库,是一个精简的MVVM。从技术角度讲,Vue.js 专注于 MVVM 模型的 ViewModel 层。它通过双向数据绑定把 View 层和 Model 层连接了起来,通过对数据的操作就可以完成对页面视图的渲染。当然还有很多其他的mvmm框架如Angular,React都是大同小异,本质上都是基于MVVM的理念。 然而vue以他独特的优势简单,快速,组合,紧凑,强大而迅速崛起

  3. vue和jquey对比 jQuery是使用选择器()选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容:)选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容:(“lable”).val();,它还是依赖DOM元素的值。 Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。

35. 引进组件的步骤

引入组件=>注册组件=>使用组件

  • 方法一
import navs from '@/views/nav/index'
components:{
    
    
  'v-nav':navs
}
  <v-nav></v-nav>
  • 方法二
import navs from '@/views/nav/index'
import indexList from './index-list'
components: {
    
     navs,indexList },
<index-list></index-list>
<navs></navs>

36.Vue-cli打包命令是什么?打包后悔导致路径问题,应该在哪里修改

npm run build

在根目录下,新建 vue.config.js文件,内容如下,

  module.exports = {
    
     
    publicPath:'./',
    configureWebpack:{
    
     
      resolve: {
    
     
        alias: {
    
     'assets': '@/assets',
         'common': '@/common', 
         'components': '@/components', 
         'network': '@/network', 
         'views': '@/views', 
         'plugins': '@/plugins', 
         } 
        } 
      } 
    }

37.三大框架的对比

  • angular(MVW):
  1. 在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。
  • vue(mvvm):
  1. 轻量级框架
  2. 在性能上,Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都是独立触发的。
  3. 在状态管理方面,使用的是vuex,vue比angular和react的运行速度快。
  • react (mvc):
  1. React采用特殊的JSX语法。
  2. React采用特殊的JSX语法,React采用的Virtual DOM会对渲染出来的结果做脏检查。
  3. 在状态管理方面,使用的是Redux

38.跨组件双向数据绑定

  • 主要思想:子组件通过 this.$emit(‘input’),改变父组件 v-model 绑定的值。

39.delete和Vue.delete删除数组的区别

  • delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。

  • Vue.delete 直接删除了数组 改变了数组的键值

<template>
  <div class="vue-delete">
    <p class="title tag-blue">
      delete和Vue.delete删除数组的区别
    </p>
    <ul>
      <li :key="index" v-for="(item, index) in a">a---{
   
   {item}}</li>
    </ul>
    <button @click="handleA">处理a数组</button>
    <ul>
      <li :key="index" v-for="(item, index) in b">b---{
   
   {item}}</li>
    </ul>
    <button @click="handleB">处理b数组</button>
  </div>
</template>
<script>
export default {
     
     
  name: "vueDelete",
  data() {
     
     
    return {
     
     
      a: [1,2,3,4],
      b: [1,2,3,4],
    }
  },
  methods: {
     
     
    handleA() {
     
     
      delete this.a[1]
      this.$set(this.a)
      console.log(this.a)
    },
    handleB() {
     
     
      this.$delete(this.b, 1)
      console.log(this.b)
    }
  }
}
</script>

40. SPA首屏加载慢如何解决

  1. 将公用的js库用script引入,让浏览器并行下载资源

  2. 配置路由,组件,页面。使用懒加载,在调用某个组件时在下载 某个js

  3. 加一个首屏的loading图,可以提高用户体验

41. Vue-router跳转和location.href有什么区别

  • 使用location.href=’/url’来跳转,简单方便,但是刷新了页面;

  • 使用history.pushState(’/url’),无刷新页面,静态跳转;

  • 引进router,然后使用router.push(’/url’)来跳转,使用了diff算法,实现了按需加载,减少了dom的消耗。

  • 其实使用router跳转和使用history.pushState()没什么差别的,因为vue-router就是用了history.pushState(),尤其是在history模式下。

42.vue slot

  • 理解:Vue插槽

  • 插槽是Vue组件的一种机制,它允许你以一种不同于严格的父子关系的方式组合组件。插槽为你提供了一个将内容放置到新位置或使组件更通用的出口

举个例子

frame.vue

<template>
  <div class="frame">
    <slot></slot>
  </div>
</template>

app.vue

<template>
  <frame><img src="an-image.jpg"></frame>
</template>

可以向组件添加多个插槽,但是如果这样做了,那么除了其中一个之外,其他所有插槽都需要有名称。如果有一个没有名称的槽 ————
详解

43.你们vue项目是打包了一个js文件,一个css文件,还是有多个文件?

  • 因为vue-cli打包使用的webpack,所以会遵循webpack的打包规则,vue-cli默认配置举例,一个index.html文件,多个css文件,多个js文件

44. vue遇到的坑,如何解决的?

根据自己的实战经历

  • 例:

    1. 同一个路由都次点击,浏览器报错问题

45.Vue里面router-link在电脑上有用,在安卓上没反应怎么解决?

  • 答:Vue路由在Android机上有问题,babel问题,安装babel polypill插件解决

46.Vue2中注册在router-link上事件无效解决方法

问题产生原因:如果当前router-link的tag不是a的话(官方文档中说明:默认为a,可以通过tag改变渲染后的标签),那么就会往自己的子元素(组件)找,找到的第一个就会把一些属性及时间覆盖过去。所以此时事件是被阻止了。个人看法:因为router-link的作用是单纯的路由跳转,如果不阻止事件的话,也许会有很多坑,所以作者干脆阻止了其他事件的触发
  • 解决方法:只需要在@click后面加上native就可以了
      <router-link  @click.native="change"><span>{
   
   {item.text}}</span></router-link>
  • 原生事件:添加native事件修饰符之后变为原生事件
$element.addEventListener(click, callback);
  • 此时a标签并不会阻止,至此便可以解决绑定在router-link身上的事件不会触发的问题。
    其次,想要实现tab切换添加class可以在router中添加如下配置:
export default new Router({
    
    
  routes: [],// 路由跳转配置
  linkActiveClass:'active' // 在路由中添加配置  active 为跳转到该路由时添加的激活类名
})

47. RouterLink在IE和Firefox中不起作用(路由不跳转)的问题

  • 模拟代码
  <button type="button" clrDropdownItem >
	<a routerLink="/admin"> Admin </a>
</button>
  1. 方法一:将 clrDropdownItem 样式放在<a>标签,不使用<button>标签
<a clrDropdownItem routerLink="/admin"> Admin </a>
  1. 方法二:使用<button>标签和Router.navigate方法
<button type="button" clrDropdownItem (click)="gotoAdmin()">
    Admin
</button>
  import {
    
     Router } from '@angular/router';
  export class MainComponent  {
    
    
      constructor(
          private router: Router
      ) {
    
    }
      
      gotoAdmin() {
    
    
          this.router.navigate(['/admin']);
      }
  }

48. axios的特点有哪些

  1. 从浏览器中创建XMLHttpRequests
  2. node.js创建http请求
  3. 支持Promise API
  4. 拦截请求和响应
  5. 转换请求数据和响应数据
  6. 取消请求
  7. 自动换成json
  • axios中的发送字段的参数是data跟params两个
    两者的区别在于params是跟请求地址一起发送的,data的作为一个请求体进行发送
    params一般适用于get请求
    data一般适用于post put 请求

49.请说下封装 vue 组件的过程?

  • 首先,使用Vue.extend()创建一个组件

  • 然后,使用Vue.component()方法注册组件

组件创建—有3中方法,extend() <template id=''> <script type='text/x-template' id=''>


A、调用Vue.extend(),创建名为myCom的组件,template定义模板的标签,模板的内容需写在该标签下

var myCom = Vue.extend({
    
    
    template: '<div>这是我的组件</div>'
})

B、<template id='myCom'>标签创建,需要加上id属性

<template id="myCom">
    <div>这是template标签构建的组件</div>
</template>

C、 <script type='text/x-template' id='myCom'>,需加id属性,同时还得加type="text/x-template",加这个是为了告诉浏览器不执行编译里面的代码

<script type="text/x-template" id="myCom1">
    <div>这是script标签构建的组件</div>
</script>

注册组件----有2中方法,全局注册,局部注册


A1、全局注册:一次注册( 调用Vue.component( 组件名称,为组件创建时定义的变量 ) ),可在多个Vue实例中使用。

  • 我们先用全局注册,注册上面例子中创建的myCom组件

  • 'my-com'为给组件自定义的名字,在使用时会用到,后面myCom对应的就是上面构建的组件变量

Vue.component('my-com',myCom)

A2、全局注册语法糖:不需要创建直接注册的写法

Vue.component('my-com',{
    
    
    'template':'<div>这是我的组件</div>'
})

A3、如果是用template及script标签构建的组件,第二个参数就改为它们标签上的id值


var app = new Vue({
    
    
    el: '#app',
    components: {
    
    
        'my-com': myCom
    }
})


B1、局部注册:只能在注册该组件的实例中使用,一处注册,一处使用

  var app = new Vue({
    
    
    el: '#app',
    components: {
    
    
        'my-com': myCom
    }
  })

B2、局部注册语法糖:

  var app = new Vue({
    
    
    el: '#app',
    components: {
    
    
        'my-com': {
    
    
           template: '<div>这是我的组件</div>'
        }
    }
  })

B3、<template><script>创建的组件,局部注册

var app = new Vue({
    
    
    el: '#app',
    components: {
    
    
        'my-com': {
    
    
           template: '#myCom'
        }
    }
})

调用方法

  <div>
    <my-com></my-com>
  </div>

50.vue 各种组件通信方法(父子 子父 兄弟 爷孙 毫无关系的组件)

组件通信-父子通信

父子通信,利用在父组件模板中,给子组件添加属性的方法进行通信,一旦添加了属性,那么在子组件中可以通过props进行接收

<template>
  <div>
    {
   
   {msg}}
    <Child :msg="msg"></Child>
  </div>
</template>

<script>
  export default {
     
     
    data () {
     
     
      return {
     
     
        msg: '父组件中的msg'
      }
    }
  }
</script>

子组件

{
    
    
  props: {
    
    
    msg: String
  }
}

组件通信-子父通信

我们需要借助于原生事件去触发自定义事件(在子组件中触发),在父组件模板中找到子组件标签,并且监听该自定义事件,那么事件执行的函数中会有一个参数,这个参数就是触发自定义事件的携带的数据
子组件

const child = {
    
    
  template: `
    <div>
      <button @click="clickHandler">点击传递数据</button>
    </div>
  `,

  methods: {
    
    
    clickHandler () {
    
    
      this.$emit('自定义事件名', 要传递的数据)
    }
  } 
}

父组件

const parent = {
    
    
  template: `
    <div>
      <child @自定义事件名="要执行的函数"></child>
    </div>
  `,

  methods: {
    
    
    要执行的函数 (param) {
    
    
      // 这个参数就是$emit时传递的数据
    }
  }
}

组件通信-非父子通信

非父子通信需要借助一个公共的vue实例(事件总线)

bus

const bus = new Vue()

组件1

const com1 = {
    
    
  template: `
    <div>
      <button @click="clickHandler"></button>
    </div>
  `,
  methods: {
    
    
    clickHandler () {
    
    
      bus.$emit('自定义事件名', 数据)
    }
  }
}

组件2

const com2 = {
    
    
  template: `
    <div>
      
    </div>
  `,
  created () {
    
    
    bus.$on('自定义事件名', (data) => {
    
    
      // data就是传递的数据
    })
  }
}

51.params和query的区别

52.vue mock数据

mock:模拟后台接口

  1. 安装,开发环境
npm i mockjs -D
  1. 在src目录新建mock文件夹,结构如下:

src

mock

json

homeBanner.json

userInfo.json

index.js

  1. index.js内容:
const Mock = require('mockjs');
//格式: Mock.mock( url, post/get , 返回的数据);
Mock.mock('/user/userInfo', 'get', require('./json/userInfo'));
Mock.mock('/home/banner', 'get', require('./json/homeBanner'));
  1. json文件夹内容如下,userInfo.json为例:
{
    
    
  "result": "success",
  "data": {
    
    
    "userSn": "3785521",
    "username": "不求甚解",
    "age": 25,
    "imgUrl": "https://avatar.csdn.net/8/5/D/3_bocongbo.jpg"
  },
  "msg": ""
}
  1. 在main.js入口文件中引入mock数据,不需要时,则注释掉。
import Vue from 'vue';
import App from './App';
import router from './router';
 
require('./mock'); //引入mock数据,关闭则注释该行
 
Vue.config.productionTip = false;
 
new Vue({
    
    
  el: '#app',
  router,
  components: {
    
     App },
  template: '<App/>'
});
  1. 在vue模板访问
axios.get('/user/userInfo')
.then(function(res){
    
    
  console.log(res);
})
.catch(function(err){
    
    
  console.log(err);
});

53. vue封装通用组件

传送门

54. vue初始化页面闪动问题

  • vue页面在加载的时候闪烁花括号{ {}},v-cloak指令和css规则如[v-cloak]:{display:none}一起用时,这个指令可以隐藏未编译的Mustache标签直到实例准备完毕。
[v-cloak] {
    
    
  display: none;
}
<div id="app" v-cloak>
  <ul>
    <li v-for="item in tabs">{
   
   {item.text}}</li>
  </ul>
</div>

55.vue禁止弹窗后的屏幕滚动

  methods : {
    
    
   //禁止滚动
   stop(){
    
    
        var mo=function(e){
    
    e.preventDefault();};
        document.body.style.overflow='hidden';
        document.addEventListener("touchmove",mo,false);//禁止页面滑动
    },
    /***取消滑动限制***/
    move(){
    
    
        var mo=function(e){
    
    e.preventDefault();};
        document.body.style.overflow='';//出现滚动条
        document.removeEventListener("touchmove",mo,false);
    }
  }

另一种方法:传送门

56.vue更新数组时触发视图更新的方法

以下方法调用会改变原始数组

  push()
  pop()
  shift()
  unshift()
  splice()
  sort()
  reverse()
  • push()

    • push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
    example1.items.push({
          
           message: 'Baz' })
    
  • pop()

    • pop() 方法用于删除最后一个元素,把数组长度减 1,并且返回它删除的元素的值。
  • shift()

    • shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
  • unshift()

    • unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
  • splice()

    • splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。 该方法会改变原始数组。
  • sort()

    • sort() 方法用于对数组的元素进行排序
  • reverse()

    • reverse() 方法用于颠倒数组中元素的顺序
  • set()

    • Vue.set() 响应式新增与修改数据
    1. 调用方法:Vue.set( target, key, value )
    2. target:要更改的数据源(可以是对象或者数组)
    3. key:要更改的具体数据
    4. value :重新赋的值
      Vue.set(this.items,itemLen,{
          
          message:"Test add attr",id:itemLen});
      // Vue.set()在methods中也可以写成this.$set()
    

以下方法调用不会改变原始数组

  filter(), consat(), slice() 
  // 他们返回的是一个新数组,使用这些方法时,可以用新数组来替换原始数组

57.vue常用的UI组件库

  • Vuetify
  • Bootstrap-Vue
  • Vue-blu
  • MintUI
  • Vue-strap
  • ElementUI

58. vue如何引进本地背景图片

  1. 只引入单个图片,这种引入方法在异步中引入则会报错。 比如需要遍历出很多图片展示时
<image :src = require('图片的路径') />
  1. 可引入多个图片,也可引入单个图片。 vuelic3版本没有static文件夹。可将静态图片存放到public目录下,直接引入即可
<image src="/public/image/logo.png"/>

59. vue如何引进sass

  1. 先在vue-cli项目中安装Sass依赖包

    npm install sass-loader --save-dev

    npm install node-sass --save-dev

  2. 执行完毕后,找到build文件夹,在文件夹里面的webpack.base.conf.js中修改以下配置:

    • 在module下的rules里添加配置:
    {
    
    
    test: /\.sass$/,
    loaders: [‘style‘, ‘css‘, ‘sass‘]
   }
  1. 在使用sass的vue文件的,只需设置lang=“scss”
<style>
  $font-size: 24px;
  .box{
     
     
    font-size: $font-size;
  }
</style>

60. vue修改打包后静态资源路径的修改

  • cli2版本:将 config/index.js 里的 assetsPublicPath 的值改为 './'
  build: {
    
    
  ...
  assetsPublicPath: './',
  ...  
}
  • cli3版本:在根目录下新建 vue.config.js 文件,然后加上以下内容:(如果已经有此文件就直接修改)
module.exports = {
    
    
  publicPath: '', // 相对于 HTML 页面(目录相同)
}

猜你喜欢

转载自blog.csdn.net/yaoguaia/article/details/109137873