vue3上手-常用的组合API

vue3中常用的Compositon API

setup

1》所有的组合API函数都在这里使用,只在初始化的时候执行一次;

2》函数如果返回对象,对象中的属性和方法,模板中可以直接使用

基本语法结构

  setup(props,{attrs,slots,emit}){
      return {}
  }

setup的执行时机

在beforeCreate之前执行一次

由于在beforeCreate之前执行,所以this为undefined,也就不能通过this来访问data method computed prop

所有的composition API都不可以

setup的返回值

一般都返回一个对象

setup对象中的属性和data返回的对象中的属性都可以在html模板中使用,会合并为组件对象的属性

setup对象中的方法和method中的方法会合并为组件对象的方法

在Vue3中尽量不要混合使用data和setup,methods和setup;如果有重名,setup优先

setup不能是一个async函数,因为返回值不再是return的对象,二是promise对象了

在mounted等原来vue就有的钩子函数,方法等里面,是可以通过this来访问setup中的属性,调用里面的方法,而且不需要通过value来获取;但是在setup内部方法访问内部属性,需要通过value来获取

setup的参数

1>props:是一个对象,里面有父组件向子组件传递的数据,并且是在子组件中使用props接收到的所有属性

2>context:是一个对象,里面有attrs对象 ,emit方法,slots对象

2.1>attars:获取当前对象组件标签上的所有属性,但是这些属性是在props中没有声明接收的

2.2>emit方法:用来定义和分发事件,相当于this.$emit

2.3>slots对象:插槽

ref

作用1:定义一个简单数据(基本数据)类型的响应式;其实也可以定义复杂数据,只不过使用起来没那么方便

const name=ref(value)

返回一个ref对象,如果是在js中则需要通过操作ref对象的value值来操作这个变量,如果是html中则不需要

作用2:获取元素

<template>
  <div ref="refBox">ref获取页面元素</div>
</template>

<script lang="ts">
import { defineComponent, ref, onMounted } from "vue";
export default defineComponent({
  setup() {
    const refBox = ref<HTMLElement | null>(null);
    onMounted(() => {
      refBox.value && (refBox.value.style.color = "red");
    });
    return {
      refBox,
    };
  },
});
</script>

reactive

定义复杂数据类型(引用型)的响应式

const proxy=reactive(obj)

响应式是”深层的“,内部是通过ES6的Proxy实现的

ref和reactive简单使用实例:

<template>
  <h4>setup以及ref,reactive的基本使用</h4>
  <div>{{ count }}</div>
  <button @click="updateCount">修改count</button>
  <hr />
  <div>性名:{{ proxyObj.name }}</div>
  <div>女友:{{ proxyObj.girlfriend.name }}</div>
  <button @click="modifyObj">修改对象信息</button>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from "vue";
export default defineComponent({
  name: "App",
  setup() {
    // ------ref定义响应式数据(简单类型)--------
    //let count = 0; // 此时变量count不是响应式的(响应式:数据改变,视图跟着改变)
    // ref用来定义响应式数据的函数,返回一个Ref对象,对象中有value属性;如果需要对数据进行操作,需要使用Ref对象调用value属性的方式修改,但是html模板中是不需要调用value的方式进行数据的读写,渲染
    let count = ref(0);
    function updateCount() {
      // count++;使用了ref后count就是一个响应式的数据了,但是它返回的是一个Ref对象,通过这个对象的value属性来读取和修改
      count.value++;
    }

    // -----reactive定义响应式数据(复杂类型)---------
    let obj = {
      name: "郝建",
      age: 24,
      girlfriend: {
        name: "小甜甜",
        age: 23,
      },
    };
    // proxyObj:代理对象,是一个Proxy对象;obj:目标对象
    // reactive返回的是一个Proxy对象,被代理的是obj对象,也叫做目标对象
    const proxyObj = reactive(obj);
    function modifyObj() {
      // 如果操作目标对象obj来修改值,那就不是响应式了
      proxyObj.name = "luca";
      proxyObj.girlfriend.name = "lucy";
    }

    return {
      count,
      updateCount,
      proxyObj,
      modifyObj,
    };
  },
});
</script>

点击后页面会同步变化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bdeZeYtI-1646054589096)(C:\Users\lucas\Desktop\学习\图片\xiangyingshi.jpg)]

如果操作代理对象,目标对象中的数据也会随之变化

所以如果想要在 操作数据的时候,界面也要跟着重新变化,就使用代理对象

ref和reactive对比

ref用来处理基本数据类型,reactive用来处理复杂数据类型(递归深度响应式)

ref其实也可以传入对象或数组,不过内部会自动将其转换为reactive的代理对象,所以对象或数组直接使用reactive就行,ref在setup中获取还需要点value

ref内部通过给value属性添加getter和setter来实现数据劫持,reactive内部通过proxy来实现对对象内部所有数据的劫持,并通过reflect操作对象内部数据

vue3响应式原理

vue2:defineProperty

缺点:给对象或数组添加数据的时候,不是响应式的,需要使用$set来修改

vue3:Proxy和Reflect

      let obj = {
        name: "张三",
        age: 25,
        wife: {
          name: "马冬梅",
          age: 24,
          creatrues: ["funny", "big eyes", "brave"],
        },
      };

      const proxyObj = new Proxy(obj, {
        get(targetObj, prop) {
          return Reflect.get(targetObj, prop);
        },

        // 不仅可以修改属性,还能添加属性
        set(targetObj, prop, val) {
          return Reflect.set(targetObj, prop, val);
        },

        deleteProperty(targetObj, prop) {
          return Reflect.deleteProperty(targetObj, prop);
        },
      });

计算属性computed和监听watch/watchEffect

<template>
  <div>app组件</div>
  <div>请输入姓:<input type="text" v-model="user.firstName" /></div>
  <div>请输入名:<input type="text" v-model="user.lastName" /></div>
  <hr />
  computed计算属性姓名fullName:<input type="text" v-model="fullName" /><br />
  computed计算属性姓名fullName2: <input type="text" v-model="fullName2" /><br />
  watch监听姓名fullName3: <input type="text" v-model="fullName3" /><br />
  watchEffect监听姓名fullName4: <input type="text" v-model="fullName3" />
</template>

<script>
import {
  defineComponent,
  reactive,
  ref,
  computed,
  watch,
  watchEffect,
} from "vue";

export default defineComponent({
  setup() {
    const user = reactive({
      firstName: "东方",
      lastName: "明月",
    });

    // 1>计算属性computed(如果只有一个回调,则是只读)
    const fullName = computed(() => {
      return user.firstName + user.lastName;
    });

    // 2>通过计算属性的大fullName2.修改fullName2,姓和名随之改变(可读可改)
    const fullName2 = computed({
      get() {
        return user.firstName + user.lastName;
      },
      set(val) {
        user.firstName = val.substr(0, 1);
        user.lastName = val.substr(1);
      },
    });

    const fullName3 = ref("");
    // watch,监听姓和名的输入框,修改fullName3
    watch(
      user,
      (newVal) => {
        fullName3.value = newVal.firstName + newVal.lastName;
      },
      { immediate: true, deep: true }
    );

    // watchEffect监听,自带immediate和deep
    const fullName4 = ref("");
    watchEffect(user, () => {
      fullName4.value = user.firstName + user.lastName;
    });

    return {
      user,
      fullName,
      fullName2,
      fullName3,
      fullName4,
    };
  },
});
</script>

computed:接收回调函数;如果只有一个回调,则只读,如果有两回调(get,set),则是可读可改的响应式

watchEffect会默认执行一次(immediate),而且自带deep深度监听

生命周期钩子函数

1》都写在setup里面,切且加了 on ;接收一个回调函数

2》没有了beforeCreated和created;这里的操作可以直接写在setup中

3》beforeDestroy/destroyed变为了beforeUnmounted/unmounted

4》setup中对应的钩子比vue2中写的对应钩子要先执行

自定义hook函数

使用vue3组合API封装的可复用的功能函数;类似于vue2中的mixin

vue组件

<template>
    <h4>x:{{ x }}</h4>
    <h4>y:{{ y }}</h4>
</template>
<script>

import { defineComponent } from "vue";
import clickPositionHook from "././components/hook";

export default defineComponent({
  setup() {
    const { x, y } = clickPositionHook();
    return {
      x,
      y,
    };
  },
});
</script>

hook.js文件

import { ref, onMounted, onBeforeUnmount } from "vue";
export default function () {
  const x = ref(0);
  const y = ref(0);
  function handleClick(e) {
    x.value = e.clientX;
    y.value = e.clientY
  }
  onMounted(() => {
    window.addEventListener("click", handleClick);
  });
  onBeforeUnmount(() => {
    window.removeEventListener("click", handleClick);
  });
  return {
    x,
    y,
  };
}

toRefs

将响应式对象变为一个普通对象 ,但是里面每一个属性都是ref对象,仍然是响应式的

如果直接结构一个响应式对象,那么得到的属性就不具有响应式

使用场景:hook返回的是一个响应式对象,我们想直接结构使用时

<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
// toRefs的使用场景,hook返回一个对象,想直接使用其属性名
function hook() {
  const person = {
    name2: "张三",
    age2: 24,
  };
  setInterval(() => {
    person.name2 += "疯";
  }, 1000);
  return {
    ...toRefs(person),
  };
}

export default defineComponent({
  setup() {
    const user = reactive({
      name: "卢卡",
      age: 20,
    });
    const { name2, age2 } = hook();
    // 方案2:直接结构user;这样也不是响应式
    // let { name, age } = user;
    // 方案3:使用 toRefs
    let { name, age } = toRefs(user);
    setInterval(() => {
      // 方案1 return 的时候,对user结构赋值
      // user.name += "=";
      // console.log(user.name);
      // 方案 2:不是响应式
      // name += "=";
      // console.log(name);
      // 方案3:使用 toRefs
      name.value += "=";
    }, 2000);
    return {
      //  ...user,  方案1,出来的时候结构赋值,但是这样结构出来的就不是响应式的数据了
      name,
      age,
      name2,
      age2,
    };
  },
});
</script>

() => {
// 方案1 return 的时候,对user结构赋值
// user.name += “=”;
// console.log(user.name);
// 方案 2:不是响应式
// name += “=”;
// console.log(name);
// 方案3:使用 toRefs
name.value += “=”;
}, 2000);
return {
// …user, 方案1,出来的时候结构赋值,但是这样结构出来的就不是响应式的数据了
name,
age,
name2,
age2,
};
},
});


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值