当前位置:   article > 正文

vue3 + ts_vue3+ts

vue3+ts

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

一、模板语法

1.使用 JavaScript 表达式

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

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

2.调用函数

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

  1. <span :title="toTitleDate(date)">
  2. {{ formatDate(date) }}
  3. </span>

3.ref 获取元素

  1. <template>
  2. <div id="haha" ref="haha"></div>
  3. </template>

得给 ref 指定类型 HTMLElement

  1. setup() {
  2. let haha = ref<HTMLElement|null>(null)
  3. console.log(haha)
  4. return {
  5. haha,
  6. }
  7. },
haha.style.fontSize = '20px'

4.reactive 

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

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

ref 和 reactive的区别:

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

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

  1. <template>
  2. <div>
  3. <p>{{title}}</p>
  4. <h4>{{userInfo}}</h4>
  5. </div>
  6. </template>
  7. <script setup lang="ts">
  8. import { ref, reactive } from "vue";
  9. type Person = {
  10. name: string;
  11. age: number;
  12. gender: string;
  13. };
  14. const title = ref<string>("彼时彼刻,恰如此时此刻");
  15. const userInfo = reactive<Person>({
  16. name: '树哥',
  17. age: 18
  18. })
  19. </script>

5.toRefs

  1. setup() {
  2. const user = reactive({
  3. name: '小浪',
  4. age: 21,
  5. })
  6. let userObj = toRefs(user)
  7. return {
  8. ...userObj,
  9. }
  10. }

6.ref 和 reactive的区别?

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

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

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

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

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

7. 周期函数   onMounted

  1. import { defineComponent, ref, onMounted } from 'vue';
  2. export default defineComponent({
  3. name: 'Gift',
  4. setup() {
  5. const counter = ref(0);
  6. onMounted(() => {
  7. // 处理业务,一般进行数据请求
  8. })
  9. return {
  10. counter
  11. }
  12. }
  13. })

8.store使用

import { useStore } from "vuex";

 const store = useStore();
 const storeData = computed(() => store);          // 配合computed,获取store的值。

  1. import { useStore } from "vuex";
  2. import { defineComponent, ref, computed } from 'vue';
  3. export default defineComponent({
  4. name: 'Gift',
  5. setup() {
  6. const counter = ref(0);
  7. const store = useStore();
  8. const storeData = computed(() => store); // 配合computed,获取store的值。
  9. return {
  10. counter,
  11. storeData
  12. }
  13. }
  14. })

9.router的使用

        import { useRouter } from "vue-router";

        const router = useRouter();
        const onClick = () => {
            router.push({ name: "AddGift" });
        }

  1. import { useStore } from "vuex";
  2. import { useRouter } from "vue-router";
  3. import { defineComponent, ref, computed } from 'vue';
  4. export default defineComponent({
  5. name: 'Gift',
  6. setup() {
  7. const counter = ref(0);
  8. const router = useRouter();
  9. const onClick = () => {
  10. router.push({ name: "AddGift" });
  11. }
  12. return {
  13. counter,
  14. onClick
  15. }
  16. }
  17. })

10.关注点分离

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

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

  1. import { useStore } from "vuex";
  2. import { useRouter } from "vue-router";
  3. import { defineComponent, ref, computed } from 'vue';
  4. import useMerchantList from './merchant.js';
  5. export default defineComponent({
  6. name: 'Gift',
  7. setup() {
  8. const counter = ref(0);
  9. const router = useRouter();
  10. const onClick = () => {
  11. router.push({ name: "AddGift" });
  12. }
  13. // 在该示例中,我们把获取商家列表的相关业务分离出去。也就是下面的merchant.ts
  14. const {merchantList} = useMerchantList();
  15. return {
  16. counter,
  17. onClick,
  18. merchantList
  19. }
  20. }
  21. })

merchant.ts    

  1. import { getMerchantlist } from "@/api/rights/gift";
  2. import { ref, onMounted } from "vue";
  3. export default function useMerchantList(): Record<string, any> {
  4. const merchantList = ref([]);
  5. const fetchMerchantList = async () => {
  6. let res = await getMerchantlist({});
  7. merchantList.value = res.data.child;
  8. };
  9. onMounted(fetchMerchantList);
  10. return {
  11. merchantList
  12. };
  13. }

11.interface

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

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

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

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

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

12.支持多个v-model

  1. //父组件
  2. <template>
  3. <child v-model="name" v-model:email="email" />
  4. <p>姓名:{{ name }}</p>
  5. <p>邮箱:{{ email }}</p>
  6. </template>
  7. <script lang="ts" setup>
  8. import child from './child.vue'
  9. import { ref } from 'vue'
  10. const name = ref<string>('张三')
  11. const email = ref<string>('666@qq.com')
  12. </script>
  1. // 子组件
  2. <template>
  3. <button @click="updateName">更新name</button>
  4. <button @click="updateEmail">更新email</button>
  5. </template>
  6. <script lang="ts" setup>
  7. // 定义emit
  8. const emits = defineEmits<{
  9. (e: 'update:modelValue', value: string): void
  10. (e: 'update:email', value: string): void
  11. }>()
  12. const updateName = () => {
  13. emits('update:modelValue', '李四')
  14. }
  15. const updateEmail = () => {
  16. emits('update:email', '123456@qq.com')
  17. }
  18. </script>

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

13.watch   

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

  • 参数一,监听的数据

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

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

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

  1. <script setup lang="ts">
  2. import { ref, watch } from "vue";
  3. const str = ref('彼时彼刻')
  4. //3s后改变str的值
  5. setTimeout(() => { str.value = '恰如此时此刻' }, 3000)
  6. watch(str, (newV, oldV) => {
  7. console.log(newV, oldV) //恰如此时此刻 彼时彼刻
  8. })
  9. </script>
  • 2、监听多个ref

这时候写法变为数组形式

  1. <script setup lang="ts">
  2. import { ref, watch } from "vue";
  3. let name = ref('树哥')
  4. let age = ref(18)
  5. //3s后改变值
  6. setTimeout(() => {
  7. name.value = '我叫树哥'
  8. age.value = 19
  9. }, 3000)
  10. watch([name, age], (newV, oldV) => {
  11. console.log(newV, oldV) // ['我叫树哥', 19] ['树哥', 18]
  12. })
  13. </script>
  • 3、监听Reactive定义的响应式对象

  1. <script setup lang="ts">
  2. import { reactive, watch } from "vue";
  3. let info = reactive({
  4. name: '树哥',
  5. age: 18
  6. })
  7. //3s后改变值
  8. setTimeout(() => {
  9. info.age = 19
  10. }, 3000)
  11. watch(info, (newV, oldV) => {
  12. console.log(newV, oldV)
  13. })
  14. </script>
  • 4、监听reactive 定义响应式对象的单一属性

    1. <script setup lang="ts">
    2. import { reactive, watch } from "vue";
    3. let info = reactive({
    4. name: '树哥',
    5. age: 18
    6. })
    7. //3s后改变值
    8. setTimeout(() => {
    9. info.age = 19
    10. }, 3000)
    11. watch(()=>info.age, (newV, oldV) => {
    12. console.log(newV, oldV) // 19 18
    13. }
    14. </script>

  • 停止监听

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

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

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

  1. <script setup lang="ts">
  2. import { watchEffect } from 'vue'
  3. // 它会自动停止
  4. watchEffect(() => {})
  5. // ...这个则不会!
  6. setTimeout(() => {
  7. watchEffect(() => {})
  8. }, 100)
  9. const stop = watchEffect(() => {
  10. /* ... */
  11. })
  12. // 显式调用
  13. stop()
  14. </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<string>('张三')
const userInfo = reactive({
  age: 18
})

// 同时监听name和userInfo的age属性
watch([name, () => userInfo.age]([newName, newAge], [oldName, oldAge]) => {
  // 
})

14.watchwatchEffect区别:

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

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

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

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

15.computed

  1. <template>
  2. <div>
  3. <p>{{title}}</p>
  4. <h4>{{userInfo}}</h4>
  5. <h1>{{add}}</h1>
  6. </div>
  7. </template>
  8. <script setup lang="ts">
  9. import { ref, reactive,computed } from "vue";
  10. const count = ref(0)
  11. // 推导得到的类型:ComputedRef<number>
  12. const add = computed(() => count.value +1)
  13. </script>

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号