前高频端面试题合集24-vue基本语法使用

1. 路由

1.1 router的使用方式

  1. 在router/index.js的文件中引入vue-router,Vue.use(VueRouter)

  2. new VueRouter 导出

  3. 创建vue实例的地方,引入router

  4. 在具体的页面中使用router-link标签 :to属性配置path或者name query或者 params

  5. 使用router-view标签展示link的链接的组件

1.2 router跳转+传参

1.2.1 路由跳转的四种方式

1
2
3
<router-link to="/home"> </router-link>
<router-link :to="{name:'home'}"> </router-link>
<router-link :to="{path:'/home'}"></router-link>
1
2
3
4
5
this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})
this.$router.replace() // (用法同上,push)
this.$router.go(n) // n是n可为正整数或负整数

1.2.2 路由传参的三种方式

  1. 路径带?key=value

    1
    <router-link to="/about?id=1">About</router-link>
  2. query 相当于get

    1
    <router-link :to="{path:'/query',query:{id:12}}">带参数query</router-link>
  3. params 相当于post

    1
    <router-link :to="{name:'Params',params:{id:11}}">带参数params</router-link>

1.2.3 获取路由参数的方法

1
2
3
4
// 路径传参和query属性传参,都用该方式获取参数
this.$route.query.val
// params属性传参,用该方式获取
this.$route.params.val

1.3 动态路由

作用:多个路由对应同一个组件,根据路由配置id不同,获取不同参数,进行相应处理

1.4 路由嵌套

作用:一个页面某个位置根据链接不同,展示不同的组件,例如项目中的店家

展示默认子路由方法:在嵌套路由父路由中添加redirect属性,值为子路由的值

1
redirect: '/childrouter',

1.5 路由懒加载/ 按需加载

作用:性能优化:不用到该路由,不加载该组件

ES6的impot方式:

1
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),

VUE中的异步组件进行懒加载方式:

1
component: resolve=>(require(['../views/About'],resolve))

2. v-show和v-if

  • 作用: 都是控制元素隐藏和显示的
  • 区别:
    • v-show: 控制的元素无论是true还是false,都被渲染出来了,通过display:none控制元素隐藏
    • v-if: 控制的元素是true,进行渲染,如果是false不渲染,根本在dom树结构中不显示
  • 应用:
    • v-show: 适合使用在切换频繁显示/隐藏的元素上
    • v-if: 适合使用在切换不频繁,且元素内容很多,渲染一次性能消耗很大的元素上

3. v-for 为什么要加key

v-for 为什么一定要加key,且key要不同

  1. 加key是为了给元素添加唯一标识,因为vue是虚拟dom,用diff算法对节点进行一一比对,要修改哪个元素,这个元素一定要有一个唯一标识,为了性能优化,比如修改了原数组,没有给li上加key,那么在进行运算的时候,就重新将整体渲染一遍,但是如果有key,那么它就会按照key找到修改内容的那个li元素,改掉它自己,不需要对其他元素进行修改

    image-20210521142603087
image-20210521142651656
  1. key为什么不能是index,因为假设我们给数组前插入一个新元素,它的下标是0,那么和原来的第一个元素重复了,整个数组的key都发生了改变,这样就跟没有key的情况一样了
image-20210619181015456

4. keepalive

  1. 默认情况下加在keepalive标签中的组件都会进行缓存

  2. 为了区别缓存哪些组件的方法

    给keepalive 添加属性,组件名称指的是具体组件添加的name,不是路由里面的name

    include 包含的组件(可以为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)

    exclude 排除的组件(以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)

    最常用的方式:和路由配合使用:在路由中添加meta属性,美团项目App.vue

  3. keepalive作用:提升性能,避免重复加载一些不需要经常变动且内容较多的组件

  4. 使用keepalive导致组件不重新加载,也就不会重新执行生命周期的函数,如果要解决这个问题,就需要两个属性进入时触发:activated 退出时触发:deactivated

5. data 为什么是函数

vue组件中data值不能为对象,因为对象是引用类型,组件可能会被多个实例同时引用。如果data值为对象,将导致多个实例共享一个对象,其中一个组件改变data属性值,其它实例也会受到影响

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

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

6. 为什么style中加scoped

区分样式的作用域,原理是加上scoped就会给当前组件添加上自定义属性,同时选择器上会添加自定义属性进行样式设置

image-20210619184557064

7. computed /watch的区别

7.1 computed

  • 初始化显示或者相关的 data、props 等属性数据发生变化的时候调用;
  • 将复杂的计算逻辑从模板中抽离出来,使模板变得更加简洁
  • 计算属性不在 data 中,它是基于data 或 props 中的数据通过计算得到的一个新值,这个新值根据已知值的变化而变化;
  • 在 computed 属性对象中定义计算属性的方法,和取data对象里的数据属性一样,以属性访问的形式调用;
  • computed中的方法只有依赖的数据发生改变的时候才会执行,且计算的结果会缓存起来,更像是input的keyup事件,获取到value值进行比对之后再触发
  • 在computed中的,属性都有一个 get 和一个 set 方法,当数据变化时,调用 set 方法

7.2 watch

  • 主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,可以看作是 computed 和 methods 的结合体;
  • 可以监听的数据来源:data,props,computed内的数据;
  • watch支持异步
  • 不支持缓存,监听的数据改变,直接会触发相应的操作;更像是input的change事件,输入就触发,不比对
  • 监听函数有两个参数,第一个参数是最新的值,第二个参数是输入之前的值,顺序一定是新值,旧值。

总结:

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;

watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

运用场景:

  • 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
  • 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

8. 组件传值

8.1 父子组件

8.1.1 父子组件使用

  1. import引入

  2. components中注入

    1. 在template中上写子组件标签

8.1.2 父子组件传值方式

  1. 父亲给子组件传递数据或者方法: 在组件上<List :list=”list” @delete=”deleteHandler”/>

  2. 子组件使用父亲传递的数据:props属性,调用父组件传递的方法this.$emit(‘方法名’,参数)

    props是只读,不可以被修改,所有被修改都会失效和被警告

8.2 不相关两个组件或者兄弟组件通信:emit发布 ,on接受

​ event.$emit(‘名称’,参数)

​ event.$on(‘名称’,方法)

​ event

9. 生命周期

生命周期图

9.1 单页面生命周期

​ 1. 生命周期是用来描述一个组件从引入到退出的全过程

​ 2. 生命周期核心的几步:挂在阶段=>更新阶段=>销毁阶段

​ 3. 挂载阶段:beforeCreate、created、beforeMounted、mounted

​ 更新阶段:beforeUpdate、updated

​ 销毁阶段:beforeDestroy、destroyed

​ 4. 重点阶段适合做什么

​ created:实例创建完成,可访问data、computed、watch、methods上的方法和数据,未挂载到DOM,

​ 不能访问到el属性,el属性,ref属性内容为空数组常用于简单的ajax请求,页面的初始化

​ beforeMount

​ 在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数

​ mounted

​ 实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问

​ 常用于获取VNode信息和操作,ajax请求

​ beforeupdate

​ 响应式数据更新时调用,发生在虚拟DOM打补丁之前

​ 适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器

​ updated

​ 虚拟 DOM 重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作

​ 避免在这个钩子函数中操作数据,可能陷入死循环

​ beforeDestroy

​ 实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例

​ 常用于销毁定时器、解绑全局事件、销毁插件对象等操作

9.2 父子组件生命周期

​ 1. 挂载:父亲created> 子created > 子mounted> 父亲mounted>

​ 2. 更新:父亲beforeUpdate > 子beforeUpdated > 子updated > 父亲updated

​ 3. 销毁:父亲beforeDestroy> 子beforeDestroy > 子destroyed> 父destroyed

10. 请求放在哪个生命周期更合适

​ 为什么不在 created 里去发ajax?created 可是比 mounted 更早调用啊,更早调用意味着更早返回结果,那样性能不是更高?

​ 1. 一个组件的 created 比 mounted 也早调用不了几微秒,性能没啥提高;

​ 2. 等到异步渲染开启的时候,created 就可能被中途打断,中断之后渲染又要重做一遍,

​ 在 created 中做ajax调用,代码里看到只有调用一次,但是实际上可能调用 N 多次,这明显不合适。

​ 3. 若把发ajax 放在 mounted,因为 mounted 在第二阶段,所以绝对不会多次重复调用,这才是ajax合适的位置.

​ 4. 在created的时候,视图中的dom并没有被渲染出来,所以此时如果直接去操作dom节点,无法找到相关元素。

​ 在mounted中,由于此时的dom元素已经渲染出来了,所以可以直接使用dom节点。

​ 一般情况下,都放在mounted中,保证逻辑的统一性。因为生命周期是同步执行的,ajax是异步执行的。

​ 服务端渲染不支持mounted方法,所以在服务端渲染的情况下统一放在created中。

11. $nextTick

在钩子函数created()里面想要获取dom的内容或者操作dom,但是这个时候只是虚拟dom,实际dom操作不了,所以在这里可以用this.$nextTick(),这样等dom更新完了再执行this.$nextTick()里面的回调,这样就可以操作或者获取dom的内容了

12. VueX基本使用

12.1 vuex的作用

集中管理项目公共数据

12.2 本来就是单页面应用,为什么不创建一个全局变量来代替vuex

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

  2. 不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用

12.3 使用方法

  1. 和vue-router使用方式一样,先引入,再use,然后new vuex.store实例,然后将该实例注入到Vue实例中

  2. 创建数据 state

​ state: {

​ count: 0

​ },

  1. 获取state中数据的方式

​ a.直接在虚拟dom上使用

​ b.在computed中定义方法,返回this.$store.state.count

​ 在页面

​ c.批量获取state中的数据

  1. 修改state数据 mutations 和 commit

​ 在mutations中定义方法没使用this.$store.commit(‘方法名称’,参数)修改state中的数据

​ …mapMutation获取多个方法

​ 注意:不要在mutation中的方法中写异步方法:ajax,那样数据就不可跟踪了

  1. getters : 如果state中的数据需要有被处理过的,我们需要一个固定处理数据的方法,同时这个方法保证,state中的数据发生改变,他就跟着改变,类似与computed方法

  2. Action : 定义调用mutations中方法的方法,为了能在改变state中值之前使用一些异步方法