网络日志

vue面试题

一、生命周期

vue2 和vue3生命周期的区别vue2 beforedestroy,destroyed 对应vue3 beforeUnmount,unmounted

不要在选项 property 或回调上使用箭头函数,比如 created: () => 
console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。
因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,
经常导致 Uncaught TypeError: Cannot read property of undefined 
或 Uncaught TypeError: this.myMethod is not a function 之类的错误。

二、组件初次渲染时,哪些生命周期被执行

beforecreate,created,beforemount,mounted,如果有keep-alive,增加activated

三、组件缓存 keep-alive

同一个组件再次进入时,组件会缓存,只执行一个生命周期:activated用<keep-alive></keep-alive>包裹组件

<keep-alive>
        <component :is="currentComponent"></component>
    </keep-alive>

四、v-if和v-show的区别

v-if:dom节点的创建和删除,性能消耗较大v-show:display:block/none,控制显示隐藏。不占位置会造成重绘和回流,相比v-if性能消耗较小。

五、v-if和v-for的优先级:v-for的优先级更高

是在源码中体现的:function getElement

六、ref是什么

获取dom节点

<div ref="abd">
mounted(){
            console.log(this.$refs.abd);
        }
this.$ref.childComponent.show()  //调用子组件的show方法

七、nextTick是什么

获取更新后的dom使用场景:(1)在nextTick里调用插件,防止数据变更dom更新后,插件未更新到最新的dom

    (2)dom节点的数据变更后,需要获取dom内容,要用nextTick

八、scoped原理

样式只在本组件中生效,<style scoped>原理:给节点加了一个自定义属性,然后根据属性选择器添加样式scss的样式穿透:父元素/deep/子元素,如下:

九、 组件传值

父传子:自定义属性,props接收子传父:$emit 自定义事件,通过事件参数传值,兄弟组件:(1)vue2bus.js

import Vue from 'vue';
export default new Vue

A组件

import bus from './bus.js'
bus.$emit("transfer","params")

B组件

import bus from './bus.js'
bus.$on("transfer",(data)=>{
     console.log(data)
})

(2)vue3安装mitt

npm install --save mitt

mitt.js

import mitt from 'mitt'
export default new mitt()

A组件

import mitt from '../common/bus'
mitt.emit("transferValue",this.msg)

B组件

import mitt from '../common/bus'
mitt.on("transferValue",(data)=>{
         this.msg = data
 })

provide-inject组件间的数据穿透

A组件:

        provide(){
            return {
                webName: this.teacher
            }
        },

B组件:

 inject:['webName']

如果希望provide传的数据变化,接收组件该数据跟着变化,两种方式:(1)、把基本数据类型改成引用数据类型(2)、利用computed属性

 import { computed } from '@vue/reactivity'
 provide(){
            return {
                webName: computed(()=>{this.teacher})
            }
        },

main.jsapp.config.unwrapInjectedRef = true

十、computed,watch,methods的区别

computed:有缓存,计算某一个属性的改变,如果某一个值发生变化,会监听到并返回methods:没有缓存watch:监听当前数据改变了,才会执行内部代码

十一、搭建后端目录

npm install express-generator -g进入项目-> express --view=ejs servercd servercnpm inpm start

十二、解决请求跨域问题

vue2在vue.config.js中来配置

module.exports{
     devServer:{
           proxy: 'localhost:3000'
      }
}

vue3在vite.config.js中的devServer.proxy选项来配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server:{
    proxy: {
        '/home':'http://localhost:3001/',
    }
  }
})

十三设置代理,打包出现空白页的问题如何解决

十四、路由

1、路由模式

history,不带“#”,利用H5新增的pushState()方法hash 带“#”,通过路径中的hash值来控制路由默认是hash模式打包页面出现空白的问题,把history改成hash就可以解决

2、路由守卫

router.beforeEach((to,from,next)=>{

const route = {name: 'user'};
return route   

})

3、$route 和$router的区别

$route 路由信息对象$router 路由实例对象

十五、props和data,谁的优先级更高

props=>methods=>data=>computed=>watch

十六、vuex

1、vuex有哪些属性

2、vuex是单向数据流还是双向数据流

3、mutations 和actions的区别

4、如果做持久化存储

十七、 碰到的难点

打包出现空白页刷新后,页面路径问题

十八、插槽

(1)基本使用:子组件使用<slot></slot>来占位, 父组件调用子组件时,里面的内容就放在<slot></slot>里。(2)作用域:使用父组件的作用域(3)插槽的后备内容:子组件使用<slot>内容</slot>(4)具名插槽子组件:

 <header>header<slot name="header"/></header>
 <main>main<slot name="main"/></main>
 <footer>footer <slot name="footer"/></footer>

父组件

<template #header>  //插槽的简写:# 
        <div style="color:blue">社区帖子</div>
    </template>
    <template v-slot:main>后蹲人是一个主张友、分享、自由的技术交流社区</template>
    <template v-slot:footer>后盾人 人人做后盾</template>

十八、全局组件注册

main.js

import { createApp } from 'vue'
import App from './App.vue'
import Card from './provide-inject/Card.vue' //注册全局组件
const app = createApp(App);
app.component('Card',Card);
app.mount('#app')

在其他组件中不需在引入和注册,直接用<Card />就可以了

十九、动态组件

<component is="componentName"></component>

二十、异步组件,用函数方式引入组件

<template>
<ChildComponent />
</template>
<script>
export default {
      components:{
            ChildComponent: ()=> import('./src/ChildComponent')
      }
}
</script>

二十一、 mixin,抽离组件公共逻辑

common.js

export default {
    data(){
        return {
            commonData: '公共的数据'
        }
    },
    methods: {
        commonMethod() {
            console.log('公共的方法');
        }
    }
}

componetA.vue

//在A组件里直接引用mixin文件,在mixins里注册,就可以直接使用mixin里的方法和变量
<template>
<div>
    <span style="color:red;">{{ commonData }}</span>
    <button @click="commonMethod">a</button>
</div>
</template>
<script>
import mixin from '@/assets/js/mixin'
export default {
    mixins: [mixin],
    data(){
        return {

        }
    },
    methods:{

    }
}
</script>

minxin可以注册多个,如果有方法或变量重名的,后面注册的会覆盖前面的

二十二、自定义指令

<input type="text" value="11" v-focus>
directives: {
        focus: {
            // 指令的定义
            inserted: function (el) {
                alert(el.value)
                el.focus()
            }
        }
    },
    data(){
        return {

        }
    }

二十三、 data为什么必须是函数一个组件可能会被多个组件调用,如果data是对象的话,只要修改组件的值,这个值会在所有调用者中都发生变化,造成变量污染。本质是因为对象是引用类型。data变为函数返回值,那么每调用一次组件,都会调用这个data函数,这样就不会影响其他组件