前端面试笔记vue

devtools/2024/9/24 12:18:27/

vue2

生命周期

beforeCreate:无data、methods、dom
created:有data、methods,无dom
beforeMount:有data,无dom
mounted:有data,有dom
beforeUpdate
updated
deforeDestroy
destroy:记录用户浏览、播放记录
keep-alive缓存的组件
activated: 进入时会执行,mounted之后
deactivated:离开时会执行(销毁)

进入组件执行顺序
beforeCreate,created,beforeMount
子组件 ->[beforeCreate,created,beforeMount,mounted]
mounted
activated(keep-alive):判断id,避免重复请求

组件通信

父传子
1、组件绑定,props取值(不可修改,优:传子方便,缺:不能传孙)
2、直接获取 (dom可直接使用,可修改,缺:复杂)
this.$parent.xxx this.$parent.$parent.xxx
3、依赖注入:(优:子孙都可用,缺:数据来源不好定位)

//父组件
provide(){return {val: 'xxx'}
}
//子,孙组件
inject:['val']

子传父
1、$emit$on(不可修改)

//父组件
created(){this.$on('handle1',val => {console.log(val)})
}
//子组件
this.$emit('handle1',val)

2、直接获取(dom不可直接使用,优:可修改,缺:复杂,不常用)

this.$children[0].xxx
this.$children[1].xxx

3、ref(dom不可直接使用,需定义变量赋值,优:可修改)

//父组件
<child ref='child'></child>this.$refs.child.val

传兄弟
1、eventBus

//main.js
Vue.prototype.$Bus = new Vue()
//list1
created(){this.$Bus.$on('handle1',val => {console.log(val)})
}
destroyed(){// 移出监听this.$Bus.$off('handle1')
}
//list2
this.$Bus.$emit('handle1',val)

插槽

一般组件封装时使用
1、匿名插槽:所有内容都会插入(会带有隐含的名字default)

//父组件
<child><p>这是一些内容。</p>
</child>
//子组件
<template><div><slot></slot></div>
</template>

2、具名插槽:通过slot名来指定内容插入
v-slot:header可简写为 #header

// 父组件
<child><template v-slot:header><p>这是头部内容。</p></template><p>这是默认插槽的内容。</p><template #footer> // v-slot:footer的简写<p>这是底部内容。</p></template>
</child>
// 子组件
<template><div><slot name="header"></slot><slot></slot><slot name="footer"></slot></div>
</template>

3、作用域插槽:子组件可以通过:varName="value"传递数据给父组件,父组件通过v-slot:slotName="slotProps"来接收

// 父组件
<child><template v-slot:user="slotProps"><p>用户名: {{ slotProps.user.name }}</p><p>年龄: {{ slotProps.user.age }}</p></template>
</child>
// 子组件
<template><div><slot name="user" :user="userInfo"></slot></div>
</template>
<script>
export default {data() {return {userInfo: { name: '张三', age: 30 }};}
};
</script>

组件封装

需要介绍到:父子互传值,插槽的使用

Vuex

1、属性

state:全局共享属性
getters:state的计算属性
mutations:同步方法
actions:异步方法提交mutations
modules:vuex的模块划分(更好维护)

2、使用

1、this.$store.state.val:可直接修改值
2、辅助函数:不可直接修改值(映射)

import {mapState,mapGetters} from 'vuex'
computed:{...mapState([val]),...mapGetters([val1])
}

3、getters不可修改
4、module

const moduleA = {state: () => ({ ... }),mutations: { ... },actions: { ... },getters: { ... }
}
const moduleB = {state: () => ({ ... }),mutations: { ... },actions: { ... }
}
const store = new Vuex.Store({modules: {a: moduleA,b: moduleB}
})store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
...mapState('a', {state: state => state
})
...mapState({val: state => state.a.val,str: state => state.b.str,a: state => state.a,b: state => state.b
})

5、mutations,actions(return值拿不到)
mutations:同步,修改state
actions:异步,返回premise,提交mutations

//辅助函数
mutations: {add( state ){state.num ++;}
}
actions: {addNum({commit,state}){//state.num += 2setTimeout(()=>{commit('add')}1000)}
}

6、vuex的持久化存储
vuex 不是持久化存储,需要用到插件 vuex-persistedstate

npm install vuex-persistedstate --saveimport Vue from 'vue';
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate';Vue.use(Vuex);export default new Vuex.Store({state: {// ...},mutations: {// ...},actions: {// ...},//storage选项可以是localStorage或sessionStorage//localStorage会持久化到浏览器会话结束,而sessionStorage只会持续到用户关闭浏览器标签//也可以通过paths选项来指定需要持久化状态的部分//或者通过reducer选项自定义持久化的逻辑plugins: [createPersistedState({storage: window.sessionStorage, // 或者 window.localStoragepaths: ['moduleA.token','moduleB.username'], // 只持久化特定的状态(推荐)reducer(val){ // 自定义持久化逻辑,例如加密return {...val,token: val.moduleA.token,username: val.moduleB.username}}})]
});

路由

1、模式:hashhistory
2、子路由和动态路由
3、路由传值
4、导航故障:当前页跳当前页会报错,处理方法是重写router的push方法

import VueRouter from 'vue-router'
//  修改原型对象中的push方法
const routerPush = VueRouter.prototype.push
VueRouter.prototype.push = function push( location ) {return routerPush.call(this, location).catch(err => err)
}

5、$router$route
$router:路由器对象,用于管理路由,包含 push、replace、go、back、forward、currentRoute、beforeEach、afterEach路由属性和方法
$route:当前路由对象,用于获取当前路由的信息。包含 path、params、query、hash、name、meta、fullPath等属性和方法
6、导航守卫
全局守卫:判断登录状态
beforeEach:路由进入之前
afertEach:路由进入之后
单个路由独享守卫
beforeEnter:路由进入之前
组件内守卫
beforeRouteEnter:路由进入之前
beforeRouteUpdate:路由更新之前
beforeRouteLeave:路由离开之前

//全局 main.js
router.beforeEach((to,from,next)=>{if(to.meta.isAuth){if(localStorage.getItem('user')){next()}else{next('/login')}}else{next()}
})
//独享 router.js
{path: '/userInfo',name: 'userInfo',component: userInfo,meta:{ isAuth: false },beforeEnter:(to,from,next) =>{if(to.meta.isAuth){if(localStorage.getItem('user')){next()}}else{next('/login')}}
}
//组件内 component.vue
beforeRouteEnter (to, from, next) {    if (localStorage.getItem('user')) {next()} else {next(vm => {vm.$router.push('/login')})}
}

API

1、$set
2、$nextTick:在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM

//源码
class Vue{constructor(options){//this.$el=document.querySelector(options.el);options.created.bind(this)();options.mounted.bind(this)();this.$el=document.querySelector(options.el);}$nextTick( callback ){return Promise.resolve().then(()=>{callback();}}
})
new Vue({el:'#app',created(){this.$nextTick(()=>{console.log( this.$el);})},mounted(){}
}

3、$el:获取当前组件根节点
4、$refs:获取dom
5、$children:获取当前组件所有子组件
6、$parent:返回当前组件的父组件,找不到返回自身
7、$root:返回根组件

8、data
return 内定义的变量是响应式
return 外定义的变量是非响应式

data(){this.val1 = 1 // 响应式return {val2: 2 // 非响应式}
}

9、computed
一般情况不可修改,使用 get set 时可以修改
如果computed的值被v-model绑定,使用 get set 时也可以修改,否则修改时会报错

data(){return {val: 1}
},
computed:{newVal1(){return val + 1},newVal2:{get(){return val + 2},set(v){//修改newVal2时,v赋值给val,再触发get返回计算后的值this.val = v}}
},
methods:{changeVal(){this.val = 10//val = 10,val1 = 11,val2 = 12this.newVal2 = 10//val = 10,val1 = 11,val2 = 12}
}

10、watch
一般初始化不执行,变化时执行
immediate:初始化执行一次
deep:深度监听(修改对象或数组内的值)

watch:{str(newval,oldVal){}, //初始化不执行str:{handler(newval,oldVal){},immediate:true, //初始化执行一次deep: true, //深度监听(修改对象或数组内的值)}
}

methods和computed的区别:
computed:有缓存机制,使用n次只会执行一次,购物车数据
methods:没有缓存机制,使用几次就会调用几次,每次修改也会调用
watch:并且支持异步

指令

2和3的区别
全局指令:
局部指令:

知识点

1、v-ifv-for 优先级
vue2 中 v-for > v-if
vue3 中 v-if > v-for

2、proxyData 函数的实现(双向绑定核心)
注:把 this.$data 中的数据和 this 进行双向绑定,可以在this中直接读写this.$data

prosyData(){for(let key in this.$data){Object.defineProperty(this,key,{get(){return this.$data[key]},set(val){this.$data[key] = val}})}
}

vue2 和 vue3 的区别

  1. 双向绑定方法不同
    vue2:Object.defineProperty
    劫持不到后添加的属性
    vue3:new Proxy
    可以劫持到后添加的属性
  2. vue2 + webpack ,vue3 + ts + pinia + vite
  3. vue2 是选项式API
    vue3 是组合式API或者Setup语法糖,可以向下兼容选项式API
  4. vue3中没有this.$set方法(vue3中data没有声明的变量也可以直接响应式的使用)
  5. v-if 和 v-for 优先级
  6. ref 和 children
let data = {a:1,b:2}
//vue2
let vueData = {}
for(let key in data){Object.defineProperty(vueData,key,{get(){return data[key]},set(val){data[key] = val}})
}
//vue3
let vueData = new Proxy(data,{get(target, propKey, receiver){return Reflect.get(target, propKey, receiver)},set(target, propKey, value, receiver){return Reflect.set(target, propKey, value, receiver)}
})vueData.c = 3
console.log(vueData.c)

vue3在setup中获取this

import { getCurrentInstance } from 'vue'
let that = getCurrentInstance()

vue3常用的API
1、createApp() 创建应用实例
说明:vue2中 new Vue()
场景:写插件、分装全局组件
2、provide/inject 依赖注入
说明:组件传值
场景:父组件向子组件多层传值
缺点:不好维护,不好定位数据来源
3、directive 自定义指令
说明:自定义指令
场景:后台管理中按钮权限控制
4、mixin 混入
说明:全局、局部混入
场景:添加生命周期
缺点:不好维护,不好定位数据来源
5、app.config.globalProperties
说明:获取vue对象的属性和方法
场景:封装插件时,添加属性和方法到vue对象
6、nextTick
7、computed
8、reactive 和 ref
说明:定义数据,vue2的data
9、watch
说明:监听,vue2不需要深度监听
10、markRaw
说明:静态数据,非响应式数据
11、defineProps()
说明:setup形式,接收父组件传递的值
12、defineEmits()
说明:setup形式,自定义事件
13、slot
说明:匿名、具名、作用域

vue3响应式数据类型
1、ref:定义基本类型
2、reactive:定义复杂类型
3、toRef:解构一个值
4、toRefs:解构多个值

import {ref,reactive,toRef,toRefs} from 'vue'
let sum = ref(10)
let obj = reactive({name:'张三',age: 16
})
let name = toRef(obj,'name')
let {name,age} = toRefs(obj)const btnClick = () => {name.value = '李四'
}

teleport
说明:将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置
场景:一般用来包裹模态框
好处:可以忽略 DOM 结构导致的布局问题,如position,z-index

<script setup>import { ref } from 'vue'const open = ref(false)
</script><template><button @click="open = true">Open Modal</button>//不使用Teleport <div v-if="open" class="modal"><p>Hello from the modal!</p><button @click="open = false">Close</button></div>//使用Teleport <Teleport to="body"><div v-if="open" class="modal"><p>Hello from the modal!</p><button @click="open = false">Close</button></div></Teleport>
</template><style scoped>
.modal {position: fixed;z-index: 999;top: 20%;left: 50%;width: 300px;margin-left: -150px;
}
</style>

http://www.ppmy.cn/devtools/12067.html

相关文章

Octopus+: An RDMA-Enabled Distributed Persistent Memory File System——泛读笔记

TOS 2021 Paper 分布式元数据论文阅读笔记整理 问题 非易失性存储器&#xff08;NVM&#xff09;和远程直接存储器访问&#xff08;RDMA&#xff09;在存储和网络硬件中提供了极高的性能。然而&#xff0c;现有的分布式文件系统隔离了文件系统和网络层&#xff0c;而且分层的…

git工作流程简介及常用命令

1、git工作流程 1&#xff0e;从远程仓库中克隆或拉取代码到本地仓库(clone/pull) 2&#xff0e;从本地进行代码修改 3&#xff0e;在提交前先将代码提交到暂存区 4&#xff0e;提交到本地仓库。本地仓库中保存修改的各个历史版本 5&#xff0e;修改完成后&#xff0c;需要…

【图文教程】在PyCharm中导入Conda环境

文章目录 &#xff08;1&#xff09;在Anaconda Prompt中新建一个conda虚拟环境&#xff08;2&#xff09;使用PyCharm打开需要搭建环境的项目&#xff08;3&#xff09;配置环境 &#xff08;1&#xff09;在Anaconda Prompt中新建一个conda虚拟环境 conda create - myenv py…

笔记:定义一个函数,要求从键盘输人两个数,调用该函数得出两个数的最大公约数,并显示在屏幕上。

文章目录 前言一、什么是调用该函数得出两个数的最大公约数&#xff1f;二、编写代码1.代码2.优化代码 总结 前言 题目&#xff1a;定义一个函数&#xff0c;要求从键盘输人两个数&#xff0c;调用该函数得出两个数的最大公约数&#xff0c;并显示在屏幕上。 在数学中&#x…

【后端】python2和python3的语法差异

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、为何要了解不同版本的语法差异二、python2和python3的语法差异三、总结 前言 随着开发语言及人工智能工具的普及&#xff0c;使得越来越多的人会主动学习使…

Jmeter04:关联

1 Jmeter组件&#xff1a;关联 概括&#xff1a;2个请求之间不是独立的&#xff0c;一个请求响应的结果是作为另一个请求提交的数据&#xff0c;存在数据交互 1.1 是什么&#xff1f; 就是一个请求的结果是另一个请求提交的数据&#xff0c;二者不再是独立 1.2 为什么&#x…

深度学习-数据预处理

目录 创建一个人工数据集处理缺失的数据插入对inputs中的类别值或离散值&#xff0c;将NaN视为一个类别对inputs和outputs中的数值类型转换为张量格式 创建一个人工数据集 import os import pandas as pd os.makedirs(os.path.join(.., data), exist_okTrue) data_file os.p…

第九章 更复杂的光照

Unity的渲染路径 渲染路径决定了光照是如何应用到Unity Shader中的,需要为每个Pass指定它的渲染路径。 完成上面的设置后,我们可以在每个Pass中使用标签来指定该Pass使用的渲染路径。 指定渲染路径是我们和Unity的底层渲染引擎的一次重要的沟通。 前向渲染路径 前向渲染路…