Setup
执行时间是 beforeCreate 之前之前,且是自动执行
setuup 代码特点:
定义数据 + 函数 最后以对象方式 return 出去
<script>
export default {
setup() {
//数据
const messag = "ggg";
//函数
const logmessage = () => {
console.log(messag);
};
//若想要在模板中用到该数据或者函数,必须以对象形式 return 出现
return {
messag,
logmessage,
};
},
};
</script>
<template>
<div>
{{ messag }}
<button @click="logmessage">点我看看?</button>
</div>
</template>
在setup中的this不再是指向组件实例,指向的是undefined
而如果有大量数据,岂不是要定义一个,在return一次,这里可以用到语法糖 <script setup> 非常方便!
经过语法糖的封装可以更简单的使用组合式api
<script setup>
//数据
const messag = "ggg";
//函数
const logmessage = () => {
console.log(messag);
};
</script>
组合式API中与响应有关的函数:reactive 和 ref
类似于vue2中的data 都是用来生成相应数据
reactive
作用:接受对象类型数据的参数传入并返回一个响应式的对象
<script setup>
//导入
import { reactive } from "vue";
//执行函数 传入参数 变量接收
const state = reactive(对象数据类型);
</script>
例子:
<script setup>
//导入
import { reactive } from "vue";
//执行函数 传入参数 变量接收
const state = reactive({
count: 0,
});
const addCount = () => {
state.count++;
console.log(state.count);
};
</script>
<template>
<div>
<button @click="addCount">点击 count +1</button>
</div>
</template>
那么可以知道 reactive 针对的是对象类型的参数,而对于其他类型的参数,我们可以用到 ref
Ref
作用:接收简单类型或者对象类型的数据传入并返回一个响应式的对象
<script setup>
//导入
import { ref } from "vue";
//执行函数 传入参数 变量接收
const state = ref(简单类型或者是复杂类型数据);
</script>
例子
<script setup>
//导入
import { ref } from "vue";
//执行函数 传入参数 变量接收
const count = ref(888);
const delCount = () => {
//若在脚本区域修改有ref产生的响应式对象数据,必须通过 .value 属性
count.value--;
console.log(count.value);
};
</script>
<template>
<div>
<button @click="delCount">点击 count +1</button>
</div>
<!-- 在模板中如果想用该数据 直接用这个变量即可 -->
<input type="text" v-model="count" />
</template>
注意:
若在脚本区域修改有ref产生的响应式对象数据,必须通过 .value 属性
在模板中如果想用该数据 直接用这个变量即可
我们在脚本中直接打印 count 👇
组合式 API-computed 计算属性函数
计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法
//导入
import { computed } from "vue";
// 执行函数 变量接收 在回调参数中return计算值
const computedState = computed(() => {
return 基于响应式数据做计算之后的值;
});
</script>
例子:
<script setup>
//导入
import { ref } from "vue";
//执行函数 传入参数 变量接收
const arr = ref([1, 2, 3, 4, 5, 6, 7, 8]);
//导入
import { computed } from "vue";
// 执行函数 变量接收 在回调参数中return计算值
const computedArr = computed(() => {
return arr.value.filter((item) => item > 3);
});
console.log(arr.value);
setTimeout(() => {
arr.value.push(100);
}, 2000);
</script>
<template>
<div>原始数组:{{ arr }}</div>
<div>去除3以下的数组: {{ computedArr }}</div>
</template>
2秒后:
注意:
计算属性应该是只读的,不应该去直接修改属性的值
API watch函数
作用: 侦听一个或者多个数据的变化,数据变化时执行回调函数
俩个额外参数: 1. immediate (立即执行) 2. deep (深度侦听)
基础使用 - 侦听单个数据
1.导入watch函数
2.执行watch函数传入要侦听的响应式数据(ref对象)和回调函数
<script setup>
//导入
import { watch, ref } from "vue";
const count = ref(888);
watch(count, (newVal, oldVal) => {
//newVal 为变化后的新数据,oldVal 为旧数据
});
</script>
例子:
<script setup>
//导入
import { watch, ref } from "vue";
const count = ref(0);
const addCount = () => {
count.value++;
};
// 注意这里的 count 是不需要加 .vaule 属性的
watch(count, (newVal, oldVal) => {
console.log("新数据" + newVal);
console.log("老数据" + oldVal);
});
</script>
<template>
<div>
<button @click="addCount">+1</button>
</div>
</template>
基础使用 - 侦听多个数据
说明:同时侦听多个响应式数据的变化,不管哪个数据变化都需要执行回调
<script setup>
//导入
import { watch, ref } from "vue";
const count = ref(0);
const str = ref("agg");
const addCount = () => {
count.value++;
};
const changeStr = () => {
str.value = "bgg";
};
// 注意这里的 count 是不需要加 .vaule 属性的
watch([count, str], ([newCount, newStr], [oldCount, oldStr]) => {
console.log("新的数据" + [newCount, newStr]);
console.log("旧的数据" + [oldCount, oldStr]);
});
</script>
<template>
<div>
<button @click="addCount">+1</button>
</div>
<div>
<button @click="changeStr">改变字符</button>
</div>
</template>
immediate
说明:在侦听器创建时立即触发回调,响应式数据变化之后继续执行回调
watch(
count,
() => {
console.log(count.val);
},
{
immediate: true,
}
);
deep
默认机制:通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep选项。
<script setup>
//导入
import { watch, ref } from "vue";
const count = ref({ num: 0 });
const addCount = () => {
//直接修改属性 -> 不会触发回调
count.value.num++;
};
watch(count, () => {
console.log("变化");
});
</script>
开启 deep 后
<script setup>
//导入
import { watch, ref } from "vue";
const count = ref({ num: 0 });
const addCount = () => {
//直接修改属性 -> 不会触发回调
count.value.num++;
};
watch(
count,
() => {
console.log("变化");
},
{
deep: true,
}
);
</script>
<template>
<div>
<button @click="addCount">+1</button>
</div>
</template>
注意:当count 修改如下,当sum值修改也会触发 监听造成浪费。所提实操中最好尽量不开启deep,这样容易造成性能损耗
const count = ref({ num: 0, sum: 100 });
精确侦听对象的某个属性
需求:在不开启deep的前提下,侦听sum的变化,只有sum变化时才执行回调
可以把第一个参数写成函数的写法,返回要监听的具体属性
<script setup>
//导入
import { watch, ref } from "vue";
const count = ref({ num: 0, sum: 100 });
const addNum = () => {
count.value.num++;
};
const addSum = () => {
count.value.sum++;
};
watch(
() => count.value.sum,
() => {
console.log("sun变化");
}
);
</script>
<template>
<div>
<button @click="addCount">num+1</button>
</div>
<div>
<button @click="addSum">sum+1</button>
</div>
</template>
点击num不响应,点击sum控制台有响应
生命周期函数
生命周期函数是可以执行多次的,多次执行时传入的回调会在时机成熟时依次执行
组合式API 父传子
基本思想
1.父组件中给子组件绑定属性
2.子组件内部通过props选项接收
defineProps({属性名: 类型})
例子:
结果:
如果传过来的是响应式数据
啥是 defineProps "编译器宏”
类似于 vue2 的申明方式
组合式API 子传父
基本思想
1.父组件中给子组件标签通过@绑定事件
2.子组件内部通过 $emit 方法触发事件
defineEmits(['事件名称'])
例子
组合式API 模板引用
通过ref标识获取真实的dom对象或者组件实例对象
<script setup>
//1.调用 ref 函数得到 ref 对象
const h1Ref = ref(null);
</script>
<template>
<!-- 2. 通过 ref 标识绑定 ref 对象 -->
<h1 ref="h1Ref">我是H1</h1>
</template>
例子 (获取模板引用的时机是 组件挂在完毕)
<script setup>
import { onMounted, ref } from "vue";
import sonCom from "./son-com.vue";
//1.调用 ref 函数得到 ref 对象
const h1Ref = ref(null);
const comRef = ref(null);
onMounted(() => {
console.log(h1Ref.value);
console.log(comRef.value);
});
</script>
<template>
<!-- 2. 通过 ref 标识绑定 ref 对象 -->
<h1 ref="h1Ref">我是H1</h1>
<sonCom ref="comRef" />
</template>
defineExpose()
默认情况下在<script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose编译宏指定哪些属性和方法允许访问
作用:显示暴露组件内部的属性和方法
新增蓝框内容
请注意观察红框变化
什么是pinia
Pinia 是 Vue的专属的最新状态管理库,是 Vuex 状态管理工具的替代品
优势:
- 提供更加简单的API(去掉了 mutation,之前的 Vuex 里面既有 mutation 又有 action )
- 提供符合组合式风格的API (和 Vue3新语法统一)
- 去掉了 modules 的概念,每一个 store 都是一个独立的模块4.搭配TypeScript 一起使用提供可靠的类型推断
import { createApp } from 'vue'
import App from './App.vue'
//1. 导入 createPinia
import { createPinia } from 'pinia'
//2. 执行方法,得到实例
const pinia = createPinia();
//3. 把 Pinia 实例加到 app 应用中
createApp(App).use(pinia).mount('#app')
如何定义 store 并且使用?
定义store
组件使用store
例子
getters实现
Pinia中的 getters 直接使用 computed函数 进行模拟
action如何实现异步
action中实现异步和组件中定义数据和方法的风格完全一致
storeToRefs
使用storeToRefs函数可以辅助保持数据(state + getter)的响应式解构
如果我们直接用解构赋值的方法去得到该数据,是不行的,响应式丢失
const { count, doubleCount } = counterStore;
用 storeToRefs 即可! 保持响应式
import { storeToRefs } from "pinia";
const { count, doubleCount } = storeToRefs(counterStore);
打印两值式响应式对象
以上是对于数据相关的处理,而对于方法呢 可以直接从原本的 counterStore 中解构赋值
const { addCount } = counterStore;