vue3组合式api的函数系列一

1、响应式核心

1)、 ref(值)

1)、功能:接受值,返回一个响应式的、可更改的 ref 对象,ref对象只有一个属性:value。value属性保存着接受的值。

2)、使用ref对象:模板上不需要写 .value 属性(会自动解构),在js中,使用 .value 来完成数据的读写

3)、ref可以接收基本类型和引用类型

  • ref可以接收基本类型。

  • ref也可以接收引用类型:如果将一个对象传给 ref函数,那么这个对象将通过 reactive() 转为具有深层次响应式的对象。

const count = ref(0)
console.log(count.value) // 0
​
count.value++
console.log(count.value) // 1

示例

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app"><!-- ref响应对象,在模板上使用时,不需要.value,因为,在模板上vue会自动处理 --><p>msg:{{msg}}</p><input type="button" value="修改msg" @click="changeMsg"></div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    // ref:对应着选项式api中data(data中的数据都是响应式的)​const {createApp,ref} = Vue;
​let app = createApp({setup(){// ref()函数会返回一个响应式对象,该响应式对象的value属性,保存着数据的值// 1、在模板使用时,不需要 .value// 2、在js中使用时,需要 .valuelet msg=ref("hello");//ref函数返回一个响应式的对象,该对象的value属性的值是"hello"console.log("msg",msg);console.log("msg.value",msg.value);
​function changeMsg(){msg.value+="1";}
​return {msg,changeMsg}}})
​app.mount("#app");
​
</script>

以后创建 非 对象类型的数据 使用 ref, 创建对象类型的数据建议使用 reactive

2)、 reactive(对象)

1)、功能: 接受一个对象,返回一个对象的响应式代理(proxy)。返回的对象以及其中嵌套的对象都会通过 ES Proxy 包裹,因此不等于源对象,建议只使用响应式代理,避免使用原始对象。

响应式转换是“深层”的:它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性,同时保持响应性。【解释一下”解包“,也就是说不用 .value。或者说读取ref属性时,自动会把.value属性的值拿到。】

2)、注意点:当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包【还得使用.value】。

创建一个响应式对象:

const obj = reactive({ count: 0 })
obj.count++
2.1)、reactive的基本使用,对象使用reactive

reactive示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app"><!-- // 1、引用类型的数据使用reactive       --><p>person.name:{{person.name}}</p><p>person.sex:{{person.sex}}</p><p>person.age:{{person.age}}</p><input type="button" value="修改age" @click="changeAge"><p>person.wife.age:{{person.wife.age}}</p><input type="button" value="修改wife.age" @click="changeWifeAge"><hr/><!--  // 2、引用类型的数据使用ref --><p>book.name:{{book.name}}</p><p>book.price:{{book.price}}</p><input type="button" value="修改价格" @click="changePrice"><p>book.author.age:{{book.author.age}}</p><input type="button" value="修改作者的age" @click="changeAuthorAge"><hr/><!--   // 3、基本类型使用reactive:不会成为响应式 --><p>msg:{{msg}}</p><input type="button" value="修改Msg" @click="changeMsg"></div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    
​// reactive:对应着选项式api中data,一般使用在对象上// ref也可以让对象成为响应式的,只不过需要多些一个value。
​
​const {createApp,ref,reactive} = Vue;
​let app = createApp({setup(){
​// reactive()函数会返回代理对象Proxy。// 1、引用类型的数据使用reactivelet person = reactive({name:"王义鑫",sex:"男",age:18,wife:{name:"范冰冰",age:16}});
​console.log("person",person); //Proxy对象
​function changeAge(){person.age++;}function changeWifeAge(){person.wife.age++;}// 2、引用类型的数据使用reflet book = ref({name:"三国演义",price:51.2,author:{name:"罗贯中",age:108,address:"南窑头国际"}});
​function changePrice(){book.value.price ++;}function changeAuthorAge(){book.value.author.age++;}
​// 3、基本类型使用reactive:不会成为响应式let msg = reactive("hello");//如果给reactive传入基本类型的数据,那么,返回值就是基本类型console.log("msg",typeof msg);//string。肯不是响应式的了
​function changeMsg(){msg +="1";console.log("changeMsg函数",msg);}
​return {person,changeAge,changeWifeAge,book,changePrice,changeAuthorAge,msg,changeMsg}}})
​app.mount("#app");
​
</script>

2.2)把ref对象赋给reactive,会自动解包

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app">      <p>countRef:{{countRef}}</p><p>personReactive.count:{{personReactive.count}}</p><input type="button" value="修改count" @click="changeCount"></div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    
​// 把ref对象赋给reactive,会自动解包。// 进一步解释:把ref对象作为某个对象的属性值,并把该对象传给reactive,那么ref会自动解包
​const {createApp,ref,reactive} = Vue;
​let app = createApp({setup(){
​// 1、定义一个ref对象let countRef = ref(12);​// 2、把ref对象作为某个对象的属性值,并把该对象传给reactive,// 1)、那么ref会自动解包(把value属性取出来)// 2)、ref和对象的属性形成了关联关系。let personReactive = reactive({count:countRef //会解包,并且还会把count属性和countRef对象关联起来。});            console.log("personReactive.count",personReactive.count);//12;其实是代理对象读取count属性时,调用了get,get函数里返回的是ref对象的value属性console.log(personReactive.count===countRef);//falseconsole.log(personReactive.count===countRef.value);//true    
​function changeCount(){personReactive.count++;//修改reactive对象的属性时,ref的值也会变化。console.log("countRef.value",countRef.value);}
​// 3、如果没有reactive,肯定不会解包let obj = {count:countRef}
​console.log("obj.count",obj.count);//ref对象           
​return {countRef,personReactive,changeCount}}})
​app.mount("#app");
​
</script>

2.3)、注意:ref类型的数组元素不会解构。

当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包(模板上也不会解包):

const books = reactive([ref('Vue 3 Guide'),ref(5)])//给reactive传入的是数组。不会解包
// 这里需要 .value
console.log(books[0].value)//'Vue 3 Guide'
console.log(books[1].value)//5
​
const map = reactive(new Map([['count', ref(0)]]))//给reactive传入的是Map。不会解包
// 这里需要 .value
console.log(map.get('count').value)

示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app">      <ul><li v-for="item in booksReactive"><!-- 如果reactive对象里写的是ref数组时。显示ref对象的值时,需要使用 .value--><p>{{item.value}}</p></li></ul><input type="button" value="添加一本书" @click="addBook"></div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    
​
//   reactive接收ref的数组时,不会解包
​const {createApp,ref,reactive} = Vue;
​let app = createApp({setup(){
​let bookRef1 = ref("三国演义");let bookRef2 = ref("红楼梦");
​let booksReactive = reactive([bookRef1,bookRef2]);console.log("booksReactive",booksReactive);
​console.log("booksReactive[0]",booksReactive[0]);//ref对象console.log("booksReactive[1]",booksReactive[1]);//ref对象
​console.log("booksReactive[0].value",booksReactive[0].value);
​function addBook(){booksReactive.push(ref("西游记"));}
​return {booksReactive,addBook}}})
​app.mount("#app");
​
</script>

reactive 和 ref的选用:

对象用reactive,其它用ref

3)、 readonly()

1)、功能:接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理。

2)、只读代理是深层的:对任何嵌套属性的访问都将是只读的。它的 ref 解包行为与 reactive() 相同,但解包得到的值是只读的。

const original = reactive({ count: 0 })
​
const copy = readonly(original)
​
watchEffect(() => {// 用来做响应性追踪console.log(copy.count)
})
​
// 更改源属性会触发其依赖的侦听器
original.count++
​
// 更改该只读副本将会失败,并会得到一个警告
copy.count++ // warning

示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app">      <p>bookReadonly.name:{{bookReadonly.name}}</p><p>bookReadonly.author.name:{{bookReadonly.author.name}}</p><input type="button" value="修改" @click="changeName" ></div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    
​// readonly 接收一个对象(响应式对象,普通对象)和ref。让其成为只读的,而且,只读是深层次的。
​// 原生中学习的const的只读,只限定变量对应的内存区域是只读的。const p = {name:"王义鑫"}
​p = {name:"罗怡欣"};//不能改的console.log("p.name",p.name);//王义鑫
​p.name = "张伟业";//可以console.log("p.name",p.name);//张伟业
​
​const {createApp,ref,reactive,readonly} = Vue;
​let app = createApp({setup(){
​let book = {name:"三国演义",author:{name:"老罗",address:"南窑头国际"}}
​let bookReactive = reactive(book);
​let bookRef = ref(book);
​// let bookReadonly = readonly(book);// let bookReadonly = readonly(bookReactive);let bookReadonly = readonly(bookRef);
​console.log("bookReadonly",bookReadonly);
​function changeName(){// bookReadonly.name +=1;// console.log("bookReadonly.name",bookReadonly.name);// bookReadonly.author.name += 1;// console.log("bookReadonly.author.name",bookReadonly.author.name);
​bookReadonly.value.name +=1;console.log("bookReadonly.value.name",bookReadonly.value.name);}return {bookReadonly,changeName}}})
​app.mount("#app");
​
</script>

原生中 const 只能让对象本身只读,不能让对象的属性(包括嵌套属性)只读。

但是,readonly可以让对象的属性(包括嵌套属性)只读

既就是:

const:限制的是:地址(变量对应内存的内容)是只读的。

readonly:限制的是:值(变量引用的内存区域)是只读的

4)、 computed ()
  • 功能:computed是计算属性。和选项式api中的计算属性实现的功能一样。

  • 参数:

    • 可以接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。

    • 也可以接受一个带有 getset 函数的对象来创建一个可写的 ref 对象。

4.1)、创建一个只读的计算属性 ref:
const count = ref(1)
const plusOne = computed(() => count.value + 1)
​
console.log(plusOne.value) // 2
​
plusOne.value++ // 错误
4.2)、创建一个可写的计算属性 ref:
const count = ref(1)
const plusOne = computed({get: () => count.value + 1,set: (val) => {count.value = val - 1}
})plusOne.value = 1
console.log(count.value) // 0

示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app">      <!-- 1、定义一个只读的计算属性 --><p>count:{{count}}</p><p>doubleCount:{{doubleCount}}</p><input type="button" value="修改count" @click="changeCount" ><hr/><!--  2、定义一个可读写的计算属性 -->
​<p>age:{{age}}</p><p>wifeAge:{{wifeAge}}</p><input type="button" value="修改age" @click="changeAge" ><input type="button" value="修改wifeAge" @click="changeWifeAge" >       
​</div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    
​const {createApp,ref,reactive,computed} = Vue;
​let app = createApp({setup(){
​// 1、定义一个只读的计算属性let count = ref(5);
​// 定义一个计算属性:let doubleCount = computed(()=>count.value*count.value);
​function changeCount(){count.value ++;}
​// 2、定义一个可读写的计算属性
​let age = ref(20);
​let wifeAge = computed({set:function(newVal){console.log("newVal",newVal);age.value = newVal-3;},get:function(){return age.value+3 }})
​function changeAge(){age.value--;}function changeWifeAge(){wifeAge.value--;}
​return {count,doubleCount,changeCount,age,wifeAge,changeAge,changeWifeAge}}})
​app.mount("#app");
​
</script>

5)、 watch()
watch(第一个参数,第二个参数,第三个参数)

功能:侦听数据的变化,和选项式api中的watch实现的功能一样,组合式api中watch功能更加强大,灵活。默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。

参数:

  • 第一个参数:侦听器的,可以是以下几种:

    • 一个函数(返回一个值的函数)

    • 一个 ref

    • 一个reactive

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

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

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

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

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

    • deep:如果源是对象,侦听的源(是ref),强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器。

返回值: 是个函数,该函数可以停止侦听。

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

  • 懒执行副作用;

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

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

  • 示例

    侦听一个 ref(侦听ref 不用写value):

    const count = ref(0)
    watch(count, (count, prevCount) => {/* ... */
    })

    侦听一个 getter 函数:

  const state = reactive({ count: 0 })
watch(() => state.count,(count, prevCount) => {/* ... */})

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

  watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {/* ... */})

当使用 getter 函数作为源时,回调只在此函数的返回值变化时才会触发。如果你想让回调在深层级变更时也能触发,你需要使用 { deep: true } 强制侦听器进入深层级模式。在深层级模式时,如果回调函数由于深层级的变更而被触发,那么新值和旧值将是同一个对象。

  const state = reactive({ count: 0 })watch(() => state,(newValue, oldValue) => {// newValue === oldValue},{ deep: true })

当直接侦听一个响应式对象时,侦听器会自动启用深层模式:

  const state = reactive({ count: 0 })watch(state, () => {/* 深层级变更状态所触发的回调 */})

示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app">      <!--  1、监听一个ref。 --><p>age:{{age}}</p><p>wifeAge:{{wifeAge}}</p><input type="button" value="修改age" @click="changeAge" ><hr/>
​<!--  2、监听一个响应式对象 -->
​<p>person.name:{{person.name}}</p><p>person.wife.name:{{person.wife.name}}</p><input type="button" value="修改wife的name" @click="changeWifeName" ><hr/>  
​<!--  3、监听一个回调函数 -->       <p>count:{{count}}</p>         <input type="button" value="修改count" @click="changeCount" />
​<p>inc:{{inc}}</p> <input type="button" value="修改inc" @click="changeInc" /><hr/>
​<!-- 4、体现deep (当返回值是一个对象时,需要使用deep:true --><p>a:{{objReactive.a}}</p><p>b.b1:{{objReactive.b.b1}}</p><input type="button" value="修改deep" @click="changeDeep"><!-- 5、清除上次的副作用代码--><hr/><input type="text" v-model="value" ><!-- 6、停止侦听-->        <hr/><input type="button" value="取消侦听" @click="clearWatch"></div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    
​const {createApp,ref,reactive,watch} = Vue;
​let app = createApp({setup(){
​// 1、监听一个ref。
​let age = ref(18);
​let wifeAge = ref(0);
​watch(age,function(newVal,oldVal){console.log("watch",newVal,oldVal);wifeAge.value = newVal + 3;},{immediate:true})
​function changeAge(){age.value--;}
​// 2、监听一个响应式对象
​let person = reactive({name:"王义鑫",age:12,wife:{name:"范冰冰"                    }})watch(person,function(){console.log("watch person");})
​function changeWifeName(){                console.log("changeWifeName");// person = {};//这样修改,不会监听到,因为,你已经让person变成了普通对象,而不是proxy对象
​// person.wife = {};//可以// person.wife.name="李冰冰";//可以}
​// 3、监听一个回调函数let count = ref(12);let inc = ref(2);
​// 因为回调函数里使用了count和inc,所以,相当于监听了 count和inc的变化watch(()=>count.value+inc.value,function(newVal){// watch([count,inc],function(newVal){console.log("watch监听回调函数newVal",newVal);},{immediate:true});function changeCount(){count.value ++;}
​function changeInc(){inc.value ++;}
​// 4、体现deep
​let objReactive = reactive({a:1,b:{b1:2,b2:3}})
​// 当监听的源是回调函数时,只有在 回调函数的返回值发生变化时,才触发watch。// 那么,如果:返回值是引用类型,那么地址不变,返回值就不会变。所以说,改变对象的属性时,并不会引起watch。// 所以说:  当回调函数(侦听源)的返回值是(响应式)对象时。需要使用deep。watch(()=>objReactive,function(){console.log("watch,deep");},{deep:true})
​function changeDeep(){console.log("changeDeep");// objReactive.a ++;//并没有改变 objReactive对象,只是改变了对象的属性。objReactive.b.b1 ++;}// 5、清除上次的副作用// 清除上次启动的定时器。const value = ref("");
​const stopHandle =  watch(value,(newVal,oldVal,onCleanup)=>{
​// 发送请求let myTimer = setTimeout(()=>{console.log("响应回来了");},2000)
​onCleanup(()=>{// 这个函数:实在watch下次触发时,优先调用函数。window.clearTimeout(myTimer);})
​})
​//6、清除侦听器function clearWatch(){stopHandle();//清除侦听。}
​return {age,wifeAge,changeAge,person,changeWifeName,count,inc,changeCount,changeInc,objReactive,changeDeep,value,clearWatch}}})
​app.mount("#app");
​
</script>

6)、 watchEffect()

watchEffect

function watchEffect(effect: (onCleanup: OnCleanup) => void,options?: WatchEffectOptions
): StopHandle

  • 功能: watchEffect也是监听数据,但是它会立即运行一个函数,而不是懒侦听。watchEffect侦听(依赖)的数据:watchEffect里使用了哪个数据,哪个数据就是watchEffect的依赖。watchEffect是深度侦听的。

  • 参数:

    • 第一个参数:要运行的副作用函数。这个副作用函数的参数也是一个函数,注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如:等待中的异步请求。(和watch的第二个参数中回调函数的第三参数一样)。

  • 第二个参数:可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。因为,侦听默认是在vue组件更新前调用,如果你希望组件更新后调用,可以把第二个参数传入:{ flush: 'post' }

  • 返回值:用来停止该副作用的函数。

const count = ref(0)
​
watchEffect(() => console.log(count.value))
// -> 输出 0
​
count.value++
// -> 输出 1

6.1)、基本使用(副作用)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app">      <p>age:{{age}}</p><p>isAdult:{{isAdult}}</p><input type="button" value="修改Age" @click="changeAge" ><p>count:{{count}}</p><p>isLimit:{{isLimit}}</p><p>limitChina:{{limitChina}}</p><input type="button" value="修改Count" @click="changeCount" ></div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    
​const {createApp,ref,reactive,watch,watchEffect,computed} = Vue;
​let app = createApp({setup(){
​let age = ref(16);let isAdult = ref(false);
​let count = ref(5);let maxCount = 10;let isLimit = ref(false);//是否达到上限let limitChina = computed(()=>isLimit.value?"不能再买了":"继续买");
​// 1、watchEffect回调函数里,使用哪个响应式数据,那么就会监听哪个数据。
​watchEffect(()=>{                console.log("watchEffect:age.value",age.value);// 此处写的是 age发生变化时的副作用(即:当age发生变化,还应该做什么事情)isAdult.value = age.value>=18?true:false;
​// 此处写的是:count发生变化时的副作用。isLimit.value = count.value>=maxCount?true:false;
​});
​// watch(age,function(){//     console.log("watch:age.value",age.value);// })
​function changeAge(){age.value++;}
​function changeCount(){if(isLimit.value){return;}
​count.value++;}return {age,changeAge,isAdult,count,changeCount,isLimit,limitChina}}})
​app.mount("#app");
​
</script>
​
​
​

6.2)、副作用清除:

下面的示例,有点像防抖。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>    <div id="app">      <p>count:{{count}}</p><p>isLimit:{{isLimit}}</p><input type="button" value="修改" @click="changeCount" ></div>
</body>
</html>
​
<script src="./js/vue.global.js"></script>
<script>    
​const {createApp,ref,reactive,watchEffect} = Vue;
​let app = createApp({setup(){
​let count = ref(1);let isLimit = ref(false);​watchEffect((cb)=>{console.log("watchEffect:count.value",count.value);
​let myTimer = setTimeout(function(){
​console.log("修改isLimit的值");isLimit.value = count.value>=10?true:false
​},2000);
​// cb里的回调函数是在下次触发副作用时,首先会执行的代码。cb(()=>{console.log("清除定时器");clearTimeout(myTimer);})
​});
​function changeCount(){count.value++;}
​return {count,changeCount,isLimit}}})
​app.mount("#app");
​
</script>

6.3)、停止侦听器:
 const stop = watchEffect(() => {console.log(count.value)})// 当不再需要此侦听器时:const stopWatch = () => {stop()}

示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>watchEffect</title>
</head>
<body><div id="app"><button @click="increment">点击了{{ count }}次</button><p id="p01">p01的内容:{{msg}}</p><button @click="addMsg">点击了addMsg</button><button @click="stopWatch">停止监听</button>
​<ul><li @click="id=1">请求第一条数据</li><li @click="id=2">请求第二条数据</li><li @click="id=3">请求第三条数据</li></ul></div>
</body>
<script src="./js/vue.global.js"></script>
<script>const { createApp, ref, watchEffect } = Vue
​const app = createApp({
​setup () {const count = ref(0)
​const increment = () => {count.value += 1}
​const msg = ref("a");
​const addMsg = ()=>{msg.value += 1;}
​// 返回值可以用来停止侦听const stop = watchEffect(() => {console.log(document.getElementById("p01").innerHTML);//此处打印更新前还是更新后的值,由第二个参数决定console.log(`监听到count的数据为${count.value}`)console.log(`监听到msg的数据为${msg.value}`)},{flush:"post"})
​const stopWatch = () => {stop()}
​const id = ref(1)
​watchEffect((onCleanup) => {console.log("id.value",id.value) // 关键  ---  引起 当前 watchEffect 二次执行const timer = setTimeout(() => {console.log(`请求第${id.value}条数据`)}, 3000)console.log("timer",timer);
​// onCleanup的回调函数 会在id更改优先调用。如:下次id更改时,可以对上次的未完成的事情(如:请求)做清除……onCleanup(() => {console.log('onCleanup的回调函数被调用了','清除')clearTimeout(timer);//在id的值更新比较频繁时,只让最后一次请求起作用  })
​})
​// onInvalidatereturn {count,increment,msg,addMsg,stopWatch,id}}})
​app.mount('#app')
</script>
</html>

watchEffect没有具体监听哪一个值的变化,只要内部有某一个状态发生改变就会执行

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

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

相关文章

腾讯mini项目-【指标监控服务重构】2023-08-28

今日已办 分工 测试 - 谢雨晨、郑兆隆将1的测试结果记录整理为一个表格&#xff0c;列有&#xff1a;平均内存、最大内存、95内存、cpu的这些等等 - 邓烨钒HyperScan和官方正则库的benchmark对比 - 张锐添PPT制作 - 其他人灵活调动 进度 trace上报&#xff1a;jaeger-colle…

【Linux】【网络】传输层协议:TCP

文章目录 TCP 协议1. TCP 协议段格式2. TCP 报头解析3. TCP 的可靠性4. 面向字节流5. 粘包问题6. 连接队列维护 TCP 的 确认应答机制TCP 的 超时重传机制TCP 的 三次握手TCP 的 四次挥手setsockopt 函数&#xff1a;设置套接字选项&#xff0c;解决 TIME_WAIT 状态引起的 bind …

基于jquery开发的Windows 12网页版

预览 https://win12.gitapp.cn 首页代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"refresh" content"0;urldesktop.html" /> <meta name"viewport&…

NPDP产品经理认证怎么报名?考试难度大吗?

PMDA&#xff08;Product Development and Management Association&#xff09;是美国产品开发与管理协会&#xff0c;在中国由中国人才交流基金会培训中心举办NPDP&#xff08;New Product Development Professional&#xff09;考试&#xff0c;该考试是产品经理国际资格认证…

python+vue驾校驾驶理论考试模拟系统

管理员的主要功能有&#xff1a; 1.管理员输入账户登陆后台 2.个人中心&#xff1a;管理员修改密码和账户信息 3.用户管理&#xff1a;管理员可以对用户信息进行添加&#xff0c;修改&#xff0c;删除&#xff0c;查询 4.添加选择题&#xff1a;管理员可以添加选择题目&#xf…

upload-labs靶场未知后缀名解析漏洞

upload-labs靶场未知后缀名解析漏洞 版本影响&#xff1a; phpstudy 版本&#xff1a;5.2.17 ​ 1 环境搭建 1.1 在线靶场下载&#xff0c;解压到phpstudy的www目录下&#xff0c;即可使用 https://github.com/c0ny1/upload-labs1.2 已启动&#xff1a;访问端口9000&…

lS1028 + 六网口TSN 硬交换+QNX/Linux实时系统解决方案在轨道交通系统的应用

lS1028 六网口TSN 硬交换QNX/Linux实时系统解决方案在轨道交通系统的应用 以下是在轨道交通应用的实物&#xff1a; CPUNXP LS1028A架构双核Cortex-A72主频1.5GHzRAM2GB DDR4ROM8GB eMMCOSUbuntu20.04供电DC 12V工作温度-40℃~ 80℃ 功能数量参数Display Port≤1路支持DP1.3…

WebDAV之葫芦儿·派盘+NMM

推荐一款文件管理器,可以对手机中的文件进行多方面的管理,支持语法高亮和ftp等远程的文件的管理。支持从WebDav服务器连接葫芦儿派盘服务下载文件和上传文件。 NMM文本编辑器是一款文件管理器,在功能上面更加的适合于一些编程人员进行使用,需要在手机上面进行各种代码编辑的…

HarmonyOS 4.0 实况窗上线!支付宝实现医疗场景智能提醒

本文转载自支付宝体验科技&#xff0c;作者是蚂蚁集团客户端工程师博欢&#xff0c;介绍了支付宝如何基于 HarmonyOS 4.0 实况窗实现医疗场景履约智能提醒。 1.话题背景 8 月 4 日&#xff0c;华为在 HDC&#xff08;华为 2023 开发者大会&#xff09;上推出了新版本操作系统…

C++之std::function类模板定义函数对象应用总结(二百三十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

python的讲解和总结V2.0

python的讲解和总结V2.0 一、Python的历史二、Python的特点三、Python的语法四、Python的应用领域五、Python的优缺点优点a. 简单易学&#xff1a;b. 可读性强&#xff1a;c. 库和框架丰富&#xff1a;d. 可移植性强&#xff1a;e. 开源&#xff1a; 缺点a. 运行速度较慢&#…

高速USB转8路RS422串口

基于480Mbps 高速USB转8路串口芯片CH348&#xff0c;可以为各类主机扩展出8个独立的串口。使用厂商提供的VCP串口驱动程序&#xff0c;可支持Windows、Linux、Android、macOS等操作系统。使用单个CH348芯片即可实现USB一拖八串口转接产品&#xff0c;高速USB收发器和控制器、高…

vue做无缝滚动

类似于这种&#xff1a; 以上截图来自于官网&#xff1a;vue-seamless-scroll 具体使用步骤为&#xff1a; 1:安装 cnpm install vue-seamless-scroll --save  2&#xff1a;引入 <vue-seamless-scroll></vue-seamless-scroll>import vueSeamlessScroll from …

最熟悉的陌生人!Java运算符详解

&#x1f451;专栏内容&#xff1a;Java⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、算术运算符1、四则运算符2、增量运算符3、自增、自减运算符 二、关系运算符三、关系运算符1、逻辑与 &&2、逻辑或|…

Android.bp常用语法和预定义属性

介绍 Android.bp是Android构建系统中用于定义模块和构建规则的配置文件&#xff0c;它使用一种简单的声明式语法。以下是Android.bp的一些常见语法规则和约定&#xff1a; 注释&#xff1a; 单行注释使用//符号。 多行注释使用/和/包围。 和go语言相同 // 这是单行注释 /* 这是…

jenkins自动化部署springboot、gitee项目

服务器需要安装jdk11、maven、gitee 1. jenkins安装 # yum源 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo # 公钥 sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io-2023.key # 安装 yum install jenkins如果yum源报…

Redis入门 (店铺营业状态设置) --苍穹外卖day4

目录 redis简介 redis下载与安装 redis服务启动与停止​编辑 redis数据类型 五种常用数据类型 各个类型特点 redis常用命令 字符串 哈希 列表 集合 有序集合 通用指令 ​在Java中操作Redis 导入坐标 编写配置类​ 通过RedisTem~对象操作 字符串 ​哈希 列…

uni-app:实现密码框内容展示与隐藏

效果 代码 <template><view class"container"><view class"item_left"><view>密码</view><view class"eye_position" taptoggleShowPassword><image :srceye v-ifisShowPassword /><image :srcey…

20-SpringCloudAlibaba-1

一 Spring Cloud Alibaba简介 什么是Spring Cloud Alibaba Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案。 此项目包含开发分布式应用微服务的必需组件&#xff0c;方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。 为什么要推出Sp…

深入理解Elasticsearch中的Match Phrase查询

文章目录 摘要Match Phrase查询的原理Match Phrase查询的用法Match Phrase查询的示例代码 Match Phrase查询的注意事项总结 摘要 Elasticsearch是一个功能强大的开源搜索引擎&#xff0c;它提供了丰富的查询功能。其中&#xff0c;Match Phrase查询是一种强大的查询类型&#…