Vue3魔法手册 作者 张天禹 06_监控

017_watch监视_情况一

watch他本身的含义就是监视, 监视数据的变化,为什么要使用watch?大家想一想,有没有这种场景,age一旦大于18,我们要做点什么,又不如order 订单 一旦金额大于1万元,我就要联系后端请求优惠卷等等这些数据去走逻辑,挺常用的,在vue3官方文档里面,明确表达了watch能监视4种数据。
复制代码
1, ref 定义的数据
2, reactive 定义的数据
3,函数返回一个值(getter函数)
4, 一个包含上述内容的数组。

笔记

3.9 [watch]

复制代码
1,作用: 监视数据的变化(和Vue2中的watch作用一致)
2,特点: Vue3中的watch只能监视以下四种数据:
	1) ref 定义的数据。
	2) reactive 定义的数据
	3) 函数返回一个值。
	4) 一个包含上述内容的数组。
我们在 Vue3 中使用 watch 的时候,通常会遇到以下几种情况:
情况一:
监视 ref 定义的 [基本类型] 数据: 直接写数据名即可,监视的是其value值的改变。
<template>
	<div class="person">
		<h2>
			watch情况一: 监视[ref]定义的[基本类型]数据,默认监视的就是value的值			</h2>
		<h3>当前求和:{{sum}}</h3>
		<button @click="changeSum">sum+1</button>
	</div>
</template>
准备数据
vue2在watch的写法,要监视的逻辑统统写入watch里面,如下图所示

watch的写法 watch(监视谁,回调函数)

我们这里监视sum,回调函数我们就使用箭头函数 即 watch(sum, () => {})

sum变化了,我们要传入两个参数 变化前后两个值 (newValue,oldValue)

vue3里面我们绝对不会用this

sum变化了,他会收到两个值(新的值,旧的值),然后我们打印一下这两个值
页面上值与打印的最新值是保持同步的
如果你持续点下去,结果如下图所示
以上这就watch去监视ref定义的基本类型
watch只能监视ref定义的数据
如果监视的数据为 sum.value 编辑器飘红报错
谁才是ref定义的数据 -> sum 所以sum.value会报错 如下图所示
两个插件 TypeScript Vue Plugin(Volar)和Vue Language Features(Volar)
如何解除监视?当 sum 的值大于等于 10 的时候,要解除监视,如图所示
当调用watch()的时候,会返回一个值x,打印x的值,watch()返回一个回调函数,具体如下
复制代码
() => {
    effect2.stop();
    if (scope && scope.active) {
      remove(scope.effects, effect2);
    }
  }
  
 ----
 老师的
 () => {
 	effect2.stop();
 	if (instance && instance.scope) {
 		remove(instance.scope.effects, effect2);
 	}
 }
当 sum 大于等于 10 立即结束监视
页面已经25了,监视从10就停下来了
你如果不写,他就会持续的监视
watch监视_情况一 实现代码如下:
复制代码
<template>
	<div class="person">
		<h1>情况一: 监视【ref】定义的【基本类型】数据</h1>
		<h2>当前求和为: {{ sum }} </h2>
		<button @click="changeSum">点我sum+1</button>
	</div>
</template>

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

	// 定义一个响应式数据
	let sum = ref(0)

	// 定义一个方法
	function changeSum() {
		// sum.value++
		sum.value += 1
	}

	// 监视 情况一: 监视【ref】定义的【基本类型】数据
	// sum的变化 sum.value报错,因为sum.value是基本类型数据,监视的是它的值的变化,而不是引用类型的地址变化。
	const stopWatch = watch(sum, (newValue, oldValue) => {
		console.log('sum变化了', newValue, oldValue);
		// 停止监视
		if (newValue >= 10) {
			stopWatch()
		}
	})

</script>

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

	button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}
</style>

018_watch监视_情况二

复制代码
情况二
监视 ref 定义的[对象类型]数据: 直接写数据名,监视的是对象的[地址值],若想监视对象内部的数据,要手动开启深度监视。
注意:
1,若修改的是ref定义的对象中的属性,newValue和oldValue都是新值,因为他们是同一个对象
2,若修改整个 ref 定义的对象, newValue 是新值,oldValue 是旧值,因为不是同一个对象了

笔记

修改整个人
红色指向是修改对象里面的属性,没有修改对象,地址值是不会发生变化
蓝色指向修改的对象,地址值是会发生改变的
watch()监视的是谁
watch()根本就不关心name,age等属性,watch()只关心的是整个地址值是否发生变化
我们点击'修改整个人',返回如下页面
有情况出现,开发时我们就需要监视name,age等对象属性的变化,该如何处理
要开启深度监视,需要传递三个参数:
复制代码
第1个参数: person	绿色指向
第2个参数:回调函数 红色指向
第3个参数: {deep:true}  watch()的配置对象

---
完整示例代码
watch(person,(newValue,oldValue)=>{
    console.log('person变化了',newValue,oldValue);
}, {deep: true})
修改名字可以监视
修改年龄可以监视
修改整个人也可以监视
第3个参数 watch()的配置对象 红色指向
还可以配置watch()监视选项{immediate:true},如果有此项配置,一上来,不论数据是否发生改变,他都要先执行 选项{immediate:true},告诉你新的值是多少。新的值就是当前的值, 旧的值是undifined
点击 '修改整个人',张三就是旧的值,李四此时是新的值了,如下图所示
绿色的person发生改变时,红色函数在你所监视的地址值发生改变时调用里面的回调函数。
绿色person发生改变,他才会去调用红色函数 如下图所示
有些时候新的值和旧的值是一样的

总结

watch的第一个参数是: 被监视的数据
watch的第二个参数是: 监视的回调(箭头函数)
watch的第三个参数是: 配置对象(deep,immediate,flush等等)
复制代码
{deep:true,immediate:true,flush:'post'}
watch监视_情况二 代码实现如下:
复制代码
1, src/components/Person.vue
<template>
	<div class="person">
		<h1>情况二: 监视【ref】定义的【对象类型】数据</h1>
		<h2>姓名: {{ person.name }}</h2>
		<h2>年龄: {{ person.age }}</h2>
		<h2>爱好: {{ person.hobbies }}</h2>
		<button @click="changeName">修改名字</button>
		<button @click="changeAge">修改年龄</button>
		<button @click="changeHobbies">修改爱好</button>
		<button @click="changePerson">修改整个人</button>
	</div>
</template>

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

	// 数据
	let person = ref({
		name: '张三',
		age: 18,
		hobbies: ['抽烟','喝酒','烫头']
	})

	// 方法
	function changeName() {
		person.value.name += '~'
	}

	function changeAge() {
		person.value.age += 1
	}

	function changeHobbies() {
		person.value.hobbies[0] = '打游戏'
	}

	function changePerson() {
		person.value = {
			name: '李四',
			age: 20,
			hobbies: ['写代码','唱歌','旅游']
		}
	}

	// 监视 
	// 情况二: 监视【ref】定义的【对象类型】数据 
	// 监视对象类型的数据,默认情况下监视的是对象的引用地址,
	// watch(person,(newValue,oldValue) => {
	// 	console.log('person变化了',newValue,oldValue)
	// })

	// 监视对象类型的数据
	// 监视的是对象的地址值的变化情况
	// 如果要监视对象内部属性的变化,则需要手动开启深度监视
	// watch(person,(newValue,oldValue)=>{
	// 	console.log('person变化了',newValue,oldValue);
	// }, {deep: true, immediate: true})

	// 监视 新的值和旧的值
	watch(person,(newValue,oldValue)=>{
		console.log('person变化了',newValue,oldValue);
	}, {deep: true})
</script>

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

	button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}
</style>

019_watch监视_情况三

笔记

复制代码
监视 reactive 定义的[对象类型]数据,且默认开启了深度监视。
不论是ref还是reactive绿色框里面的不需要更改
能修改整个person吗?不能
reactive定义的数据有一个局限性,不可整体修改

我们需要用 Object.assign() 这个API接口实现整体替换

复制代码
function changePerson() {
	Object.assign(person,{name:'李四',age:80})
}
ref定义的人对象与reactive定义的人对象是有本质区别的
ref定义的人是真正替换了整个人,已经是一个新的对象了
reactive定义的人是批量的修改了人里面的属性而与,所以对象还是原来的对象

reactive定义的人对象的数据是不能整个改变的

person 地址值没有发生变化,

还是那个person,只不过我们要将后面的值分配进来,对象还是那个对象,只不过

对象还是那个对象,只不过将新的绿色的数据塞进红色person对象里面去了,将原来的name与age替换了

ref定义的人对象数据是可以整个改变的

只能这么做,vue3就这么设计的,使用Object.assign()接口去实现批量替换对象中的属性。注意:对象还是原来的对象

监视
1,2,3都能监视到

person是一个reactive对象

验证 reactive 是默认开启深度监视的

reactive 隐式创建了深度监视,是非常好的

reactive创建的深度监视是你无法关闭的,页面仍然可以获取数据

newValue,oldValue值没有改变,因为我们一直在原对象上操作属性,压根就没有新对象所有 newValue,oldValue 一样,地址值没有改变

020_watch监视_情况四

笔记

情况四

复制代码
情况四
监视ref或reactive定义的[对象类型]数据中的某个属性,注意点如下:
1, 若该属性值不是[对象类型],需要写成函数形式.
2, 若该属性值是依然是[对象类型],可直接编,也可写成函数,不过建议写成函数。

总结:
监视的要是对象里的属性,那么最好写函数式,注意:若是对象监视的是地址值,需要关注对象内部需要手动开启深度监视.
脚本和结构都删除

先监视对象里面的基本属性

如何来监视某个属性
下图表示监视的person.name不是规定的四种数据源,所以报错
若只要监视name属性,先正常写法person.name,但是你要加工一下成getter函数
复制代码
加工成getter函数有如下两种写法 ()=>person.name ()=>{return person.name}
1,简写
// 监视  
 watch(()=>person.name, (newValue,oldValue) => {
    console.log('person变了', newValue,oldValue)
 })

2,完整写法
watch(()=>{return person.name}, (newValue,oldValue) => {
    console.log('person变了', newValue,oldValue)
})
以上两种写法返回如下图示 都一样
解释:getter函数,就能返回一个值的函数 https://cn.vuejs.org/
监视name 新值和旧值不一样 终于实现只监视对象person中的某一个属性
第一个参数简写: () => person.name
第一个参数完整写法: () => {return person.name}

watch()

侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。

详细信息

watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。

第一个参数是侦听器的。这个来源可以是以下几种:

  • 一个函数,返回一个值

  • 一个 ref

  • 一个响应式对象

  • ...或是由以上类型的值组成的数组

第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。

当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。

第三个可选的参数是一个对象,支持以下这些选项:

  • immediate :在侦听器创建时立即触发回调。第一次调用时旧值是 undefined

  • deep :如果源是对象,强制深度遍历,以便在深层级变更时触发回调。在 3.5+ 中,此参数还可以是指示最大遍历深度的数字。参考深层侦听器

  • flush :调整回调函数的刷新时机。参考回调的刷新时机watchEffect()

  • onTrack / onTrigger :调试侦听器的依赖。参考调试侦听器

  • once:(3.4+) 回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。

watchEffect() 相比,watch() 使我们可以:

  • 懒执行副作用;

  • 更加明确是应该由哪个状态触发侦听器重新执行;

  • 可以访问所侦听状态的前一个值和当前值。

侦听数据源类型

watch 的第一个参数可以是不同形式的"数据源":它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:

复制代码
const x = ref(0)
const y = ref(0)

// 单个 ref
watch(x, (newX) => {
  console.log(`x is ${newX}`)
})

// getter 函数
watch(
  () => x.value + y.value,
  (sum) => {
    console.log(`sum of x + y is: ${sum}`)
  }
)

// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})
这是定义的reactive响应式数据和监视reactive对象中某一个属性的代码如下图所示
name属性值不是【对象类型】,需要写成函数形式 如下图所示
接下来我们监视对象类型
监视的person.car里面的汽车,因为汽车是对象,所以可以直接写
watch第一个参数直接写 person.car 不报错,但是监视不断整个car的情况了,如图所示
所以我们要把person.car写成 () => person.car 函数形式,就可以监视到汽车的整个变化情况了,这里跟写不写第三个参数选项{deep:true}没有关系,但是如果要监视基本类型属性,必须开启深度监视选项{deep:true}
如果将选项 {deep:true}去掉,第一台与第二台就不能监视了,只有开启深度监视,他们才你实现监视,但是他们的新值和旧值是一样的。
总结:
由于包了函数此时监视的是地址值,而此时基本类型的数据就无法监视了
当我们加上选项{deep:true}基本类型和地址值都可以监视了
小结:
你只要监视响应式对象中的某个属性,不论是基本类型,还是对象类型,我们直接写函数就可以解决所有问题,但是你要知道基本类型走的是地址值,在地址值监视,你只要开一个深度监视{deep:true}就解决问题,这就是最佳实践.
watch监视_情况四 实现代码如下
复制代码
1, src/components/Person.vue
<template>
	<div class="person">
		<h2>姓名: {{ person.name }}</h2>	
		<h2>年龄: {{ person.age }}</h2>	
		<h2>汽车: {{ person.car.c1 }},{{ person.car.c2 }}</h2>
		<button @click="changeName">修改名字</button>
		<button @click="changeAge">修改年龄</button>
		<button @click="changeFirstCar">修改第一台车</button>
		<button @click="changeSecondCar">修改第二台车</button>	
		<button @click="changeCar">修改整个汽车</button>	
	</div>
</template>

<script setup lang="ts" name="Person">
	import { reactive, watch } from 'vue'

	// 数据
	let person = reactive({
		name: '张三',
		age: 18,
		car: {
			c1: '宝马',
			c2: '奔驰'
		}
	})

	// 方法
	function changeName() {
		person.name += '~'
	}

	function changeAge() {
		person.age += 1
	}

	function changeFirstCar() {
		person.car.c1 = '奥迪'
	}

	function changeSecondCar() {
		person.car.c2 = '特斯拉'
	}

	function changeCar() {
		person.car = {
			c1: '比亚迪',
			c2: '五菱宏光'
		}
	}

	// 监视 情况四: 监视响应式对象中的某个属性,且属性是基本类型的,要写成函数的形式,监视多层嵌套的属性值时,要写成函数的形式
	// watch(()=>person.name, (newValue,oldValue) => {
	// 	console.log('person.name变了', newValue,oldValue)
	// })

	// watch(()=>person.age, (newValue,oldValue) => {
	// 	console.log('person.age变了', newValue,oldValue)
	// })

	// watch(()=>{return person.name}, (newValue,oldValue) => {
	// 	console.log('person变了', newValue,oldValue)
	// })

	// 监视 情况四: 监视响应式对象中的某个属性,且属性是对象类型的,可以直接写,也可以写成函数的形式,推荐写函数
	watch(()=>person.car, (newValue,oldValue) => {
		console.log('person.car变了', newValue,oldValue)
	},{deep:true})
</script>

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

	button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}
</style>

021_watch监视_情况五

监视上述多个数据

笔记

开发里面监视多个使用频率还是很多的
newValue是整个红色数组
watch监视情况五 实现代码如下
复制代码
1, src/components/Person.vue
<template>
	<div class="person">
		<h1>情况五: 监视上述多个数据</h1>
		<h2>姓名: {{ person.name }}</h2>	
		<h2>年龄: {{ person.age }}</h2>	
		<h2>汽车: {{ person.car.c1 }},{{ person.car.c2 }}</h2>
		<button @click="changeName">修改名字</button>
		<button @click="changeAge">修改年龄</button>
		<button @click="changeFirstCar">修改第一台车</button>
		<button @click="changeSecondCar">修改第二台车</button>	
		<button @click="changeCar">修改整个汽车</button>	
	</div>
</template>

<script setup lang="ts" name="Person">
	import { reactive, watch } from 'vue'

	// 数据
	let person = reactive({
		name: '张三',
		age: 18,
		car: {
			c1: '宝马',
			c2: '奔驰'
		}
	})

	// 方法
	function changeName() {
		person.name += '~'
	}

	function changeAge() {
		person.age += 1
	}

	function changeFirstCar() {
		person.car.c1 = '奥迪'
	}

	function changeSecondCar() {
		person.car.c2 = '特斯拉'
	}

	function changeCar() {
		person.car = {
			c1: '比亚迪',
			c2: '五菱宏光'
		}
	}

	// 监视 情况五: 监视上述的多个数据
	// watch([()=>person.name,()=>person.car.c1], (newValue,oldValue) => {
	// 	console.log('person.car变了', newValue,oldValue)
	// },{deep:true})

	watch([()=>person.name,person.car], (newValue,oldValue) => {
		console.log('person.car变了', newValue,oldValue)
	},{deep:true})
</script>

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

	button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}
</style>

022_watchEffect

3.10 【watchEffect】
复制代码
官网: 立即运行一个函数,同时响应式第追踪其依赖,并在依赖更改时重新执行该函数.
watch 对比 watchEffect
1, 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
2, watch: 要明确指出监视的数据
3, watchEffect: 不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)。

笔记

watchEffect()

立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。

类型

复制代码
function watchEffect(
  effect: (onCleanup: OnCleanup) => void,
  options?: WatchEffectOptions
): WatchHandle

type OnCleanup = (cleanupFn: () => void) => void

interface WatchEffectOptions {
  flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
}

interface WatchHandle {
  (): void // 可调用,与 `stop` 相同
  pause: () => void
  resume: () => void
  stop: () => void
}

详细信息

第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用,例如等待中的异步请求 (参见下面的示例)。

第二个参数是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。

默认情况下,侦听器将在组件渲染之前执行。设置 flush: 'post' 将会使侦听器延迟到组件渲染之后再执行。详见回调的触发时机。在某些特殊情况下 (例如要使缓存失效),可能有必要在响应式依赖发生改变时立即触发侦听器。这可以通过设置 flush: 'sync' 来实现。然而,该设置应谨慎使用,因为如果有多个属性同时更新,这将导致一些性能和数据一致性的问题。

返回值是一个用来停止该副作用的函数。

示例

复制代码
const count = ref(0)

watchEffect(() => console.log(count.value))
// -> 输出 0

count.value++
// -> 输出 1

停止侦听器:

复制代码
const stop = watchEffect(() => {})

// 当不再需要此侦听器时:
stop()

暂停/恢复侦听器:

复制代码
const { stop, pause, resume } = watchEffect(() => {})

// 暂停侦听器
pause()

// 稍后恢复
resume()

// 停止
stop()

副作用清理:

复制代码
watchEffect(async (onCleanup) => {
  const { response, cancel } = doAsyncWork(newId)
  // 如果 `id` 变化,则调用 `cancel`,
  // 如果之前的请求未完成,则取消该请求
  onCleanup(cancel)
  data.value = await response
})

3.5+ 中的副作用清理:

复制代码
import { onWatcherCleanup } from 'vue'

watchEffect(async () => {
  const { response, cancel } = doAsyncWork(newId)
  // 如果 `id` 变化,则调用 `cancel`,
  // 如果之前的请求未完成,则取消该请求
  onWatcherCleanup(cancel)
  data.value = await response
})

选项:

复制代码
watchEffect(() => {}, {
  flush: 'post',
  onTrack(e) {
    debugger
  },
  onTrigger(e) {
    debugger
  }
})

watchPostEffect()

watchEffect() 使用 flush: 'post' 选项时的别名。

watchSyncEffect()

watchEffect() 使用 flush: 'sync' 选项时的别名。

删除所有结构和脚本 如图所示
需要监视两个数据水温和水位
只关注最新值
拿到最新的水温(newTemp)和最新的水位(newHeight)
判断条件 满足就发送请求
源码和实现效果
逻辑里面监视了两个值
如果逻辑里面要监视7个值,我们是不是要写7个监视值,是不是很麻烦
watch() 与 watchEffect() 区别
watch() 必须明确指出要监视是数据
watchEffect()他神奇在哪里?你不用告诉他监视谁,你直接用就可以了,他会自己去分析监视谁。
如果有多个数据需要监视,我们可以用watchEffect()解决问题
绿色的回调函数监视谁?
验证 有点像watch()里面加了{immediate: true}感觉,立即监视
写监视代码
他只会监视两个,剩余的8g个他不会重新调用
watchEffect() 是全自动的监视
使用 watchEffect去写watch能省很多力气
官网依据

_watchEffect 实现代码如下

复制代码
1, src/components/Person.vue
<template>
	<div class="person">
		<h2>需求:当水温达到60度或水位80cm时,给服务器发送请求</h2>
		<h2>当前水温为: {{ temp }}℃</h2>
		<h2>当前水位为: {{ height }}cm</h2>
		<button @click="changeTemp">水温+10</button>
		<button @click="changeHeight">水位+10</button>
	</div>
</template>

<script setup lang="ts" name="Person">
	import { ref,watch,watchEffect} from 'vue'

	// 数据
	let temp = ref(10)
	let height = ref(0)

	// 方法
	function changeTemp() {
		temp.value += 10
	}

	function changeHeight() {
		height.value += 10
	}

	// 监视--watch()
	// watch([temp, height], ([newTemp, newHeight]) => {
	// 	if (newTemp >= 60 || newHeight >= 80) {
	// 		console.log('发送请求');
	// 	}
	// })

	// // 需求根据水温和水位发送请求
	// watch([temp,height],(value)=>{
	// 	// 从value中获取最新的水温(newTemp)和水位(newHeight)数据
	// 	let [newTemp,newHeight] = value;
	// 	// console.log(newTemp, newHeight);
	// 	// 逻辑 判断是否满足条件,如果满足则发送请求
	// 	if(newTemp >= 60 || newHeight >= 80) {
	// 		console.log('给服务器发送请求');
	// 	}
	// })

	// 监视--watchEffect()
	// watchEffect(()=>{
	// 	if(temp.value >= 60 || height.value >= 80) {
	// 		console.log('给服务器发送请求');
	// 	}
	// })
	watchEffect(()=>{
		// console.log('@')
		if (temp.value >= 60 || height.value >= 80) {
			// 逻辑判断是否满足条件,如果满足则发送请求
			console.log('给服务器发送请求');
		}
	})

</script>

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

	button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}
</style>
相关推荐
恋猫de小郭2 小时前
你知道不,你现在给 AI 用的 Agent Skills 可能毫无作用,甚至还拖后腿?
前端·人工智能·ai编程
用户600071819103 小时前
【翻译】用生成器实现可续充队列
前端
少云清3 小时前
【UI自动化测试】4_web自动化测试 _元素定位(重点)
前端·web前端自动化
若丶相见3 小时前
腾讯云完整部署方案:CODING + CI/CD + Docker + Nginx + K8s 扩展
前端·后端
比奇堡鱼贩4 小时前
python第五次作业
开发语言·前端·python
半兽先生4 小时前
使用 retire.js 自动检测前端 JavaScript 库漏洞
开发语言·前端·javascript
扶苏10024 小时前
详解Vue3的自定义 Hooks
前端·javascript·vue.js
二级小助手4 小时前
26年计算机二级web考试介绍【内附真题】
前端·计算机二级·全国计算机二级·web二级·二级web·前端二级·全国计算机web二级
专注VB编程开发20年5 小时前
WebView2 处理跨域访问限制,Frame脚本执行,难度比CEF大10倍
前端·javascript·.net