首页IT科技vue3如何实现响应式(vue3 + ts)

vue3如何实现响应式(vue3 + ts)

时间2025-05-04 22:47:51分类IT科技浏览4549
导读:在 vue3.2 中,我们只需在script标签中添加setup。就可以做到,组件只需引入不用注册,属性和方法也不用 return 才能于 template 中使用,也不用写setup函数,也不用写export default ,甚至是自定义指令也可以在我们的template中自动获得。...

在 vue3.2 中            ,我们只需在script标签中添加setup            。就可以做到                  ,组件只需引入不用注册      ,属性和方法也不用 return 才能于 template 中使用         ,也不用写setup函数                  ,也不用写export default          ,甚至是自定义指令也可以在我们的template中自动获得                  。

一            、模板语法

1.使用 JavaScript 表达式

我们仅在模板中绑定了一些简单的属性名      。但是 Vue 实际上在所有的数据绑定中都支持完整的 JavaScript 表达式:

{{ number + 1 }} {{ ok ? YES : NO }} {{ message.split().reverse().join() }} <div :id="`list-${id}`"></div>

2.调用函数

可以在绑定的表达式中使用一个组件暴露的方法:

<span :title="toTitleDate(date)"> {{ formatDate(date) }} </span>

3.ref 获取元素

<template> <div id="haha" ref="haha"></div> </template>

得给 ref 指定类型 HTMLElement

setup() { let haha = ref<HTMLElement|null>(null) console.log(haha) return { haha, } }, haha.style.fontSize = 20px

4.reactive 

在模板使用直接 {{obj.name}} 即可

修改直接修改 obj[name] = ‘xxx’

ref 和 reactive的区别:

ref: 用来给基本数据类型绑定响应式数据      ,访问时需要通过 .value 的形式                  , tamplate 会自动解析,不需要 .value

reactive: 用来给 复杂数据类型 绑定响应式数据            ,直接访问即可

<template> <div> <p>{{title}}</p> <h4>{{userInfo}}</h4> </div> </template> <script setup lang="ts"> import { ref, reactive } from "vue"; type Person = { name: string; age: number; gender: string; }; const title = ref<string>("彼时彼刻   ,恰如此时此刻"); const userInfo = reactive<Person>({ name: 树哥, age: 18 }) </script>

5.toRefs

setup() { const user = reactive({ name: 小浪, age: 21, }) let userObj = toRefs(user) return { ...userObj, } }

6.ref 和 reactive的区别?

在功能方面                  ,ref 和 reactive               ,都是可以实现响应式数据!

在语法层面,两个有差异         。ref定义的响应式数据需要用[data].value的方式进行更改数据;reactive定义的数据需要[data].[prpoerty]的方式更改数据                  。

const actTitle: Ref<string> = ref(活动名称); const actData = reactive({ list: [], total: 0, curentPage: 1, pageSize: 10 }); actTitle.value = 活动名称2; actData.total = 100;

但是在应用的层面               ,还是有差异的                  ,通常来说:单个的普通类型的数据   ,我们使用ref来定义响应式         。表单场景中            ,描述一个表单的key:value这种对象的场景                  ,使用reactive;在一些场景下      ,某一个模块的一组数据         ,通常也使用reactive的方式                  ,定义数据      。

那么         ,对象是不是非要使用reactive来定义呢?其实不是的      ,都可以                  ,根据自己的业务场景            ,具体问题具体分析!ref他强调的是一个数据的value的更改   ,reactive强调的是定义的对象的某一个属性的更改                  。

7. 周期函数   onMounted

import { defineComponent, ref, onMounted } from vue; export default defineComponent({ name: Gift, setup() { const counter = ref(0); onMounted(() => { // 处理业务                  ,一般进行数据请求 }) return { counter } } })

8.store使用

import { useStore } from "vuex";

 const store = useStore();

 const storeData = computed(() => store);          // 配合computed               ,获取store的值            。 import { useStore } from "vuex"; import { defineComponent, ref, computed } from vue; export default defineComponent({ name: Gift, setup() { const counter = ref(0); const store = useStore(); const storeData = computed(() => store); // 配合computed,获取store的值   。 return { counter, storeData } } })

9.router的使用

        import { useRouter } from "vue-router";

        const router = useRouter();

        const onClick = () => {

            router.push

({ name: "AddGift" });

        } import { useStore } from "vuex"; import { useRouter } from "vue-router"; import { defineComponent, ref, computed } from vue; export default defineComponent({ name: Gift, setup() { const counter = ref(0); const router = useRouter(); const onClick = () => { router.push({ name: "AddGift" }); } return { counter, onClick } } })

10.关注点分离

关注点分离               ,应该分两层意思:第一层意思就是                  ,Vue3的setup   ,本身就把相关的数据            ,处理逻辑放到一起                  ,这就是一种关注点的聚合      ,更方便我们看业务代码                  。

第二层意思         ,就是当setup变的更大的时候                  ,我们可以在setup内部         ,提取相关的一块业务      ,做到第二层的关注点分离               。

import { useStore } from "vuex"; import { useRouter } from "vue-router"; import { defineComponent, ref, computed } from vue; import useMerchantList from ./merchant.js; export default defineComponent({ name: Gift, setup() { const counter = ref(0); const router = useRouter(); const onClick = () => { router.push({ name: "AddGift" }); } // 在该示例中                  ,我们把获取商家列表的相关业务分离出去。也就是下面的merchant.ts const {merchantList} = useMerchantList(); return { counter, onClick, merchantList } } })

merchant.ts    

import { getMerchantlist } from "@/api/rights/gift"; import { ref, onMounted } from "vue"; export default function useMerchantList(): Record<string, any> { const merchantList = ref([]); const fetchMerchantList = async () => { let res = await getMerchantlist({}); merchantList.value = res.data.child; }; onMounted(fetchMerchantList); return { merchantList }; }

11.interface

使用TS进行业务开发            ,一个核心的思维是   ,先关注数据结构                  ,再根据数据结构进行页面开发               。以前的前端开发模式是               ,先写页面,后关注数据                  。

比如要写一个礼品列表的页面               ,我们可能要定义这么一些interface   。总而言之                  ,我们需要关注的是:页面数据的interface                  、接口返回的数据类型      、接口的入参类型等等            。

// 礼品创建         、编辑                  、列表中的每一项   ,都会是这个数据类型                  。 interface IGiftItem { id: string | number; name: string; desc: string; [key: string]: any; } // 全局相应的类型定义 // 而且一般来说            ,我们不确认                  ,接口返回的类型到底是什么(可能是null         、可能是对象      、也可能是数组)      ,所以使用范型来定义interface interface IRes<T> { code: number; msg: string; data: T } // 接口返回数据类型定义 interface IGiftInfo { list: Array<IGiftItem>; pageNum: number; pageSize: number; total: number; }

在一个常见的接口请求中         ,我们一般使用TS这么定义一个数据请求                  ,数据请求的req类型         ,数据请求的res类型      。

export const getGiftlist = ( params: Record<string, any> ): Promise<IRes<IGiftInfo>> => { return Http.get("/apis/gift/list", params); };

12.支持多个v-model

//父组件 <template> <child v-model="name" v-model:email="email" /> <p>姓名:{{ name }}</p> <p>邮箱:{{ email }}</p> </template> <script lang="ts" setup> import child from ./child.vue import { ref } from vue const name = ref<string>(张三) const email = ref<string>(666@qq.com) </script> // 子组件 <template> <button @click="updateName">更新name</button> <button @click="updateEmail">更新email</button> </template> <script lang="ts" setup> // 定义emit const emits = defineEmits<{ (e: update:modelValue, value: string): void (e: update:email, value: string): void }>() const updateName = () => { emits(update:modelValue, 李四) } const updateEmail = () => { emits(update:email, 123456@qq.com) } </script>

如果v-model没有使用参数      ,则其默认值为modelValue                  ,如上面的第一个v-model            ,注意此时不再是像Vue2那样使用$emit(input)了   ,而是统一使用update:xxx的方式         。

13.watch   

watch(data,()=>{},{})

参数一                  ,监听的数据

参数二               ,数据改变时触发的回调函数(newVal,oldVal)

参数三,options配置项               ,为一个对象

1                  、监听ref定义的一个响应式数据

<script setup lang="ts"> import { ref, watch } from "vue"; const str = ref(彼时彼刻) //3s后改变str的值 setTimeout(() => { str.value = 恰如此时此刻 }, 3000) watch(str, (newV, oldV) => { console.log(newV, oldV) //恰如此时此刻 彼时彼刻 }) </script>

2            、监听多个ref

这时候写法变为数组形式

<script setup lang="ts"> import { ref, watch } from "vue"; let name = ref(树哥) let age = ref(18) //3s后改变值 setTimeout(() => { name.value = 我叫树哥 age.value = 19 }, 3000) watch([name, age], (newV, oldV) => { console.log(newV, oldV) // [我叫树哥, 19] [树哥, 18] }) </script>

3   、监听Reactive定义的响应式对象

<script setup lang="ts"> import { reactive, watch } from "vue"; let info = reactive({ name: 树哥, age: 18 }) //3s后改变值 setTimeout(() => { info.age = 19 }, 3000) watch(info, (newV, oldV) => { console.log(newV, oldV) }) </script>

4                  、监听reactive 定义响应式对象的单一属性

<script setup lang="ts"> import { reactive, watch } from "vue"; let info = reactive({ name: 树哥, age: 18 }) //3s后改变值 setTimeout(() => { info.age = 19 }, 3000) watch(()=>info.age, (newV, oldV) => { console.log(newV, oldV) // 19 18 } </script>

停止监听

当 watchEffect 在组件的 setup() 函数或生命周期钩子被调用时                  ,侦听器会被链接到该组件的生命周期   ,并在组件卸载时自动停止                  。

但是我们采用异步的方式创建了一个监听器            ,这个时候监听器没有与当前组件绑定                  ,所以即使组件销毁了      ,监听器依然存在         。

这个时候我们可以显式调用停止监听

<script setup lang="ts"> import { watchEffect } from vue // 它会自动停止 watchEffect(() => {}) // ...这个则不会! setTimeout(() => { watchEffect(() => {}) }, 100) const stop = watchEffect(() => { /* ... */ }) // 显式调用 stop() </script>

(以下一样)

不同数据类型的监听

  基础数据类型的监听:

const name = ref<string>(张三)

watch(name, (newValue, oldValue

) => {

  console.log(watch===, newValue, oldValue)

})

复杂数据类型的监听:

interface UserInfo 

{

  name: string

  age: number

}

const userInfo = reactive<UserInfo

>({

  name: 张三,

  age: 10

})

// 监听整个对象

watch(userInfo, (newValue, oldValue) =>

 {

  console.log(watch userInfo, newValue, oldValue)

})

// 监听某个属性

watch(() => userInfo.name,  (newValue, oldValue) => 

{

  console.log(watch name, newValue, oldValue)

})

支持监听多个源

const name = ref(张三)

const userInfo = reactive({

  age: 18

})

// 同时监听name和userInfo的age属性

watch([name, () => userInfo.age]

([newName, newAge], [oldName, oldAge]) => {

  // 

})

14.watch和watchEffect区别:

1               、watch是惰性执行         ,也就是只有监听的值发生变化的时候才会执行                  ,但是watchEffect不同         ,每次代码加载watchEffect都会执行(忽略watch第三个参数的配置      ,如果修改配置项也可以实现立即执行)

2、watch需要传递监听的对象                  ,watchEffect不需要

3               、watch只能监听响应式数据:ref定义的属性和reactive定义的对象            ,如果直接监听reactive定义对象中的属性是不允许的   ,除非使用函数转换一下

4                  、watchEffect如果监听reactive定义的对象是不起作用的                  ,只能监听对象中的属性      。

15.computed

<template> <div> <p>{{title}}</p> <h4>{{userInfo}}</h4> <h1>{{add}}</h1> </div> </template> <script setup lang="ts"> import { ref, reactive,computed } from "vue"; const count = ref(0) // 推导得到的类型:ComputedRef<number> const add = computed(() => count.value +1) </script>

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
python for语句怎么用(python for语句的应用场景) 建设一个网站的规划(从零开始构建你的在线空间)