Vue11 Vue3完结撒花

shallowRef和shallowReactive

shallowRef

  1. 作用:创建一个响应式数据,但只对顶层属性进行响应式处理

  2. 用法

    let myVar = shallowRef(initialValue)
    
  3. 特点:只跟踪引用值变化,不关心值内部的属性变化

案例

<template>
	<div class="app">
		<h2>求和为:{{ sum }}</h2>
		<h2>名字为:{{ person.name }}</h2>
		<h2>年龄为:{{ person.age }}</h2>
		<h2>汽车为:{{ car }}</h2>
		<button @click="changeSum">sum+1</button>
		<button @click="changeName">修改名字</button>
		<button @click="changeAge">修改年龄</button>
		<button @click="changePerson">修改整个人</button>
		<span>|||||</span>
		<button @click="changeBrand">修改品牌</button>
		<button @click="changeColor">修改颜色</button>
		<button @click="changeEngine">修改发动机</button>
		<!-- <button @click="changeCar">修改整个车</button> -->
	</div>
</template>

<script setup lang="ts" name="App">
	import { ref,reactive,shallowRef,shallowReactive } from 'vue'

	let sum = shallowRef(0)
	let person = shallowRef({
		name: '小黑',
		age:2
	})
	let car = shallowReactive({
		brand: '特斯拉',
		options: {
			color: '黑色',
			engine:'v8'
		}
	})

	function changeSum (){
		sum.value += 1;
	}
	// 不会改变
	function changeName (){
		person.value.name = '大狗';
	}
	function changeAge (){
		person.value.age = 5;
	}
	//只能改变第一层
	function changePerson (){
		person.value = {name:'乐乐',age:3}
	}
	/* ********** */
	function changeBrand () {
		car.brand = '宝马'
	}
	function changeColor () {
		car.options.color = '红色'
	}
	function changeEngine () {
		car.options.engine = 'v12'
	}
	// function changeCar () {
	// 	Object.assign(car,{})
	// }
</script>

<style scoped>
	.app{
		background-color: #ddd;
		border-radius: 10px;
		box-shadow: 0 0 10px;
		padding: 10px;
	}
	button{
		margin:0 5px;
	}
</style>

总结

通过使用shallowRef()和shallowReactive()来绕开深度响应。浅层式API创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理,避免了对每一个内部属性做响应式所带来的性能成本,这使得属性的访问控制变得更快、可提升性能。

readonly与shallowReadonly

readonly

  1. 作用:用于创建一个对象的深只读副本

  2. 用法

    <template>
    	<div class="app">
    		<h2>当前求和为:{{ sum }}</h2>
    		<h2>当前sum2求和为:{{ sum2 }}</h2>
    		<h2>当前car1为:{{ car }}</h2>
    		<h2>当前car2为:{{ car2 }}</h2>
    		<button @click="changeSum">点我sum+1</button>
    		<button @click="changeSum2">点我sum2+1</button>
    	</div>
    </template>
    
    <script setup lang="ts" name="App">
    	import { ref, readonly, reactive,shallowReadonly } from 'vue';
    	
    	let sum = ref(0)
    	let sum2 = readonly(sum)
    
    
    	function changeSum() {
    		sum.value += 1
    	}
    	function changeSum2() {
    		sum2.value += 1  //sum2不可修改
    	}
    </script>
    
    <style scoped>
    	.app{
    		background-color: #ddd;
    		border-radius: 10px;
    		box-shadow: 0 0 10px;
    		padding: 10px;
    	}
    	button{
    		margin:0 5px;
    	}
    </style>
    
  3. 特点:

    • 对象的所有嵌套属性变成只读
    • 任何尝试修改这个对象的操作都会被组织(在开发模式下,还会再控制台中发出警告)
  4. 应用场景:

    • 创建不可变的状态快照
    • 保护全局状态或配置不被修改

shallowReadonly

  1. 作用:与readonly类似,但只作用于对象的顶层属性,其他地方仍然可以修改

  2. 用法

    <template>
    	<div class="app">
    		<h2>当前car1为:{{ car }}</h2>
    		<h2>当前car2为:{{ car2 }}</h2>
    		<button @click="changeBrand1">修改car1品牌</button>
    		<button @click="changeColor1">修改car1颜色</button>
    		<button @click="changePrice1">修改car1价格</button>
    		<button @click="changeBrand2">修改car2品牌</button>
    		<button @click="changeColor2">修改car2颜色</button>
    		<button @click="changePrice2">修改car2价格</button>
    	</div>
    </template>
    
    <script setup lang="ts" name="App">
    	import { reactive,shallowReadonly } from 'vue';
    	
    	let car = reactive({
    		brand:'奔驰',
    		options: {
    			color:'黑色',
    			price:100
    		}
    	})
    	let car2 = shallowReadonly(car)
    
    	function changeBrand1() {
    		car.brand = '宝马'
    	}
    	function changeColor1() {
    		car.options.color = '红色'
    	}
    	function changePrice1() {
    		car.options.price += 10
    	}
    	
    	function changeBrand2() {
    		car2.brand = '宝马'
    	}
    	function changeColor2() {
    		car2.options.color = '红色'
    	}
    	function changePrice2() {
    		car2.options.price += 10
    	}
    </script>
    
    <style scoped>
    	.app{
    		background-color: #ddd;
    		border-radius: 10px;
    		box-shadow: 0 0 10px;
    		padding: 10px;
    	}
    	button{
    		margin:0 5px;
    	}
    </style>
    

toRaw与markrow

toRaw

  1. 作用:用于获取一个响应式对象的原始对象,toRaw返回的对象不再是响应式,不会触发视图更新。

    • 何时使用

      在需要将响应式对象传递给非Vue的库或外部系统时,使用toRaw可以确保他们收到的是普通对象

  2. 用法:使用toRaw之后 年龄不再改变

    <template>
    	<div class="app">
    		<h2>姓名:{{ person.name }}</h2>
    		<h2>年龄:{{ person2.age }}</h2>
    		<button @click="person.age += 1">修改年龄</button>
    	</div>
    </template>
    
    <script setup lang="ts" name="App">
    import { reactive,toRaw } from 'vue';
    
    let person = reactive({
    	name: '小黑',
    	age:2
    })
    let person2 = toRaw(person)
    
    console.log('响应式数据', person)
    console.log('原始数据',person2)
    </script>
    
    <style scoped>
    	.app{
    		background-color: #ddd;
    		border-radius: 10px;
    		box-shadow: 0 0 10px;
    		padding: 10px;
    	}
    	button{
    		margin:0 5px;
    	}
    </style>
    

markRaw

  1. 作用:标记一个对象,使其永远都不会变成响应式

    • 何时使用

      使用第三方库的时候,防止错误把第三库对象变成响应式对象,就可以使用markRaw

  2. 用法

    <template>
    	<div class="app">
    		<h2>汽车:{{ car2 }}</h2>
    		<button @click="car2.price += 10">修改价格</button>
    	</div>
    </template>
    
    <script setup lang="ts" name="App">
    import { reactive,toRaw,markRaw } from 'vue';
    
    /* markRaw */
    //添加markRaw 28行就失去作用,无法改变成响应式
    let car = markRaw({ brand: '奔驰', price: 100 })
    let car2 = reactive(car)
    
    console.log(car);
    console.log(car2);
    
    </script>
    
    <style scoped>
    	.app{
    		background-color: #ddd;
    		border-radius: 10px;
    		box-shadow: 0 0 10px;
    		padding: 10px;
    	}
    	button{
    		margin:0 5px;
    	}
    </style>
    

customRef的使用

作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行逻辑控制

实现防抖效果(useSumRef.ts)

<template>
	<div class="app">
		<h2>{{ msg }}</h2>
		<input type="text" v-model="msg">
	</div>
</template>

<script setup lang="ts" name="App">
	import { ref,customRef } from 'vue'

	//使用vue提供的默认ref定义响应式数据,数据一变,页面视图也更新
	// let msg = ref('你好')

	//使用vue提供的customRef定义响应式数据
	let initValue = '你好'
	let timer:number
	//track(跟踪)、trigger(触发) 不加上页面效果不会改变
	let msg = customRef((track,trigger) => {
		return {
			//get何时调用?——msg被读取时
			get() { 
				track() //告诉vue数据很重要,需要对msg进行持续关注,一旦msg变化就去更新
				return initValue
			},
			//set何时调用?——msg被修改时
			set(value) {
				clearTimeout(timer)
				timer = setTimeout(() => {
					// console.log('set',value);
					initValue = value
					trigger() //通知vue数据变化了
				}, 1000);
			}
			}
		})
</script>

<style scoped>
	.app{
		background-color: #ddd;
		border-radius: 10px;
		box-shadow: 0 0 10px;
		padding: 10px;
	}
	button{
		margin:0 5px;
	}
</style>

采用hooks封装

定义hooks——useMsgRef.ts

import { customRef } from 'vue';

export default function (initValue: string, delay: number) {
    //使用vue提供的customRef定义响应式数据
    // let initValue = '你好'
    let timer: number
    //track(跟踪)、trigger(触发) 不加上页面效果不会改变
    let msg = customRef((track, trigger) => {
        return {
            //get何时调用?——msg被读取时
            get() {
                track() //告诉vue数据很重要,需要对msg进行持续关注,一旦msg变化就去更新
                return initValue
            },
            //set何时调用?——msg被修改时
            set(value) {
                clearTimeout(timer)
                timer = setTimeout(() => {
                    // console.log('set',value);
                    initValue = value
                    trigger() //通知vue数据变化了
                }, delay); //延迟时间不要写死
            }
        }
    })
    //hooks必须要有返回值
    return { msg }
}

App.vue

<template>
	<div class="app">
		<h2>{{ msg }}</h2>
		<input type="text" v-model="msg">
	</div>
</template>

<script setup lang="ts" name="App">
	import useMsgRef from './useMsgRef';

	//使用useMsgRef来定义一个响应式数据且有延迟效果
	let { msg } = useMsgRef('小黑', 2000)
	
</script>

<style scoped>
	.app{
		background-color: #ddd;
		border-radius: 10px;
		box-shadow: 0 0 10px;
		padding: 10px;
	}
	button{
		margin:0 5px;
	}
</style>

Teleport

定义:Teleport是一种能够将我们的组件html结构移动到指定位置的技术

App.vue

<template>
    <div class="outer">
        <h2>我是App组件</h2>
        <img src="https://img.zcool.cn/community/014b275d0a1c95a801213ec257bb95.jpg@2o.jpg" alt="">
        <br>
        <Modal/>
    </div>
</template>

<script setup lang="ts" name="App">
    import Modal from './Modal.vue';
</script>

<style  scoped>
.outer{
    background-color: #ddd;
    border-radius: 10px;
    padding:5px;
    box-shadow: 0 0 10px;
    width: 500px;
    height: 500px;
    /* 添加滤镜后,模块定位不再参考视口,参考的是父容器了 */
    filter:saturate(150%);
}
img{
    height: 180px;
    object-fit: cover;
}
</style>

modal.vue

<template>
    <button @click="isshow = true">展示弹窗</button>
        <!-- teleport解决添加滤镜后fix定位问题 -->
    <teleport to='body'>
        <div class="modal" v-show="isshow">
            <h2>我是弹窗标题</h2>
            <p>我是弹窗内容</p>
            <button @click="isshow = false">关闭弹窗</button>
        </div>
    </teleport>
</template>

<script setup lang="ts" name="Modal">
import { ref } from 'vue'
let isshow = ref(false)
</script>

<style  scoped>
.modal{
    width: 200px;
    height: 150px;
    background-color: skyblue;
    border-radius: 10px;
    padding: 5px;
    box-shadow: 0 0 5px;
    text-align: center;
    position:fixed;
    left:50%;
    top: 20px;
    margin-left: -100px;
}
</style>

Suspense

  • 等待异步组件时渲染一些额外内容,让应用有更好的用户体验
  • 使用步骤:
    • 异步引入组件
    • 使用Suspense包裹组件,并配置好default和fallback

App.vue

<template>
    <div class="app">
        <h2>我是App组件</h2>
        <!-- 解决异步事件,如果不加下面,那么Child组件不显示 -->
        <Suspense>
            <template v-slot:default>
                <Child/>
            </template>
        </Suspense>
    </div>
</template>

<script setup lang="ts" name="App">
    import { Suspense } from 'vue'
    import Child from './Child.vue'
</script>

<style scoped>
.app{
    border-color: #ddd;
    border-radius:10px;
    padding:10px;
    box-shadow: 0 0 10px;
}
</style>

Child.vue

<template>
    <div class="child">
        <h2>我是Child组件</h2>
        <h3>当前sum求和为:{{ sum }}</h3>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import axios from 'axios'

let sum = ref(0)
let xxx = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
console.log(xxx);
//如果要看到数据,可以解构 xxx 替换成 {data{content}} log直接打印content即可

</script>

<style scoped>
.child{
    background-color: skyblue;
    border-radius:10px;
    padding:10px;
    box-shadow: 0 0 10px;
}
</style>

全局API转移到应用对象

  • app.component

App.vue

<template>
    <div class="app">
        <h2>我是App组件</h2>
        <Hello/>
        <Child/>
    </div>
</template>

<script setup lang="ts" name="App">
    import Child from './Child.vue'
</script>

<style scoped>
.app{
    border-color: #ddd;
    border-radius:10px;
    padding:10px;
    box-shadow: 0 0 10px;
}
</style>

Child.vue

<template>
    <div class="child">
        <h2>我是Child组件</h2>
        <h3>当前sum求和为:{{ sum }}</h3>
        <Hello/>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

let sum = ref(0)

</script>

<style scoped>
.child{
    background-color: skyblue;
    border-radius:10px;
    padding:10px;
    box-shadow: 0 0 10px;
}
</style>

Hello.vue

<template>
    <h2 style="color:red">你好</h2>
</template>

<script setup lang="ts" >

</script>

<style scoped>

</style>

main.ts

import { createApp } from 'vue'
import App from './App.vue'
import Hello from './Hello.vue'

// 创建应用
const app = createApp(App)

app.component('Hello', Hello)

// 挂载应用
app.mount('#app')
  • app.config

main.ts

app.config.globalProperties 添加 那么全局都可以使用

import { createApp } from 'vue'
import App from './App.vue'
import Hello from './Hello.vue'

// 创建应用
const app = createApp(App)

app.component('Hello', Hello)
app.config.globalProperties.x = 99

//这样下面x就不会爆红
declare module 'vue' {
    interface ComponentCustomProperties {
        // $http: typeof axios
        // $translate: (key: string) => string
        x: number
    }
}

// 挂载应用
app.mount('#app')

比如:Child.vue 页面就会呈现 我是Child组件99 这里x会爆红 在main.ts添加定义部分

<template>
    <div class="child">
        <h3>当前sum求和为:{{ sum }}</h3>
        <Hello/>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

let sum = ref(0)

</script>

<style scoped>
.child{
    background-color: skyblue;
    border-radius:10px;
    padding:10px;
    box-shadow: 0 0 10px;
}
</style>
  • app.directive

main.ts

import { createApp } from 'vue'
import App from './App.vue'
import Hello from './Hello.vue'

// 创建应用
const app = createApp(App)

app.directive('beauty', (element, { value }) => {
    element.innerText += value
    element.style.color = 'green'
    element.style.backgroundColor = 'yellow'
})

// 挂载应用
app.mount('#app')

比如:Child.vue 页面就会呈现 不高兴0——黄色背景,绿色文字

<template>
    <div class="child">
        <h2>我是Child组件{{ x }}</h2>
        <h3>当前sum求和为:{{ sum }}</h3>
        <h4 v-beauty="sum">不高兴</h4>
        <Hello/>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

let sum = ref(0)

</script>

<style scoped>
.child{
    background-color: skyblue;
    border-radius:10px;
    padding:10px;
    box-shadow: 0 0 10px;
}
</style>
  • app.mount

main.ts

import { createApp } from 'vue'
import App from './App.vue'
import Hello from './Hello.vue'
import type axios from 'axios'

// 创建应用
const app = createApp(App)

// 挂载应用
app.mount('#app')
  • app.unmount

main.ts 2秒钟之后 app消失在页面上

import { createApp } from 'vue'
import App from './App.vue'
import Hello from './Hello.vue'
import type axios from 'axios'

// 创建应用
const app = createApp(App)

// 挂载应用
app.mount('#app')

setTimeout(() => {
    app.unmount()
}, 2000);
  • app.use

见router那一节 安装插件

//使用路由器
app.use(router)

Vue3的非兼容性改变

Vue2和Vue3区别

看vue官网:Breaking Changes | Vue 3 Migration Guide (vuejs.org)

  • 过渡类名v-enter 修改为 v-enter-from、过渡类名 v-leave 修改为 v-leave-from 。
  • keyCode 作为 v-on 修饰符的支持。
  • v-model 指令在组件上的使用已经被重新设计,替换掉了v-bind.sync。
  • v-if 和 v-for 在同一个元素身上使用时的优先级发生了变化。
  • 移除了 Son、 Soff 和 Sonce 实例方法。
  • 移除了过滤器 filter。
  • 移除了 $children 实例 propert。

相关推荐

  1. Vue11 Vue3完结

    2024-05-12 12:02:03       9 阅读
  2. python基础24(完结)_习题总结

    2024-05-12 12:02:03       19 阅读
  3. C 练习实例98-汉诺塔(完结

    2024-05-12 12:02:03       11 阅读
  4. re:从0开始的CSS之旅 20. 渐变(暂完结

    2024-05-12 12:02:03       26 阅读
  5. 一个月时间为 vue3 重制了 vue-styled-components

    2024-05-12 12:02:03       14 阅读
  6. <span style='color:red;'>vue</span><span style='color:red;'>3</span>-<span style='color:red;'>12</span>

    vue3-12

    2024-05-12 12:02:03      35 阅读
  7. <span style='color:red;'>vue</span><span style='color:red;'>3</span>-<span style='color:red;'>13</span>

    vue3-13

    2024-05-12 12:02:03      33 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-12 12:02:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-12 12:02:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-12 12:02:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-12 12:02:03       18 阅读

热门阅读

  1. AIGC全面介绍:探索人工智能通用计算的未来

    2024-05-12 12:02:03       10 阅读
  2. 顺序表和链表

    2024-05-12 12:02:03       11 阅读
  3. 巩固学习5

    2024-05-12 12:02:03       10 阅读
  4. 写SQL的心得

    2024-05-12 12:02:03       7 阅读
  5. 相机3:曝光三要素之光圈与快门

    2024-05-12 12:02:03       7 阅读
  6. 一次基类类型对象无法被传递问题的分析

    2024-05-12 12:02:03       8 阅读
  7. 函数指针和指针函数的区别

    2024-05-12 12:02:03       12 阅读
  8. 机器学习中的数据集的收集方法和工具

    2024-05-12 12:02:03       10 阅读
  9. 【C语言】预处理器

    2024-05-12 12:02:03       12 阅读
  10. conda 常用的命令

    2024-05-12 12:02:03       9 阅读
  11. 为什么PHP 是一门弱类型语言?

    2024-05-12 12:02:03       8 阅读
  12. WPF之页的使用

    2024-05-12 12:02:03       9 阅读