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>
可写的计算属性:

​ 默认情况下,声明的计算属性是只读的,不可修改。但我们可以通过同时给计算属性设置gettersetter方法来创建一个可读写的计算属性。虽然说是可写的计算属性,但实际上原理是在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()传入第二个参数,参数值为一个包含了onTrackonTrigger两个函数的对象。其中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元素之后:

在这里插入图片描述

注意:计算属性的 onTrackonTrigger 选项仅会在开发模式下工作。

3、其他
getter方法不应该有副作用:

​ 计算属性的getter方法只能用于根据依赖的响应式变量计算并返回计算的结果。一定不能在getter方法中进行修改其他变量的值、操作DOM以及发起异步请求等会产生副作用的操作,这违背了计算属性的设计初衷。

​ 在计算属性getter方法中使用 reverse()sort() 等会影响原有数据的方法时务必小心。由于这些方法将改变原始数组的值,因此在调用这些方法之前要深拷贝一个原始数据的副本,然后对副本进行操作,并返回操作后的结果。

计算属性依赖的变量必须为响应式变量:

​ 计算属性依赖的变量必须是响应式的变量,可以是refreactive声明的响应式变量,也可以是shallowRefshallowReactive声明的浅层响应式变量。但如果是浅层响应式变量,则只有修改可以被监听到的属性时,才会触发计算属性的重新计算,计算属性的值层会更新。

​ 通过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
})
侦听器调试:

​ 和计算属性类似,侦听器的第三个参数也支持 onTrackonTrigger 的调试选项。

// watch侦听器调试
watch(count, (newVal, oldVal) => { console.log('watch监听一个响应式变量--', newVal, oldVal);
}, {onTrack(e) {console.log('onTrack---', e);},onTrigger(e) {console.log('onTrigger---', e);}
});

注意:侦听器的 onTrackonTrigger 选项仅会在开发模式下工作。

停止侦听器:

​ 正常情况下用同步语句创建的侦听器,会自动绑定到当前组件实例上,并且会在当前组件卸载时自动停止。但如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它,以防内存泄漏。所以尽量不要在异步回调中创建侦听器。

​ 正常创建的侦听器,也可以被手动停止,但基本不需要这么做。

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'
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/662884.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】P1 Deep Learning 简介

目录 什么是深度学习深度学习网络结构深度学习重要历史节点常见深度学习库 什么是深度学习 深度学习&#xff0c;deep learning&#xff0c;是机器学习的分支&#xff0c;是一种以人工神经网络为架构&#xff0c;对资料进行表征学习的算法。而深度学习中“深度”一词&#xff…

Map和Set讲解

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f4d5;格言&#xff1a;那些在暗处执拗生长的花&#xff0c;终有一日会馥郁传香欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 集合框架 模型 Set 常见方法和说明 Set总结 Map说明 Map常见方法和说明 Map 中HashMap的 …

Linux一些实用操作

学习笔记&#xff0c;记录以下课程中关于Linux的一些实用操作。黑马程序员新版Linux零基础快速入门到精通&#xff0c;全涵盖linux系统知识、常用软件环境部署、Shell脚本、云平台实践、大数据集群项目实战等_哔哩哔哩_bilibili 目录 1 各类小技巧&#xff08;快捷键&#xff…

天翼数科实在智能,战略合作签约!Agent最大化赋能应用领域

近日&#xff0c;天翼数智科技(北京)有限公司&#xff08;以下简称“天翼数科”&#xff09;与杭州实在智能科技有限公司&#xff08;以下简称“实在智能”&#xff09;签署战略合作协议。 基于本次战略合作&#xff0c;天翼数科将与实在智能发挥各自的专业特长&#xff0c;整合…

SQL的函数类型

目录 一、聚合函数 二、数值型函数 三、字符串函数 四、日期函数 五、流程控制函数 一、聚合函数 定义&#xff1a;聚合函数是指对一组值进行运算&#xff0c;最终返回是单个值&#xff0c;也可以被称为组合函数。 COUNT() 统计目标行数量的函数 AVG() 求平均值 SU…

10:基于Servlet模拟用户登录功能的实现与解析-Java Web

目录 10.1 登录表单设计与前端交互10.2 创建Servlet处理登录请求10.3 用户服务模拟实现10.4 安全性与优化考量10.5 区别总结10.6 应用场景总结 在Web开发中&#xff0c;用户登录功能是几乎所有系统的基础模块。本篇博客将通过编写一个基于Java Servlet的用户登录模拟案例&#…

24美赛C思路分享

可以参考这篇文章通过数据分析理解网球一发的重要性 - 知乎 (zhihu.com)

C语言stderr、errno、strerror、perror

C语言stderr、errno、strerror、perror stderr 是标准错误输出&#xff0c;类型为 FILE* &#xff1b; errno 宏是运行时最近一次的错误代码&#xff0c;正常运行时值为 0&#xff1b; strerror() 函数用于获取 errno 错误代码对应的错误信息字符串&#xff1b; perror() 函数…

在CentOS 7 中配置 YUM源

目录 YUM源的功能&#xff1a; YUM 源的安装过程 ps YUM工具 配置YUM仓库/YUM源 网络源&#xff1a;使用官方源 前提&#xff1a;联网 YUM源的功能&#xff1a; YUM&#xff08;Yellowdog Updater Modified&#xff09;是一个在Red Hat、CentOS、Fedora等基于RPM的Linux发…

Nat Med | 儿童急性淋巴细胞白血病基因组景观中的药物类型

今天给同学们分享一篇实验文章“Pharmacotypes across the genomic landscape of pediatric acute lymphoblastic leukemia and impact on treatment response&#xff0c;这篇文章发表在Nat Med期刊上&#xff0c;影响因子为82.9。 结果解读&#xff1a; 与ALL药物敏感性的临…

C++(17.5)——list模拟实现扩展

在上篇文章中&#xff0c;实现了的大部分功能以及部分迭代器。本片文章将对剩下的功能进行补充。 1. const迭代器&#xff1a; 对于上篇文章中实现的迭代器只能使用于非类型的对象。对于类型的遍历&#xff0c;则需要额外编写类型的迭代器。例如对于下面的场景&#xff1a; …

【持续更新】2024牛客寒假算法基础集训营1题解 | JorbanS

文章目录 [A - DFS搜索](https://ac.nowcoder.com/acm/contest/67741/A)[B - 关鸡](https://ac.nowcoder.com/acm/contest/67741/B)[C - 按闹分配](https://ac.nowcoder.com/acm/contest/67741/C)[E - 本题又主要考察了贪心](https://ac.nowcoder.com/acm/contest/67741/E)[F -…

Linux定时删除log

编写删除脚本 logPath/data/cd $logPathecho "" > xiaozou/nohup.out配置定时任务 执行crontab -e 编辑新增定时任务 */30 * * * * sh /data/clear.sh查看定时任务执行log tail -f /var/log/cron

Unknown custom element:<xxx>-did you register the component correctly解决方案

如图所示控制台发现了爆红&#xff08;大哭&#xff09;&#xff1a; 报错解释&#xff1a; 当我们看到报错时&#xff0c;我们需要看到一些关键词&#xff0c;比如显眼的“component”和“name”这两个单词&#xff0c; 因此我们就从此处切入&#xff0c;大概与组件有关系。…

力扣(leetcode)第228题汇总区间(Python)

228.汇总区间 题目链接&#xff1a;228.汇总区间 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某个范围但不属于 num…

vue + element 页面滚动计算百分比 + 节流函数

html&#xff1a; <el-progress :percentage"scrollValue"></el-progress> js&#xff1a; data() {return {scrollValue: 0,} }, mounted() {window.addEventListener(scroll, this.handleScroll) // 监听页面滚动 }, beforeDestroy() {window.remov…

Spring Boot--07--@Repository 和@Mapper的区别

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.Repository的作用1.1 含义1.2 Repository与Service和Component有什么区别&#xff1f;1.3 使用场景单独使用Repository&#xff0c;需要配合使用MapperScannerCon…

深度学习的新前沿:突破、应用与挑战

引言 深度学习的快速发展已经在人工智能领域引起了革命性的变化。作为模仿人脑结构和功能的强大工具&#xff0c;深度神经网络在图像识别、自然语言处理、医学诊断等多个领域取得了显著成就。但是&#xff0c;随着技术的不断推进&#xff0c;深度学习也在不断地进化和扩展其能…

云上自动部署丨使用 Terraform 在 AWS 上搭建 DolphinDB

HashiCorp Terraform 是一款基础架构即代码工具&#xff0c;旨在实现 "Write, Plan, and Create Infrastructure as Code"。它通过配置文件来描述云资源的拓扑结构&#xff0c;包括虚拟机、存储账户和网络接口。Terraform 几乎支持市面上所有的云服务&#xff0c;能够…

一键部署FC超级马里奥web游戏

效果展示 安装 拉取镜像 #拉取镜像 docker pull stayhungrystayfoolish666/mario #创建并启动容器 docker run -d -p 10034:8080 --name maliao --restartalways stayhungrystayfoolish666/mario:latest 使用 浏览器打开 http://你的ip:10034/