前端面试笔记vue

本文详细介绍了Vue2中的关键概念,如组件生命周期的不同阶段、组件间通信的方法(props、$emit、注入),Vuex的状态管理,路由配置、API使用以及Vue3的新特性对比。
摘要由CSDN通过智能技术生成

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 += 2
		setTimeout(()=>{
			commit('add')
		}1000)
	}
}

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

npm install vuex-persistedstate --save

import 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.localStorage
		paths: ['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 = 12
		this.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>
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值