vue3 响应式 API:watch()、watchEffect()

news2025/2/5 15:40:36

watch()

  • 基本概念
    • watch()用于监视响应式数据的变化,并在数据变化时执行相应的回调函数。
    • 可以监视单个响应式数据、多个响应式数据的组合,或者一个计算属性。
  • 返回值
    • 返回一个函数,调用这个函数可以停止监视。
  • 特点
    • watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。
    • watch()可以监视单个数据、多个数据的组合或计算属性。
    • 通过深度监视选项,可以方便地监视对象的内部属性变化。
    • 立即执行选项可以在特定情况下立即执行回调函数,提供更多的控制。

watch()的参数说明

watch()函数接收3个参数:数据源、回调函数、选项对象(可选)。

  • 第一个参数:数据源(被监视的数据)
    • ref()定义的数据:基本类型的响应式变量、对象类型的响应式变量。
    • reactive()定义的数据:对象类型的响应式变量。
    • 一个返回响应式数据的函数,比如一个计算属性的 getter 函数。
    • 一个包含上述内容的数组。

  • 第二个参数:回调函数
    • 当数据源发生变化时,会调用这个回调函数。
    • 回调函数接收三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数onInvalidate
      • 如果只监视一个数据源,那么新值和旧值分别对应数据源变化后的新值和变化前的旧值。
      • 如果监视多个数据源,那么新值和旧值分别是一个包含新数据源值的数组和一个包含旧数据源值的数组。
      • onInvalidate: 这是一个用于注册副作用清理的回调函数。这个回调函数可以在 watch() 的回调函数内部调用,传入一个清理函数作为参数。这个清理函数会在下次 watch() 回调执行之前被调用,以便清理上一次执行产生的副作用。
    • 示例:(newValue, oldValue) => { /* 处理变化的逻辑 */ }
      (newValue, oldValue, onInvalidate) => { /* 处理变化的逻辑, 用于注册副作用清理的回调函数 */ }

  • 第三个参数:选项对象(可选)
    • deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器。
      • 布尔值,默认值为false
      • 如果设置为true,则会进行深度监视,即当监视的是一个对象时,对象的内部属性发生变化也会触发回调函数。
    • immediate:侦听器创建时立即触发回调。第一次调用时旧值是 undefined
      • 布尔值,默认值为false
      • 如果设置为true,则在创建 watch() 时立即调用回调函数,此时旧值是 undefined,新值是当前值。
    • flush:控制回调函数的执行时机。参考回调的刷新时机及 watchEffect()。
      • 默认值是'pre',表示在 DOM 更新之前执行回调;
      • 'post'表示在 DOM 更新之后执行回调;
      • 'sync'表示同步执行回调,即立即执行回调函数,并且在响应式数据变化时同步更新视图。
    • onTrack / onTrigger:调试侦听器的依赖。参考调试侦听器。
      • onTrack(用于调试):当响应式数据被读取并作为依赖被追踪时,这个函数会被调用。可以在这个函数中记录哪些数据被读取了,以便进行调试和分析依赖关系。
      • onTrigger(用于调试):当响应式数据发生变化并触发依赖时,这个函数会被调用。可以在这个函数中记录哪些数据发生了变化,以便进行调试和分析依赖关系。
    • once:回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。
      • 布尔值,默认值为false
      • 如果设置为true,回调函数只会执行一次。侦听器将在回调函数首次运行后自动停止。

示例

监视ref()定义的【基本类型】数据

语法: watch(变量名, (newValue, oldValue) => {})
监视时直接写变量名,其本质上监视的是.value

<template>
  <div>
    <div>count: {{ count }}</div>
    <button @click="addCount">点击 count+1</button>
  </div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';

let count = ref(0)

const addCount = () => {
  count.value++
}

// watch 监视的是 ref定义的数据:count
watch(count, (newValue, oldValue) => {
  console.log(`count 从 ${oldValue} 变为 ${newValue}`);
})
</script>

使用watch()监视count这个响应式变量的变化。当count的值发生变化时,回调函数会被执行,打印出旧值和新值。

监视ref()定义的【对象类型】数据

语法: watch(变量名, (newValue, oldValue) => {})
监视时直接写变量名,监视的是对象的引用地址值,如果想监视对象的内部属性变化,要手动开启深度监视(deep: true

  • 如果修改的是ref()定义的对象中的属性,newValueoldValue 都是新值,因为它们是同一个对象(同一个引用地址)。
  • 如果修改整个ref()定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。

示例:

<template>
  <div>
    <p>姓名: {{ person.name }}</p>
    <p>年龄: {{ person.age }}</p>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changePerson">修改整个人</button>
  </div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';

const person = ref({
  name: '张三',
  age: 18
});

const changeName = () => {
  person.value.name += '哈'  
}
const changeAge = () => {
  person.value.age ++   
}

const changePerson = () => {
  person.value = { name: '李四', age: 17 }
}

// changeName、changeAge修改person的内部属性,不会改变person的引用地址,不会触发 watch
// changePerson 对 person 重新赋值,改变了person的引用地址,触发watch
watch(person, (newValue, oldValue) => {
  console.log('newValue: ',  newValue)
  console.log('oldValue: ', oldValue)
})
</script>

如果想要深度监视对象的内部属性变化,可以在watch()第三个参数(选项对象)中设置deep: true

watch(person, (newValue, oldValue) => {
  console.log('newValue: ',  newValue)
  console.log('oldValue: ', oldValue)
},{ deep: true })

开启深度监视(deep: true)后,修改personname属性、age属性,触发了watch()监视。
但是,watch()监视到的newValueoldValue 都是新值:
在这里插入图片描述
这是因为newValueoldValue 都是指向同一个引用地址:person的引用地址。

为了更准确地区分新旧值,可以在修改对象内部属性之前,先对旧对象进行一个副本的创建,这样在watch()回调函数中,就可以把副本作为旧值来处理。

监视reactive()定义的【对象类型】数据

监视reactive()定义的对象类型的响应式变量,watch()默认开启了深度监视,且这个深度监视是无法关闭的(设置deep: false无效)。

<template>
  <div>
    <p>姓名: {{ person.name }}</p>
    <p>年龄: {{ person.age }}</p>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changePerson">修改整个人</button>
  </div>
</template>
<script setup lang="ts">
import { reactive, watch } from 'vue';

const person = reactive({
  name: '张三',
  age: 18
});

const changeName = () => {
  person.name += '哈'  
}
const changeAge = () => {
  person.age ++   
}

const changePerson = () => {
  // Object.assign 方法会合并源对象到目标对象上。
  // 当对一个 reactive 对象使用 Object.assign 时,对象的引用地址不会改变。
  // 它实际上是在修改原始对象的属性,而不是完全替换对象。
  Object.assign(person,{ name: '李四', age: 17 })
}


// 监视reactive()定义的对象类型的响应式变量,watch()默认开启了深度监视。
// changeName、changeAge修改person的内部属性,触发 watch
// changePerson 对 person 重新赋值,改变了person的引用地址,触发watch
watch(person, (newValue, oldValue) => {
  console.log('newValue: ',  newValue)
  console.log('oldValue: ', oldValue)
})
</script>

在这里插入图片描述
注意:新值和旧值是同一个值。因为它们都指向同一个引用地址。
changeNamechangeAgechangePerson 从本质上来讲,都是在修改person的属性,没有修改person的引用地址。

监视ref()reactive()定义的【对象类型】数据中的某个属性

  • 若该属性不是【对象类型】属性,需要写成函数形式
    • 当监视ref()reactive()定义的对象中的某个非对象类型属性时,需要写成函数形式。
    • 因为直接监视一个非对象类型的属性时,watch()无法准确追踪其变化。写成函数形式可以确保正确地获取属性值并进行监视。
  • 若该属性【对象类型】属性
    • 可以直接编写属性名进行监视
    • 可以写成函数形式
    • 如果要深度监视对象类型的属性,必须在watch()的选项中设置deep: true
<template>
  <div>
    <p>姓名: {{ person.name }}</p>
    <p>年龄: {{ person.age }}</p>
    <p>职业:{{ person.details.job }}</p>
    <p>年级:{{ person.details.grade }}</p>
    <button @click="changeName">修改名字</button>
    <button @click="changeJob">修改职业</button>
    <button @click="changeGrade">修改年级</button>
    <button @click="changeDetails">修改详细信息</button>
  </div>
</template>
<script setup lang="ts">
import { reactive, watch } from 'vue';

const person = reactive({
  name: '张三',
  age: 18,
  details: {
    job: 'senior high school student',
    grade: '高三'
  }
});

const changeName = () => {
  person.name += '哈'  
}

const changeJob = () => {
  person.details.job = 'undergraduate'   
}

const changeGrade = () => {
  person.details.grade = '大一'   
}

const changeDetails = () => {
  person.details = {
    job: 'fresh graduate',
    grade: '毕业啦!'
  }
}

// 监视person对象的name属性(基本类型),watch()的第一个参数写成函数式(getter函数)
// () => person.name是一个 getter 函数,它返回person对象的name属性值。
watch(() => person.name, (newName, oldName) => {
  console.log('newName:', newName, 'oldName:', oldName)
});


// 监视details属性中的job属性,watch()的第一个参数写成函数式(getter函数)
// () => person.details.job是一个 getter 函数,它返回person.details.job的值。
watch(() => person.details.job, (newJob, oldJob) => {
  console.log('newJob:', newJob, 'oldJob:', oldJob)
});


// 监视person对象的details属性(对象类型),watch()的第一个参数写成函数式(getter函数)
// () => person.details, 它返回person对象的details属性值。
watch(() => person.details, (newDetails, oldDetails) => {
  console.log('newDetails:', newDetails, 'oldDetails:', oldDetails)
});

// 监视person对象的details属性(对象类型),watch()的第一个参数可以直接写变量
watch(person.details, (newDetails, oldDetails) => {
  console.log('newDetails:', newDetails, 'oldDetails:', oldDetails)
});

// 监视person对象的details属性(对象类型),watch()的第一个参数可以直接写变量
watch(person.details, (newDetails, oldDetails) => {
  console.log('newDetails:', newDetails, 'oldDetails:', oldDetails)
});
</script>

在这个例子中:

  • watch()的第一个参数写成函数式(getter函数)。例如:() => person.name是一个 getter 函数,它返回person对象的name属性值。
  • changeJobchangeGrade不会触发watch(() => person.details, (newDetails, oldDetails) => {}),因为没有开启深度监视。
  • changeDetails 会触发两个监视:
    • watch(() => person.details.job, (newJob, oldJob) => {})
    • watch(() => person.details, (newDetails, oldDetails) => {})

在这里插入图片描述
如果要深度监视对象类型的属性,必须在watch()的选项中设置deep: true
例如,改变person.details.jobperson.details.grade 会 触发watch(person.details)

// 监视person对象的details属性(对象类型),写成函数式
watch(() => person.details, (newDetails, oldDetails) => {
  console.log('newDetails:', newDetails, 'oldDetails:', oldDetails)
}, { deep: true });

设置deep: truechangeJobchangeGradechangeDetails都会触发watch(() => person.details, (newDetails, oldDetails) => {})

监视多个响应式数据

<template>
  <div>
    <p>姓名: {{ name }}</p>
    <p>年龄: {{ age }}</p>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
  </div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';

let name = ref('张三')
let age = ref(18)
const changeName = () => {
  name.value = `${name.value}`
}
const changeAge = () => {
  age.value++
}

watch([name, age], (newValue, oldValue) => {
  console.log('newValue', newValue) // newValue是一个数组:[name, age]
  console.log('oldValue', oldValue) // oldValue是一个数组:[name, age]
})

// 当监视多个响应式数据时,回调函数接受两个数组,分别对应来源数组中的新值和旧值:
watch([name, age], ([newName, newAge], [oldName, oldAge]) => {
  console.log(`Name changed from ${oldName} to ${newName}`)
  console.log(`Age changed from ${oldAge} to ${newAge}`)
})
</script>

在这个例子中,监视了 nameage 两个响应式数据的变化。当其中任何一个数据发生变化时,回调函数会被执行,打印出两个数据的旧值和新值。

停止监视

使用 watch() 函数创建的监视器,可以通过调用watch()函数的返回值(是一个函数)来停止监视。

<template>
  <div>
    <div>count: {{ count }}</div>
    <button @click="addCount">点击 count+1</button>
  </div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';

let count = ref(0)

const addCount = () => {
  count.value++
}

// watch 监视的是 ref定义的数据:count
// watch()的返回值是一个函数,调用这个函数可以停止监视。
const stopWatcher = watch(count, (newValue, oldValue) => {
  console.log(`count 从 ${oldValue} 变为 ${newValue}`);
  // 当newValue > 10,结束监视
  if(newValue > 10) {
    // 调用stopWatcher ,结束监视
    stopWatcher ()
  }
})
</script>

立即执行回调函数

<template>
  <div>
    <p>Counter: {{ counter }}</p>
  </div>
</template>

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

const counter = ref(0)

watch(
  counter,(newValue, oldValue) => {
    console.log(`Counter changed from ${oldValue} to ${newValue}`)
  },
  { immediate: true }
)
</script>

通过设置选项对象的immediate: true,可以让watch()在创建后立即执行一次回调函数,无论被监视的数据是否已经发生变化。
此时,oldValue 的值为 undefined

只执行一次的回调函数

<template>
  <div>
    <p>Counter: {{ counter }}</p>
  </div>
</template>

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

const counter = ref(0)

watch(
  counter,(newValue, oldValue) => {
    console.log(`Counter changed from ${oldValue} to ${newValue}`)
  },
  { once: true }
)
</script>

通过设置选项对象的once: true,回调函数只会执行一次。侦听器将在回调函数首次运行后自动停止。

副作用清除

watch(id, async (newId, oldId, onCleanup) => {
  const { response, cancel } = doAsyncWork(newId)
  // 当 `id` 变化时,`cancel` 将被调用,
  // 取消之前的未完成的请求
  onCleanup(cancel)
  data.value = await response
})

watchEffect()

  • 基本概念
    watchEffect()立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
    • watchEffect()自动追踪函数中使用的响应式数据,并在这些数据发生变化时重新执行函数。
    • watch()不同,watchEffect()不需要明确指定要监视的数据源,它会自动分析函数内部的依赖关系(函数中用到哪些属性,那就监视哪些属性)。
  • 返回值
    • 返回一个函数,调用这个函数可以停止副作用的执行。

watchEffect()参数说明

watchEffect()函数接收以下参数:

  • 回调函数

    • 这是一个必须的参数,它是一个函数,在这个函数内部可以访问响应式数据和执行副作用逻辑。
    • 当使用watchEffect()时,它会立即执行这个回调函数,并在其依赖的响应式数据发生变化时再次执行这个回调函数。
    • 例如:watchEffect(() => { /* 副作用逻辑 */ })

  • 选项对象(可选)

    • flush:控制回调函数的执行时机。参考回调的刷新时机及 watchEffect()。
      • 默认值是'pre',表示在 DOM 更新之前执行回调;
      • 'post'表示在 DOM 更新之后执行回调;
      • 'sync'表示同步执行回调,即立即执行回调函数,并且在响应式数据变化时同步更新视图。
    • onTrack / onTrigger:调试侦听器的依赖。参考调试侦听器。
      • onTrack(用于调试):当响应式数据被读取并作为依赖被追踪时,这个函数会被调用。可以在这个函数中记录哪些数据被读取了,以便进行调试和分析依赖关系。
      • onTrigger(用于调试):当响应式数据发生变化并触发依赖时,这个函数会被调用。可以在这个函数中记录哪些数据发生了变化,以便进行调试和分析依赖关系。

示例

基本用法

<template>
  <div>
    <p>a: {{ a }}</p>
    <p>b: {{ b }}</p>
    <p>sum: {{ sum }}</p>
    <button @click="incrementA">点击 a+2</button>
    <button @click="incrementB">点击 b+5</button>
    <button @click="incrementSum">点击 sum+1</button>
  </div>
</template>

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

const a = ref(5)
const b = ref(10)
const sum = ref(0)

const incrementA = () => {
  console.log("incrementA");
  a.value = a.value + 2
}

const incrementB = () => {
  console.log("incrementB");
  b.value = b.value + 5
}

const incrementSum = () => {
  console.log("incrementSum");
  sum.value = sum.value + 1
}

// watchEffect()的返回值是一个函数,调用这个函数可以停止监视。
let stopEffect = watchEffect(() => {
  console.log('a:', a.value, 'b:', b.value)
  if(a.value < 20 && b.value < 100){
    sum.value = a.value + b.value
  }

  if(a.value > 20 || b.value > 100) {
    stopEffect()
  }
});

watch(sum, (newSum, oldSum) => {
  console.log('newSum', newSum, 'oldSum', oldSum)
})
</script>

在这个例子中:

  • watchEffect()会立即执行传入的函数,并在ab的值发生变化时重新执行该函数,根据条件计算sum的值。
  • watchEffect()的返回值是一个函数,调用这个函数可以停止监视。
  • incrementSum直接修改sum的值,不会触发watchEffect()。因为sumwatchEffect()是作为计算结果被赋值的,而不是直接被读取使用。
  • watch用于监视sum的变化,当sum的值发生变化时,打印出新值和旧值。
    在这里插入图片描述

使用watchEffect并带有选项对象

watchEffect(() => {
  console.log('a:', a.value, 'b:', b.value)
  if(a.value < 20 && b.value < 100){
    sum.value = a.value + b.value
  }
},
{
  flush: 'post' // 在 DOM 更新之后执行回调 
}
);

在这个例子中,watchEffect()的回调函数会在ab的值发生变化时执行,并在 DOM 更新之后计算sum的值。选项对象中的flush被设置为'post',以控制回调函数的执行时机。

副作用清除

watchEffect(async (onCleanup) => {
  const { response, cancel } = doAsyncWork(id.value)
  // `cancel` 会在 `id` 更改时调用
  // 以便取消之前
  // 未完成的请求
  onCleanup(cancel)
  data.value = await response
})

watch()watchEffect()的区别

  • 数据源
    • watch()需要明确指定要监视的数据源,可以是一个响应式数据、一个返回响应式数据的函数或者一个包含多个响应式数据的数组。
    • watchEffect()不需要明确指定数据源,它会自动追踪函数内部使用的响应式数据。
  • 回调函数参数
    • watch()的回调函数接收两个参数:新值和旧值。如果监视多个数据源,新值和旧值分别是一个包含新数据源值的数组和一个包含旧数据源值的数组。
    • watchEffect()的回调函数不接收新值和旧值参数,它只接收一个用于停止副作用的清理函数作为可选参数。
  • 是否立即执行
    • watch()在创建时不会立即执行回调函数,除非设置immediate: true
    • watchEffect()在创建时会立即执行传入的函数。

watchPostEffect()​

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

watchSyncEffect()​

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

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

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

相关文章

【Linux网络】select函数

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 select函数介绍select函数参数介绍select函数返回值select的工作流程TCP服务器【多路复用版】 select函数介绍 在Linux网络编程中&#xff0c;select 函数是一种非常有用的IO多路复用技术&#xff0…

秃姐学AI系列之:LeNet + 代码实现

目录 LeNet MNIST数据集 LeNet模型图 ​编辑 总结 代码实现&#xff1a;卷积神经网络 LeNet LeNet&#xff08;LeNet-5&#xff09;由两个部分组成&#xff1a;卷积编码器核全连接层密集块 检查模型 LeNet 卷积神经网络里面最为著名的一个网络&#xff0c;80年代末提出…

【vue教程】七. Vue 的动画和过渡

文章目录 往期列表回顾本章涵盖知识点Vue 的内置动画系统基本的进入和离开过渡列表过渡 CSS 过渡CSS 过渡基础Vue 中的 CSS 过渡 JavaScript 动画使用 JavaScript 钩子 第三方动画库的使用集成 Animate.css 实例演示创建一个简单的动画应用 结语 往期列表 【vue教程】一. 环境…

iOS18升级出现白苹果、无法重启等问题,要怎么解决

随着苹果iOS 18系统beta版本的推出&#xff0c;不少用户在私信说升级后遇到了白苹果和无法重启等问题。这些问题不仅影响了大家的正常使用&#xff0c;还会导致数据丢失和系统崩溃。本文将详细介绍iOS 18升级后出现白苹果、无法重启等问题的原因及解决方法&#xff0c;帮助大家…

日期转时间濯

tfunction(date_str) local code ,time World:getTimeFromDateString(date_str) return time/(60*60*24) end print(t(2024-08-16)-t(2024-08-3))

指针 (四)

一 . 指针的使用和传值调用 &#xff08;1&#xff09;strlen 的模拟实现 库函数 strlen 的功能是求字符串长度&#xff0c;统计的是字符串中 \0 之前的字符个数&#xff0c;函数原格式如下&#xff1a; 我们的参数 str 接收到一个字符串的起始地址&#xff0c;然后开始统计…

JS 获取当前操作系统类型

在JavaScript中&#xff0c;‌直接获取用户的操作系统信息是不可能的&#xff0c;‌因为JavaScript主要运行在浏览器中&#xff0c;‌而浏览器出于安全和隐私的考虑&#xff0c;‌不会提供访问操作系统详细信息的API。‌ 但是&#xff0c;‌你可以通过分析用户代理字符串&…

数据库性能定位-慢sql定位、sql优化(docker容器实战)

安装好mysql数据之后&#xff0c;创建库的时候&#xff0c;要注意选择 字符集编码。如果没有选择好&#xff0c;你的库表存中文的时候&#xff0c;会字符集乱码。选择utf8mb4. 建表的时候&#xff0c;存储引擎 InnoDB、MyISAM mysql5.7及以后数据库&#xff0c;表的默认存储引…

官方招募 | 仓颉语言三方库社区建设全速启航,全球开发者、技术大神只等您!

Cangjie-TPC招募令 仓颉社区的小伙伴们&#xff0c;官方三方库&#xff08;Cangjie-TPC&#xff09;招募开始啦&#xff01; Cangjie-TPC&#xff08;https://gitcode.com/Cangjie-TPC&#xff09; 是 Cangjie 社区用于汇集基于仓颉编程语言开发的开源三方库的主干仓&#xf…

JS获取当前浏览器名称

在JavaScript中&#xff0c;获取当前浏览器名称的方法并不是一个标准的功能&#xff0c;因为浏览器厂商并没有提供一个直接的API来获取浏览器的名称。但是&#xff0c;你可以通过分析用户代理字符串&#xff08;User-Agent&#xff09;来推断出浏览器的名称。 以下是一个简单的…

ArcGIS如何将投影坐标系转回为地理坐标系

有时候两个数据&#xff0c;一个为投影坐标系&#xff0c;另一个为地理坐标系时&#xff0c;在GIS软件中位置无法叠加到一起&#xff0c;这需要将两个或多个数据的坐标系统一&#xff0c;可以直接将地理坐标系的数据进行投影&#xff0c;或将投影坐标系转为地理坐标系。下面介绍…

视频号AI美女跳舞,轻松月入30000+,蓝海赛道,流量池巨大,起号猛

今天给大家分享的是一个男生比较感兴趣的内容&#xff0c;AI美女视频跳舞项目4.0版本&#xff0c;7天快速起号&#xff0c;实现每月30000的稳定收入. 大家刷抖音的时候&#xff0c;肯定都刷到过美女跳舞的视频&#xff0c;对吧&#xff1f;这种视频&#xff0c;不管在哪个平台…

电商项目DevOps一体化运维实战

主要讲了git和jkins的使用&#xff0c;其中maven的一个插件还挺好用的&#xff0c;主要可以用来查看哪些类没有使用&#xff0c;哪些导入的包是多余的等。这里展示一下用法。至于git和jkins的搭建后续再操作。 maven插件的使用&#xff1a; 编译后就可以在target下面看到这个h…

网络安全之XSS基础

从 XSS Payload 学习浏览器解码 xss payload 1.<a href"%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29">1</a> 2.<a href"&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:…

代码随想录:动态规划6-10

62、不同路径 题目 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径…

基于STM32开发的智能农业环境监控系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化传感器数据采集与处理环境控制与状态指示Wi-Fi通信与远程监控应用场景 农业温室环境管理农田环境监控与自动化管理常见问题及解决方案 常见问题解决方案结论 1. 引言 随着农业技术…

Codigger 视频会议(Meeting):制造业的高效协作引擎

在制造业数字化转型的浪潮中&#xff0c;企业面临着前所未有的机遇与挑战。视频会议作为一种高效的沟通工具&#xff0c;在制造业中发挥着关键作用。 制造业对于视频会议有着多方面的需求与挑战。不同生产基地往往分布在各地&#xff0c;跨地域协作需求十分迫切。在技术交流时&…

stm32—ADC

1. 什么是ADC 生活中我们经常会用到ADC这种器件&#xff0c;比如说&#xff0c;当我们在使用手机进行语音通信时&#xff0c;ADC器件会将我们的声信号转换为电信号 (模拟信号 ---> 数字信号) 模拟信号&#xff1a; 模拟信号是指用连续变化的物理量表示的信息&#xff0c;其信…

【Vue3】编程式路由导航

【Vue3】编程式路由导航 背景简介开发环境开发步骤及源码总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日…

【Qt】 常用控件QLCDNumber

常用控件QLCDNumber QLCDNumber是一个专门用来显示数字的控件&#xff0c;类似于“老式计算机”的效果。 QLCDNumber的属性 属性说明 intValue QLCDNumber 显⽰的数字值(int). value QLCDNumber 显⽰的数字值(double). 和 intValue 是联动的. 例如给 value 设为 1.5, i…