Vue3学习记录(二)--- 组合式API之计算属性和侦听器
一、计算属性
1、简介
计算属性computed()
,用于根据依赖的响应式变量的变化,进行自动的计算,并返回计算后的结果。当依赖的响应式变量发生变化时,computed()
会自动进行重新计算,并返回最新的计算结果。如果依赖的响应式变量没有发生变化,则computed()
会将计算的结果进行缓存,后续再调用时,将会返回缓存的计算结果,而不会重新计算。
2、使用
基础用法:
computed()
方法期望接收一个 getter
函数,返回值为一个只读的响应式 ref 对象,然后使用let/const/var
声明一个变量,作为计算属性的名称,接收的返回的 ref
。与使用 ref()
声明的响应式变量类似,在JS中需要通过 计算属性名.value
访问计算结果,在组件的<template>
模板中使用,可以直接使用计算属性名
,因为此时会自动解包,获取其value
属性。
<script setup>
// 引入要使用的相关API
import { ref, computed, onMounted } from 'vue';// 声明一个响应式变量
const list = ref([1,2,3]);// 使用computed计算属性
const hasData = computed(() => {// 内部依赖响应式变量 listreturn list.value.length > 0;
});// 在mounted生命周期中修改响应式变量的值 观察computed的变化
onMounted(() => {// 初始化时输出computed的值console.log('computed',hasData.value); // true// 2秒后清空list数组 观察computed的变化setTimeout(() => {list.value = [];console.log('computed',hasData.value); // false}, 2000);
})
</script><template><div><h1>computed计算属性</h1><!-- 在模板中使用计算属性 无需使用value --><h2>computed: {{hasData}}</h2><!-- 观察其变化 初始为true 两秒后变为false --></div>
</template>
可写的计算属性:
默认情况下,声明的计算属性是只读的,不可修改。但我们可以通过同时给计算属性设置getter
和setter
方法来创建一个可读写的计算属性。虽然说是可写的计算属性,但实际上原理是在setter
方法中通过修改计算属性依赖的响应式变量的值,从而达到修改计算属性值的效果:
<script setup>
// 引入要使用的相关API
import { ref, computed, onMounted } from 'vue';// 声明一个响应式变量
const list = ref([1,2,3]);// 设置一个可读写的计算属性
const listString = computed({// getter方法 用于获取计算属性的值get() {// 依赖于响应式变量listreturn list.value.join(',');},// setter方法 用于设置计算属性的值set(val) {// 实际是通过修改依赖的响应式变量list的值 从而实现修改计算属性的值list.value = val.split(',');}
});// 在mounted生命周期中操作计算属性
onMounted(() => {// 初始输出computed的值console.log('computed',listString.value);// 2秒后修改listString的值 观察computed和依赖的响应式变量的变化setTimeout(() => {listString.value = '4,5,6';console.log('computed',listString.value);console.log('list',list.value);}, 2000);
})
</script><template><div><h1>computed计算属性</h1><!-- 在模板中使用计算属性 观察其变化 --><h2>computed: {{listString}}</h2><!-- 在模板中使用响应式变量 观察其变化 --><h2>ref变量: {{list}}</h2></div>
</template>
页面效果:
计算属性调试:
在开发环境中,可以向computed()
传入第二个参数,参数值为一个包含了onTrack
和onTrigger
两个函数的对象。其中onTrack
将在计算属性初次被调用时触发。onTrigger
将在计算属性的值发生变化,也就是所依赖的响应式变量的值发生变更时触发。
<script setup>
// 引入要使用的相关API
import { ref, computed, onMounted } from 'vue';// 声明一个响应式变量
const count = ref(0);// 声明一个计算属性 并开启调试模式
const double = computed(() => count.value * 2, {onTrack(e) {// 计算属性初次被访问时 在访问之前触发console.log('computed onTrack---',e);},onTrigger(e) {// 计算属性的结果发生变化时触发 在修改计算属性依赖的响应式变量的值之后触发console.log('computed onTrigger---',e);}
});// 点击事件
const clickFunc = () => {count.value++;console.log('computed', double.value);
}// 在mounted生命周期中操作计算属性
onMounted(() => {// 初次访问计算属性的值 触发onTrackconsole.log('computed', double.value);// 修改计算属性依赖的响应式变量的值 触发onTriggercount.value = 2;
})
</script><template><div><h1>computed计算属性</h1><!-- 在模板中使用计算属性 观察其变化 --><h2 @click="clickFunc">computed: {{double}}</h2></div>
</template>
页面效果:
点击h2元素之后:
注意:计算属性的 onTrack
和 onTrigger
选项仅会在开发模式下工作。
3、其他
getter
方法不应该有副作用:
计算属性的getter
方法只能用于根据依赖的响应式变量计算并返回计算的结果。一定不能在getter
方法中进行修改其他变量的值、操作DOM以及发起异步请求等会产生副作用的操作,这违背了计算属性的设计初衷。
在计算属性getter
方法中使用 reverse()
和 sort()
等会影响原有数据的方法时务必小心。由于这些方法将改变原始数组的值,因此在调用这些方法之前要深拷贝一个原始数据的副本,然后对副本进行操作,并返回操作后的结果。
计算属性依赖的变量必须为响应式变量:
计算属性依赖的变量必须是响应式的变量,可以是ref
、reactive
声明的响应式变量,也可以是shallowRef
和shallowReactive
声明的浅层响应式变量。但如果是浅层响应式变量,则只有修改可以被监听到的属性时,才会触发计算属性的重新计算,计算属性的值层会更新。
通过let/const/var
声明的普通JS变量不能作为计算属性依赖的变量。
二、侦听器(监听器)
1、简介
侦听器watch()
用于实现监听一个响应式变量的变化,侦听器接收三个参数,其第一个参数表示所侦听的响应式变量,第二个参数表示响应式变量变化之后触发的回调函数,第三个参数是一个可选的选项,用来进行一些侦听器配置。在响应式变量发生变化时,触发回调函数,然后在回调函数中根据变量的状态变化,执行对应的操作,与计算属性不同的是,侦听器可以在回调函数中产生副作用,如:修改其他变量的值、操作DOM、发起异步请求等等。
在侦听器的回调函数中可以接收三个参数:新值、旧值,以及一个可选参数:用于注册清理副作用的清理函数。第三个参数清理函数会在下一次侦听器的回调函数被触发之前执行,用来清除上一次回调函数未执行结束的副作用,如未执行结束的异步请求等。
watch()
函数的返回值是一个用来停止该侦听器的函数。
2、使用
基础用法:
// 引入要使用的相关API
import { ref, watch, onMounted } from 'vue';// 声明一个响应式变量
const count = ref(0);// watch监听响应式变量的变化
watch(count, (newVal, oldVal) => {// 响应式变量初始化时,不会触发watch的回调函数// 只有当响应式变量的值发生变化时,会触发watch的回调函数 newval是变化后的值 oldval是变化前的值console.log('watch--', newVal, oldVal); // 10 0// 根据变量值的具体变化 进行后续操作
});// 在mounted生命周期中修改响应式变量的值 观察watch的变化
onMounted(() => {// 2秒后修改响应式变量的值 观察watch的变化setTimeout(() => {count.value = 10;}, 2000);
});
可侦听的数据类型:
watch()
的第一个参数所监听的数据源可以是多种形式:一个响应式变量(ref、reactive等)、一个getter函数、由多个数据源组成的数组。
如果监听的数据源是一个响应式变量,当变量变动时,回调函数就会被触发,且参数中包含监听变量的新值和旧值。
如果监听的数据源是一个getter
函数,这个getter
函数类似于计算属性,依赖于某些响应式变量进行计算,并返回计算的结果,当getter
函数所依赖的变量发生变动时,回调函数就会被触发,且回调函数的参数中包含getter
函数的新返回值和就返回值。
如果监听的数据源是一个由多个数据源构成的数组,数组中可以同时包含响应式变量、getter
函数,当数组中任意一个数据源发生变动时,都会触发回调函数,且回调函数的参数中以以两个数组的形式返回所有监听数据源的新值和旧值,新值数组和旧值数组中元素的顺序与监听数组中元素的顺序一一对应。
// 引入要使用的相关API
import { ref, watch, onMounted } from 'vue';// 声明两个响应式变量
const count = ref(0);
const str = ref('hello');// watch监听一个响应式变量的变化 第一个参数为监听的数据源 第二个参数为回调函数
watch(count, (newVal, oldVal) => {// 响应式变量初始化时,不会触发watch的回调函数// 只有当响应式变量的值发生变化时,会触发watch的回调函数 newval是变化后的值 oldval是变化前的值console.log('watch监听一个响应式变量--', newVal, oldVal);
});// watch监听一个getter函数 第一个参数为监听的数据源 第二个参数为回调函数
watch(() => count.value + str.value, (newVal, oldVal) => {// 响应式变量初始化时,不会触发watch的回调函数// 只有当getter函数中依赖的任意一个响应式变量的值发生变化时,都会触发watch的回调函数console.log('watch监听一个getter函数--', newVal, oldVal);
});// watch同时监听多个数据源的变化 用数组的形式 第一个参数为监听的数据源 第二个参数为回调函数
watch([count, str,() => count.value + str.value], ([newVal1, newVal2,newVal3], [oldVal1, oldVal2, oldVal3]) => {// 响应式变量初始化时,不会触发watch的回调函数// 当任意一个数据源的值发生变化时,会触发watch的回调函数 newval是变化后的值 oldval是变化前的值console.log('watch监听多个数据源--', newVal1, newVal2, newVal3, oldVal1, oldVal2, oldVal3);
});// 在mounted生命周期中修改响应式变量的值 观察watch的变化
onMounted(() => {// 2秒后修改响应式变量的值 观察watch的变化setTimeout(() => {count.value = 10;}, 2000);
});
控制台输出:
如果想要监听响应式对象的某一个简单属性(非嵌套对象、数组属性等),而非整个响应式对象,不能直接以对象.属性名
的形式作为监听的数据源,因为这样watch()
得到的数据源参数只是一个 number
,而非响应式的数据源。因此我们需要借助getter
函数,以函数返回值的形式返回该属性,最后将getter
函数设置为监听的数据源。
// 引入要使用的相关API
import { ref, watch, onMounted } from 'vue';// 声明一个响应式对象
const obj = ref({ count: 0,name: '张三' });// watch监听一个响应式对象的某条属性的变化
watch(() => obj.value.count, (newVal, oldVal) => {// 响应式变量初始化时,不会触发watch的回调函数// 只有当响应式变量的指定属性值发生变化时,才会触发watch的回调函数console.log('watch监听一个响应式对象的某条属性的变化--', newVal, oldVal);
});// 在mounted生命周期中修改响应式对象的属性值 观察watch的变化
onMounted(() => {// 1秒后修改响应式变量的其他属性的值 观察watch的变化setTimeout(() => {// 非监听的指定属性 不会触发watch的回调函数obj.value.name = '李四';}, 1000);// 2秒后修改响应式变量的指定属性的值 观察watch的变化setTimeout(() => {// 监听的指定属性 会触发watch的回调函数obj.value.count = 2;}, 2000);
});
深度侦听器
如果我们使用watch()
监听的数据源为一个响应式对象,则侦听器内部会隐式的创建一个深层侦听器。响应式对象中任意属性的发生变动,都会触发回调函数,即使是响应式对象内部嵌套对象的属性值,也会被监听到。watch()
回调函数的参数表示的是响应式对象的新值和旧值,但由于我们监听的是一个响应式对象,因此新值和旧值在此时是相等的,指向所监听的那个响应式对象。
// 引入要使用的相关API
import { ref, watch, onMounted } from 'vue';// 用ref声明一个响应式对象
const obj = ref({ count: 0,name: '张三',info: { age: 18 } });// watch监听一个响应式对象的变化
watch(obj.value, (newVal, oldVal) => {// 响应式对象初始化时,不会触发watch的回调函数// 响应式对象的任意属性值发生变化时,都会触发watch的回调函数console.log('watch监听一个响应式对象的变化--', newVal, oldVal);// newVal和oldVal是同一个对象console.log(newVal === oldVal);// newVal、oldVal和响应式对象的值是同一个对象console.log(newVal === obj.value);
});// 在mounted生命周期中修改响应式对象的属性值 观察watch的变化
onMounted(() => {// 1秒后修改响应式对象的根属性的值 观察watch的变化setTimeout(() => {obj.value.name = '王五';}, 1000);// 2秒后修改响应式对象的嵌套对象的属性值 观察watch的变化setTimeout(() => {obj.value.info.age = 20;}, 2000);
控制台输出:
如果我们仅仅只是想要监听的数据源为响应式对象中某个嵌套对象属性,那我们需要借助getter
函数,以函数返回值的形式返回该属性。但仅仅这样,只会在嵌套对象属性整个被替换时,才会触发回调函数。想要深度监听嵌套对象属性的变动,我们还需要给watch()
函数增加第三个参数,参数为一个配置对象,对象中包含deep: true
属性,表示将监听的数据源进行深层监听。在回调函数中可以获取到被监听的嵌套对象的新值和旧值,除非监听的嵌套对象整个被替换,否则新值和旧值在此时是相等的,指向所监听的那个嵌套对象。
// 引入要使用的相关API
import { ref, watch, onMounted } from 'vue';// 用ref声明一个响应式对象
const obj = ref({ count: 0,name: '张三',info: { age: 18 } });// watch监听一个响应式对象内部某个嵌套对象的属性变化
watch(() => obj.value.info, (newVal, oldVal) => {// 响应式对象初始化时,不会触发watch的回调函数// 响应式对象的任意属性值发生变化时,都会触发watch的回调函数console.log('watch监听一个响应式对象内部某个嵌套对象的属性变化--', newVal, oldVal);// 除非监听的嵌套对象整个被替换 否则newVal和oldVal是同一个对象console.log(newVal === oldVal); // newVal、oldVal和响应式对象的值是同一个对象console.log(newVal === obj.value.info);
},{// deep选项为true时,表示深度监听,包括嵌套对象的属性变化deep: true
});// 在mounted生命周期中修改响应式变量的值 观察watch的变化
onMounted(() => {// 2秒后修改响应式对象中嵌套对象的属性值 观察watch的变化setTimeout(() => {obj.value.info.age = 22;}, 2000);
});
注意: 深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,性能开销很大。因此请谨慎使用。
监听数据源初始化
watch()
侦听器默认在数据源初始化时不触发回调函数,只有在数据源变化时才会触发回调函数。如果我们想要在数据源初始化后,立即触发一次回调函数,可以通过给watch()
函数的三个参数,设置immediate: true
属性,表示将数据源的初始化动作加入到监听范围内,此时回调函数的参数中新值为数据源初始化后的值,旧值为undefined
:
// 引入要使用的相关API
import { ref, watch, onMounted } from 'vue';// 声明两个响应式变量
const count = ref(0);// watch监听一个响应式变量的变化 包括初始化时
watch(count, (newVal, oldVal) => {// 响应式变量的值发生变化时,会触发watch的回调函数console.log('watch监听一个响应式变量--', newVal, oldVal); // 0 undefined
},{// immediate选项为true时,表示初始化时也触发watch的回调函数immediate: true
});
一次性侦听器:
watch()
侦听器默认每次数据源的变化时都会触发回调函数。如果我们想让侦听器只运行一次,可以通过给watch()
函数的三个参数,设置once: true
属性(v3.4版本新增),表示侦听器将在回调函数首次执行后自动停止,不再监听数据源的后续变动。
// 引入要使用的相关API
import { ref, watch, onMounted } from 'vue';// 声明两个响应式变量
const count = ref(0);// watch监听一个响应式变量的变化 但回调函数只执行一次
watch(count, (newVal, oldVal) => {// 响应式变量的值发生变化时,会触发watch的回调函数console.log('watch监听一个响应式变量--', newVal, oldVal);
},{// once选项为true时,表示只执行一次回调函数once: true
});// 在mounted生命周期中修改响应式变量的值 观察watch的变化
onMounted(() => {// 1秒后修改响应式变量的值 触发watch的回调函数setTimeout(() => {count.value = 5;}, 1000);// 2秒后再次修改响应式变量的值 不触发watch的回调函数setTimeout(() => {count.value = 10;}, 2000);
});
回调函数的执行时机:
如果我们使用watch()
监听了一个响应式变量,并且在单文件组件的模板中使用了它,那么该变量在修改时,可能会同时触发Vue 组件更新和侦听器回调函数。默认情况下,侦听器的回调函数会在组件更新之前执行,如果此时在回调函数中访问页面的DOM,访问的是组件更新前的DOM。如果想要访问组件更新后的DOM,可以通过给watch()
函数的三个参数,设置flush: 'post'
属性,表示回调函数在组件更新之后执行,此时访问页面的DOM,将是最新状态的DOM。
// 引入要使用的相关API
import { ref, watch, onMounted } from 'vue';// 声明两个响应式变量
const count = ref(0);// watch监听一个响应式变量的变化 回调函数在组件更新前执行
watch(count, (newVal, oldVal) => { // 在此处获取页面的DOM元素 获取的是组件更新前的DOM元素console.log('组件更新前---',document.querySelector('h3').innerText); // 0
});// watch监听一个响应式变量的变化 但回调函数在组件更新后执行
watch(count, (newVal, oldVal) => { // 在此处获取页面的DOM元素 获取的是组件更新后的DOM元素console.log('组件更新后--',document.querySelector('h3').innerText); // 10
},{// flush选项为post时,表示在组件更新后执行回调函数flush: 'post'
});// 在mounted生命周期中修改响应式变量的值 观察watch的变化
onMounted(() => {// 2秒后再次修改响应式变量的值setTimeout(() => {count.value = 10;}, 2000);
});
flush
属性的可选值有三个:
pre
(默认值):回调函数会在数据源变化之后,组件更新渲染之前立即执行。post
:回调函数会在数据源变化之后,组件更新渲染之后执行。sync
:回调函数会在数据变化时立即被同步调用。该设置要谨慎使用,因为如果有多个属性同时更新,这将导致一些性能和数据一致性的问题。
副作用清除:
清理函数会在下一次侦听器的回调函数被触发之前执行,用来清除上一次回调函数未执行结束的副作用,如未执行结束的异步请求等。
watchEffect(async (newVal, oldVal, onCleanup) => {console.log()const { response, cancel } = doAsyncWork(id.value)// `cancel`取消逻辑 会在 `id` 更改时调用// 以便取消之前// 未完成的请求onCleanup(cancel)data.value = await response
})
侦听器调试:
和计算属性类似,侦听器的第三个参数也支持 onTrack
和 onTrigger
的调试选项。
// watch侦听器调试
watch(count, (newVal, oldVal) => { console.log('watch监听一个响应式变量--', newVal, oldVal);
}, {onTrack(e) {console.log('onTrack---', e);},onTrigger(e) {console.log('onTrigger---', e);}
});
注意:侦听器的 onTrack
和 onTrigger
选项仅会在开发模式下工作。
停止侦听器:
正常情况下用同步语句创建的侦听器,会自动绑定到当前组件实例上,并且会在当前组件卸载时自动停止。但如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它,以防内存泄漏。所以尽量不要在异步回调中创建侦听器。
正常创建的侦听器,也可以被手动停止,但基本不需要这么做。
watch()
函数会返回一个对应的停止函数,如果想要手动停止一个侦听器,直接调用该侦听器返回的停止函数即可。
// watch监听一个响应式变量的变化 并接收侦听器结束函数
const unWatch = watch(count, (newVal, oldVal) => { console.log('watch监听一个响应式变量--', newVal, oldVal);
});// 在mounted生命周期中修改响应式变量的值 观察watch的变化
onMounted(() => {// 1秒后修改响应式变量的值 watch会监听到setTimeout(() => {count.value = 5;}, 1000);// 2秒后 调用对应的停止函数 手动停止侦听器setTimeout(() => {unWatch();}, 2000);// 3秒后 再次修改响应式变量的值 watch已经被停止 不会监听到setTimeout(() => {count.value = 10;}, 3000);
});
3、其他
watchEffect():
watchEffect()
是watch()
侦听器的一种简写形式,无需指定监听的数据源,该函数会自动跟踪回调函数中使用的响应式依赖。而且该函数无需指定immediate: true
,也会在响应式依赖初始化时执行。每当响应式依赖发生变化时,都会自动执行回调函数。
watchEffect()
函数的第一个参数就是要触发的回调函数,第二个参数是一个可选参数对象,用来配置侦听器的flush
属性。该函数的返回值同watch()
一样,是一个用来停止该侦听器的函数。
watchEffect()
函数的第一个参数的回调函数中可以接收一个用于注册清理副作用的清理函数。清理函数会在下一次回调函数被触发之前执行,用来清除上一次回调函数未执行结束的副作用,如未执行结束的异步请求等。
// 引入要使用的相关API
import { ref, watch, watchEffect, onMounted } from 'vue';// 声明一个响应式变量
const count = ref(0);// watchEffect监听一个响应式变量
watchEffect(() => {console.log('watchEffect监听一个响应式变量--', count.value);
})
// 等同于
// watch监听一个响应式变量
watch(count, (newVal, oldVal) => {console.log('watch监听一个响应式变量--', newVal, oldVal);
},{immediate: true
});
watch
只监听明确指定的数据源,仅在数据源确实改变时才会触发回调,能更加精确地控制回调函数的触发时机。watchEffect
,则会在回调函数发生期间追踪依赖的数据源,自动追踪回调函数中访问到的响应式属性,但其响应性依赖关系会不那么明确。可以根据具体的业务场景选择合适的API。
watchPostEffect():
watchPostEffect()
是watchEffect()
使用 flush: 'post'
选项时的简写别名。
// watchPostEffect监听一个响应式变量
watchPostEffect(() => {console.log('watchEffect监听一个响应式变量--', count.value);
})// 等同于// watchEffect监听一个响应式变量
watchEffect(() => {console.log('watchEffect监听一个响应式变量--', count.value);
}, {flush: 'post'
})
watchSyncEffect():
watchSyncEffect()
是watchEffect()
使用 flush: 'sync'
选项时的简写别名。
// watchSyncEffect监听一个响应式变量
watchSyncEffect(() => {console.log('watchEffect监听一个响应式变量--', count.value);
})// 等同于// watchEffect监听一个响应式变量
watchEffect(() => {console.log('watchEffect监听一个响应式变量--', count.value);
}, {flush: 'sync'
})
相关文章:

Vue3学习记录(二)--- 组合式API之计算属性和侦听器
一、计算属性 1、简介 计算属性computed(),用于根据依赖的响应式变量的变化,进行自动的计算,并返回计算后的结果。当依赖的响应式变量发生变化时,computed()会自动进行重新计算,并返回最新的计算结果。如果依赖的…...

react-virtualized实现行元素不等高的虚拟列表滚动
前言: 当一个页面中需要接受接口返回的全部数据进行页面渲染时间,如果数据量比较庞大,前端在渲染dom的过程中需要花费时间,造成页面经常出现卡顿现象。 需求:通过虚拟加载,优化页面渲染速度 优点࿱…...

Linux系统各目录作用
/etc文件系统 /etc 目录包含各种系统配置文件,下面说明其中的一些。其他的你应该知道它们属于哪个程序,并阅读该程序的m a n页。许多网络配置文件也在/etc 中。 1. /etc/rc或/etc/rc.d或/etc/rc?.d 启动、或改变运行级时运行的脚本或脚本的目录。 2. /…...

嵌入式系统学习(一)
嵌入式现状(UP经历): 大厂的招聘要求: 技术栈总结: 产品拆解网站: 52audio 方案查询网站iotku,我爱方案网, 主要元器件类型:...

重写Sylar基于协程的服务器(3、协程模块的设计)
重写Sylar基于协程的服务器(3、协程模块的设计) 重写Sylar基于协程的服务器系列: 重写Sylar基于协程的服务器(0、搭建开发环境以及项目框架 || 下载编译简化版Sylar) 重写Sylar基于协程的服务器(1、日志模…...

Linux之系统安全与应用续章
目录 一. PAM认证 1.2 初识PAM 1.2.1 PAM及其作用 1.2.2 PAM认证原理 1.2.3 PAM认证的构成 1.2.4 PAM 认证类型 1.2.5 PAM 控制类型 二. limit 三. GRUB加密 /etc/grub.d目录 四. 暴力破解密码 五. 网络扫描--NMAP 六. 总结 一. PAM认证 1.2 初识PAM PAM是Linux系…...

《HTML 简易速速上手小册》第7章:HTML 多媒体与嵌入内容(2024 最新版)
文章目录 7.1 在HTML中嵌入视频和音频7.1.1 基础知识7.1.2 案例 1:嵌入视频文件7.1.3 案例 2:嵌入音频文件7.1.4 案例 3:创建一个视频和音频混合的播放列表 7.2 使用 <iframe> 嵌入外部内容7.2.1 基础知识7.2.2 案例 1:嵌入…...

【CSS】移动端适配
移动端适配怎么做? 适配的目的是在屏幕大小不同的终端设备拥有统一的界面,让拥有更大屏幕的终端展示更多的内容。 meta viewport (视口) 移动端初始视口的大小默认是980px,因为世界上绝大多数PC网页的版心宽度为980px ,如果网页…...

DFS剪枝算法经典题目-挑选
4954. 挑选 - AcWing题库 给定一个包含 n 个正整数 a1,a2,…,an的集合。 集合中可能存在数值相同的元素。 请你从集合中挑选一些元素,要求同时满足以下所有条件: 被选中元素不少于 2 个。所有被选中元素之和不小于 l 且不大于 r。所有被选中元素之中最大…...

考研经验总结——考试期间
文章目录 一、订房二、看考场三、休息四、考前带宾馆的书五、安全 一、订房 我刚刚看了看,是9.10号订的酒店。你们可以提前向学长学姐打听你的考场在哪个学校(徐州的考生,考省外的学校是在矿大考试,考省内的学校是在江师大&#…...

vue3 源码解析(6)— lifecycle 生命周期的实现
前言 对于 vue3 的生命周期,我们经常性会去疑问,生命周期有哪些呢,它是怎么去实现的, 又是什么时候调用的。 vue3 生命周期有哪些 下面这个表格列出了所有选项式api生命周期钩子和组合式api生命周期钩子,以及他们的…...

three.js CSS2DRenderer、CSS2DObject渲染HTML标签
有空的老铁关注一下我的抖音: 效果: <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red;position: relative;"><…...

SECS/GEM300和半导体e84控制器
SECS(SEMI EQUIPMENT COMMUNICATIONS STANDARD 2)半导体设备通讯标准 GEM(Generic Equipment Model)定义了Fab中各个场景下设备行为及其所使用SECS消息。 GEM300也称为300mm标准,FAB是12寸设备的处理作业规范。主要包…...

k8s二进制及负载均衡集群部署详解
目录 常见部署方式 二进制部署流程 环境准备 操作系统初始化配置 关闭防火墙 配置SELinux 关闭SWAP 根据规划设置主机名 在master添加hosts,便于主机名解析 调整内核参数 配置时间同步 部署docker引擎 在所有node节点部署docker引擎 部署etcd集群 签发…...

【Django开发】0到1开发美多商城项目第3篇:用户注册业务实现(附代码,已分享)
本系列文章md笔记(已分享)主要讨论django商城项目相关知识。项目利用Django框架开发一套前后端不分离的商城项目(4.0版本)含代码和文档。功能包括前后端不分离,方便SEO。采用Django Jinja2模板引擎 Vue.js实现前后端…...

免费的ppt网站分享
前言 相信大学生们深有体会,对于学校而言,好像是任何活动都需要我们做ppt,当你拿着自己辛苦做的ppt去展示现场的时候,你看到别人的ppt比你的还好,此时心情就是毙,当你知道人家不过是仅仅的1个小时不到就完成…...

基于Transformer结构的扩散模型综述
🎀个人主页: https://zhangxiaoshu.blog.csdn.net 📢欢迎大家:关注🔍点赞👍评论📝收藏⭐️,如有错误敬请指正! 💕未来很长,值得我们全力奔赴更美好的生活&…...

POI操作word表格,添加单元格,单元格对齐方法(不必合并单元格)
添加单元格,直接对row进行create新的cell,则会导致新创建的单元格与前面的单元格不对齐的现象。 //表格信息XWPFTable table doc.createTable();table.setWidth("100%");//第一行XWPFTableRow row0table.getRow(0);XWPFTableCell cell00row0.…...

maven代码规范检查(checkstyle、findbugs)
maven代码规范检查 前言一、使用checkstyle插件1. maven-checkstyle-plugin 介绍2. 接入方式3. 如何排除某个类、包下面的文件不进行检查使用suppressionsLocation 4. 如何关闭 二、使用findbugs插件1.findbugs-maven-plugin介绍2. 接入方式3. 如何排除某个类、包下面的文件不进…...

妙用Java反射,让代码更加优雅
最近在改公司项目bug,需要修改别人的代码。在读别人的源码时感觉到反射真的是能够极大的提高代码的优雅性,在某些特定场景能极大的简化代码的编写。因此写了这篇文章用以记录分享。 我们先还原一下场景,在做数据展示的时候,需要处…...

实习日志10
1.用户信息 1.1.在用户管理中编辑用户信息 1.2.绑定公司id 1.3.显示在页面 2.修改识别逻辑 2.1.分析 先识别,再判断,清空键把识别结果清空 2.2.写码 修改了发票识别逻辑,略... 3.接高拍仪 3.1.js引入报错 分析: 遇到的错误…...

配置alias(设置别名@)
Vite配置alias需要两步进行(TS项目) 1、修改vite.config.ts(让程序支持)2、修改tsconfig.json(让编辑器支持)修改vite.config.ts import { defineConfig } from vite import path from path function…...

【动态规划】【数学】1388. 3n 块披萨
作者推荐 【动态规划】【字符串】【表达式】2019. 解出数学表达式的学生分数 本文涉及知识点 动态规划汇总 LeetCode1388 3n 块披萨 给你一个披萨,它由 3n 块不同大小的部分组成,现在你和你的朋友们需要按照如下规则来分披萨: 你挑选 任…...

CS144--Chapter0--wsl2+docker环境搭建
我的笔记本配置 荣耀magicbook16,容量是500G,芯片是R7-5800 由于笔记本容量较小,因此考虑这个方案,对于台式机用户,建议可以直接用虚拟机或者双系统。 前言 斯坦福官网给出的方法是用他们的镜像(基于Ubu…...

MGRE实验报告二
实验要求: 实验预览图: 实验分析: 1、对R1-R5配置IP地址,同时R1-R5每个路由器各有一个环回 2.1、对R1、R3、R4路由器开启虚拟接口1,分别配置隧道IP、接口封装协议,接口类型、定义封装源、开启伪广播功能&…...

算法设计与分析实验:最短路径算法
一、网络延迟时间 力扣第743题 本题采用最短路径的思想进行求解 1.1 具体思路 (1)使用邻接表表示有向图:首先,我们可以使用邻接表来表示有向图。邻接表是一种数据结构,用于表示图中顶点的相邻关系。在这个问题中&am…...

共用体与枚举法,链表的学习
结构体注意事项: 1.结构体类型可以定义在main函数里面,但是此时的作用域就被限定在该函数中 2.结构体的的的定义的形式:a.先定义类型,后定义变量-----struct stu s b.定义类型的同时,定义了变量:struct…...

SG2520CAA汽车用晶体振荡器
爱普生SG2520CAA是简单的封装晶体振荡器(SPXO),具有CMOS输出,这款SPXO是汽车和高可靠性应用的理想选择,符合AEC-Q200标准,功耗低,工作电压范围为1.8 V ~ 3.3 V类型,宽工作温度-40℃~…...

使用pip将第三方依赖包下载到本地指定位置
pip download -d save_path packages -d:后面接下载包路径(save_path) packages:安装包名称...

C语言探索:水仙花数的奥秘与计算
摘要: 水仙花数,一种特殊的三位数,其各位数字的立方和等于该数本身。本文将详细介绍水仙花数的定义、性质,以及如何使用C语言来寻找100至999范围内的水仙花数。 目录 一、水仙花数的定义与性质 二、用C语言寻找100至999范围内的…...