赞
踩
在 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: 用来给基本数据类型绑定响应式数据,访问时需要通过 .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<string>('张三')
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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。