vue3学习之路-01

91 阅读4分钟

Vue3的组合式api

setup函数

composition api 的使用,需要配置一个setup函数

  1. 从生命周期角度来看,setup会在beforeCreate钩子函数之前执行
  2. setup中不能使用this,this指向 undefined
  3. 在模板中需要使用的数据和函数,需要在setup返回
  4. setup函数是一个新的组件选项,作为组件中compositionAPI的起点
<script>
export default {
  beforeCreate() {
    console.log(4,'beforeCreate');
  },

  setup() {
    console.log(4, this);
    console.log(9,'setup');
    const obj = {
      name: "王五",
      age: 18,
    };

    return {
      obj: obj,
    };
  },
};
</script>

<template>
  <h1>
    {{ obj.age }}
  </h1>
</template>

image-20230519200544828.png

reactive函数

前置说明:

1.setup:需要有返回值,只有返回的值才能在模板中使用

2.默认普通的数据,不是响应式的

作用:传入一个复杂数据类型,将复杂类型数据,转换成响应式数据(返回改对象的响应式代理)

<script>
import { reactive } from "vue";
export default {
  setup() {
    // 1.setup 需要返回值,返回的值才能在模板中使用
    // 2.默认的普通的值不是响应式的,需要用 reactive 函数
    const obj = reactive({
      name: "zs",
      age: 18,
    });

    const addAge = () => {
      obj.age++;
      console.log(obj);
    };
    return { obj, addAge };
  },
};
</script>

<template>
  <h1>
    {{ obj }}
  </h1>
  <button @click="addAge">年龄加一</button>
</template>

总结: 通常是用来定义响应式 对象数据

ref函数

reactive 处理的数据,必须是复杂类型,如果是简单类型无法处理成响应式,所以有ref函数!

作用:对传入的数据(一般简单数据类型),包裹一层对象,转换成响应式.

  1. ref函数接收一个的值,返回一个ref响应式对象,又唯一的属性value
  2. 在setup函数中,通过ref对象的value属性,可以访问到值
  3. 在模板中,ref属性会自动解套,不需要额外的 .value
  4. ref函数也支持传入复杂类型,传入复杂类型,也会做响应式处理
<script>
import { ref } from "vue";
export default {
  setup() {
    const age = ref(9);
    console.log(age);

    const addAge = () => {
      age.value++;
    };
    return { age, addAge };
  },
};
</script>

<template>
  <h1>
    {{ age }}
  </h1>
  <button @click="addAge">年龄加一</button>
</template>

ref和reactive的嘴贱使用方式:

  • 明确的对象,明确的属性,用reactive,其他用ref
  • 从vue3.2之后,更推荐使用ref

script setup 语法

script setup 是在单文件组件(SFC)中使用组合式API的编译时语法糖.相比与普通的script语法更加简洁

要使用这个语法,需要将setup attribute 添到

<script setup>
console.log("hello script setup");
</script>

顶层的绑定会自动暴露给模板,所以定义的变量,函数和import导入的内容都可以直接在模板中直接使用

<template>
  <div>
    {{ age }}
  </div>
  <button @click="addAge">+</button>
</template>
<script setup>
import { ref } from "vue";

const age = ref(0);
const addAge = () => {
  age.value++;
};
</script>

练习

<template>
  <div>
    <h3>鼠标x坐标:{{ mouse.x }}</h3>
    <h3>鼠标y坐标:{{ mouse.y }}</h3>
    <h3>{{ testNum }}</h3>
    <button @click="addbtn">+</button>
  </div>
</template>
<script setup>
import { onMounted, onUnmounted, reactive, ref } from "vue";

const mouse = reactive({
  x: 0,
  y: 0,
});
const handleMouse = (e) => {
  mouse.x = e.clientX;
  mouse.y = e.clientY;
};
onMounted(() => {
  document.addEventListener("mousemove", handleMouse);
});
onUnmounted(() => {
  document.addEventListener("mousemove", handleMouse);
});

const testNum = ref(0);
const addbtn = () => {
  testNum.value++;
};
</script>

计算属性computed函数

computed函数调用时,要接受一个处理函数,处理函数中,需要返回计算属性的值

<template>
  <div>今年年龄: <input type="text" v-model.number="age" /></div>
  <div>明年年龄: <input type="text" v-model.number="newAge" /></div>
  <div>后年年龄: <input type="text" v-model.number="lastAge" /></div>
</template>
<script setup>
import { computed, ref } from "vue";
// 今年年龄
const age = ref(18);
// 不带set的计算属性
const newAge = computed(() => {
  return age.value + 1;
});
// 带set的计算属性
const lastAge = computed({
  get() {
    // console.log(age.value);
    return age.value + 2;
  },
  set(val) {
    // console.log(val);
    age.value = val - 2;
  },
});
</script>

侦听器watch函数

watch监视,接收三个参数
1. 参数1:监视的数据源
2. 参数2:回调函数
3. 参数3:额外的配置
<template>
  <div>
    <h1>{{ money }}</h1>
    <h1>{{ count }}</h1>
    <button @click="money -= 250">花掉520</button>

    <h3>{{ user }}</h3>
    <button @click="user.age += 1">年龄加一</button>

    <button @click="user.name += '芜湖'">变名字</button>
  </div>
</template>

<script setup>
import { reactive, ref, watch } from "vue";

// 监听单个ref
const money = ref(5200);
watch(money, (val, oldVal) => {
  console.log(val, oldVal);
});

// 监听多个ref
// 补充: 参数一可以监听多个参数
const count = ref(0);
watch([money, count], (val, oldVal) => {
  console.log(val, oldVal);
});

// 监听ref复杂数据
const user = reactive({
  name: "zs",
  age: 18,
});
watch(user, () => {
  console.log("user对象发生了变化"),
    {
      deep: true,
      immediate: true,
    };
});

// 监听对象的某一个属性
watch(
  () => {
    return user.name.value;
  },
  () => {
    console.log("名字变了");
  }
);
</script>

组件通讯-父传子

目标:能够实现组件通讯中得父传子组件通讯

步骤:

  1. 父组件提供数据
  2. 父组件将数据传递给子组件
  3. 子组件通过defineProps进行接收
  4. 子组件渲染父组件传递得数据

核心代码

父组件

<template>
  <div>父组件</div>
  <son :money="money" />
</template>

<script setup>
import son from "./components/son.vue";
import { ref } from "vue";

const money = ref(9999);
</script>

子组件

<template>
  <div>子组件</div>
  <div>{{ money }}</div>
</template>

<script setup>
// 简单写法(较少用,类型不明确)   
// defineProps(['money']);
    
// 指定类型普通写法    
defineProps({
  //   money: {
  //     typeof: String, //指定类型
  //     default: 888, //默认值
  //   },
});
console.log(money);
</script>

注意:如果使用defineProps接收数据,这个数据只能在模板中渲染,如果想要在script中也操作props属性,应该接收返回值

const res = defineProps({
  money: String,
});

组件通讯-子传父

目标: 能够实现组件通讯中得子传父

步骤:

  1. 子组件通过defineEmits获取emit对象(setup中没有this)
  2. 子组件通过emit触发事件,并且传递数据
  3. 父组件提供方法
  4. 父组件通过自定义事件得方式给子组件注册事件

核心代码

子组件

<template>
  <div>子组件</div>
  <div>{{ money }}</div>
  <button @click="btn">花钱</button>
</template>

<script setup>
defineProps({
  money: String,
});
// 返回emit对象,用于触发父组件得自定义事件
const emit = defineEmits("changeMoney");

const btn = () => {
  emit("changeMoney", 500);
};
</script>

父组件

<template>
  <div>父组件</div>
  <son :money="money" @changeMoney="changeMoneyFn" />
</template>

<script setup>
import son from "./components/son.vue";
import { ref } from "vue";

const money = ref(9999);

const changeMoneyFn = (val) => {
  money.value -= val;
};
</script>

依赖注入-provied和inject

依赖注入,可以非常方便的实现 跨层级的 组件通信

image-20230606151940234.png

父组件利用provide提供数据

<template>
  <div>父组件</div>
  <son />
</template>

<script setup>
import { provide, ref } from "vue";
import son from "./components/son.vue";

const money = ref(520);
provide("money", money);
</script>

子组件(子孙后代,都可以拿到这个数据)

<template>
  <div>
    {{ money }}
  </div>
</template>

<script setup>
import { inject } from "vue";

const money = inject("money");
console.log(money);
</script>

模板中ref的使用(通过ref获取dom实例)

联想之前的ref和$refs,获取模板的元素(dom元素,组件)

  1. 创建ref=>const divRef = ref (null)
  2. 模板中建立关联 =>
    钩子函数
  3. 使用=>divRef.value
<template>
    <!-- 2.在模板中建立关联,模板挂在完毕后,自动把DOM节点的内存地址给 ref -->
  <div ref="divRef">父组件</div>
  <button @click="btn">操作dom</button>
  <son />
</template>

<script setup>
import { onMounted, ref } from "vue";

// 1.创建空ref
const divRef = ref(null);

// 3.组件挂载完毕后,就能获取DOM节点了
onMounted(() => {
  console.log(13, divRef.value);
});

const btn = () => {
  divRef.value.innerText = "芜湖";
};
</script>

ref获取组件实例

父组件

<template>
  <son ref="sonCom" />
</template>

<script setup>
import { onMounted, ref } from "vue";
import son from "./components/son.vue";
const sonCom = ref(null);
onMounted(() => {
  console.log(12, sonCom.value.money);
  console.log(13, sonCom.value.sayHi);
});
</script>

子组件

<template>
  <div></div>
</template>

<script setup>
import { ref } from "vue";

const money = ref(88);

const sayHi = () => {
  console.log("hello");
};

// 所有的变量或函数都是局部的
// defineExpose 暴露组件内部的数据或方法
defineExpose({
  money,
  sayHi
});
</script>

vue3中废弃了过滤器

vue3.0中不能使用过滤器,直接使用函数进行代替
<template>
  <div>{{ fornmatTime(now) }}</div>
  <div>{{ fornmatTime(other) }}</div>
</template>

<script setup>
import dayjs from "dayjs";
const now = new Date();
const other = new Date("2020-11-12 12:00:00");
console.log(now);

const fornmatTime = (val) => {
  return dayjs(val).format("hh:mm:ss");
};
</script>

补充-toRefs函数

使用场景:如果对各响应式数据,进行解构 或者 展开,会丢失他的响应式特性!

原因:vue3底层是对 对象 进行监听劫持

作用:对一个响应式对象的所有内部属性,都做响应式处理

  1. reactive/ref 的响应式功能是赋值给对象的,如果给对象解构或者展开,会让数据丢失响应式的能力
  2. 使用 torefs 可以保证该对象展开的每个属性都是响应式的
<template>
  <div>{{ user }}</div>
  <div>name:{{ name }}</div>
  <div>age:{{ age }}</div>
  <button @click="user.age++">年龄++</button>
</template>

<script setup>
import { reactive, toRefs } from "vue";

const user = reactive({
  name: "zs",
  age: 18,
});
// console.log(user.name);
const { name, age } = toRefs(user);
</script>