Vue3 核心语法

1. Options API与Composition API

  • Vue2的API设计是Options(配置)风格的。
  • Vue3的API设计是Composition(组合)风格的。
  1. Options API
    Options类型的API,数据、方法、计算属性等,是分散在data、methods、computed中的,若想新增或者修改一个需求,就需要分别修改:data、methods、computed,不便于维护和复用。
    在这里插入图片描述

  2. Composition API
    可以用函数的方式,更加优雅的组织代码,让相关功能的代码更加有序的组织在一起。
    在这里插入图片描述
    说明:图片来源:大帅老猿

2. setup

在这里插入图片描述
未使用setup:

  data() {
        return {
            name: '张三',
            age: 20,
            tel:'110'
        }
    },
    methods: {
        showTel() {
            alert(this.tel)
        },
        changeAge() {
            this.age+=1
        },
        changeName() {
            this.name = 'ZhangSan'
        }
    }

使用setup

setup() {
        // 数据
        let name = "张三";
        let age = 19;
        let tel = "110"

        // 方法
        function changeName() {
            name = 'zhangsan'
        }
        function changeAge() {
            age +=1
        }
        function showTel() {
            alert(tel)
        }
         return {name,age,changeName,changeAge,showTel}
    }

setup返回值:不仅可以返回对象,还可以返回渲染函数…

2.1 setup与options API

  1. setup与options API是可以共存的;
  2. options API是可以读取到setup中的数据的;

2.2 setup语法糖

之前的写法

<script lang="ts">
export default {
    name: 'Person',
    data() {
        return {
            name: this.name,
            age: 20,
            tel:'110'
        }
    },
    methods: {
        showTel() {
            alert(this.tel)
        },
        changeAge() {
            this.age+=1
        },
        changeName() {
            // this.name = 'ZhangSan'
        }
    },
    setup() {
        // setup中this是undefined ,Vue3在弱化this了
        // 数据
        let name = "张三";
        let age = 19;
        let tel = "110" // 此时的name,age,tel都不是响应式数据,也就是页面中数据不能随之改变

        // 方法
        function changeName() {
            name = 'zhangsan'
        }
        function changeAge() {
            age +=1
        }
        function showTel() {
            alert(tel)
        }
        // 将数据交出去才可以在模版中使用
        return {name,age,changeName,changeAge,showTel}
    }
}
</script>

这种写法需要将数据通过return 交出去,不然无法在模板中使用。

setup语法糖写法

<script lang="ts">
export default {
    name: 'Person',
}
</script>

<script lang="ts" setup>
    // setup中this是undefined ,Vue3在弱化this了
    // 数据
    let name = "张三";
    let age = 19;
    let tel = "110" // 此时的name,age,tel都不是响应式数据,也就是页面中数据不能随之改变

    // 方法
    function changeName() {
        name = 'zhangsan'
    }
    function changeAge() {
        age +=1
    }
    function showTel() {
        alert(tel)
    }
</script>

声明:两个 script 标签使用的语言需要统一为ts,不然系统会默认未声明语言的script标签部分使用js语言。

扩展:上述代码,还需要编写一个不写setup的script标签,去指定组件名字,比较麻烦,我们可以借助vite中的插件简化,vite-plugin-vue-setup-extend -D可以省略写暴漏组件的script标签(也就是上面一个script标签)

npm i vite-plugin-vue-setup-extend -D

在这里插入图片描述

<script lang="ts" setup name="Person234">
// 此时的name 值可以与文件名称不一样
    // setup中this是undefined ,Vue3在弱化this了
    // 数据
    let name = "张三";
    let age = 19;
    let tel = "110" // 此时的name,age,tel都不是响应式数据,也就是页面中数据不能随之改变

    // 方法
    function changeName() {
        name = 'zhangsan'
    }
    function changeAge() {
        age +=1
    }
    function showTel() {
        alert(tel)
    }
</script>

3. 创建响应式数据

3.1 ref — 创建基本类型的响应式数据

  • 作用:定义响应式变量。
  • 语法:let xxx=ref(初始值)
  • 返回值:一个RefImpl的实例对象,简称ref对象或ref,ref对象的value属性是响应式的;
  • 注意点:
    • JS中操作数据需要:xxx.value,但模板中不需要.value,直接使用即可。
    • 对于let name=ref('张三')来说,name不是响应式的,name.value是响应式的。

在这里插入图片描述

import {ref} from 'vue'
    let name = ref("张三");
    let age = ref(19); //响应式
    let tel = "110" // 此时的name,age,tel都不是响应式数据,也就是页面中数据不能随之改变

    // 方法
    function changeName() {
        name.value = 'zhangsan'  // 只能通过.value修改name的值
    }
    function changeAge() {
        age.value +=1
    }

3.2 reactive — 创建对象类型的响应式数据

reactive处理的对象是深层次的,也就是obj.a.ab.c.d…这样的数据都是响应式的。

<template>
    <div class="person">
        <h2>名字:{{ car.name }}</h2>
        <h2>价格:{{ car.price }}</h2>
        <button @click="changeName">修改名字</button>
        <hr>
        <ul>
            <li v-for="g in games" :key="g.id">{{ g.name }}</li>
        </ul>
    </div>
</template>

<script lang="ts" setup name="Person">
import {reactive} from 'vue'
let car = reactive({ name: 'byd',price:'200' })
let games = reactive([
    { id:'1',name: '第五人格' },
    { id:'2',name: '宾果消消消' },
    {id:'3',name:'绝地求生'},
])
function changeName() {
    car.name = 'Byd'
}
</script>

在这里插入图片描述
注:
数组数据不必使用map遍历,可以使用v-for

 <li v-for="g in games" :key="g.id">{{ g.name }}</li>

games:数据源;
:key:唯一标识;

3.3 ref — 创建对象类型的响应式数据

在这里插入图片描述

console.log(car);
console.log(games);

在这里插入图片描述
ref创建对象类型的像影视数据其实在.value中放置了一个Proxy对象,获取数据时需要使用.value。

3.4 ref 对比 reactive

宏观对比:

  1. ref用来定义:基本类型数据、对象类型数据:
  2. reactive用来定义:对象类型数据。

区别:

  1. ref创建的变量必须使用.value(可以使用volar插件自动添加.value)。
  2. reactive重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)。
let car = reactive({ name: 'byd', price: '200' })
let person = ref({ name:'xiaoming'})
function changeName() {
    // car = reactive({name:'小鸟',price:2000})
    // car = {name:'小鸟',price:2000}   // 这两种方式都无法改变页面中的数据
    Object.assign(car, { name: '小鸟', price: 2000 }) // 修改reactive创建的数据需要使用obj.assign()
    person.value.name='hh' 
    person = ref({name='hh'}) // 无法改变数据
}

使用原则:

  1. 若需要一个基本类型的响应式数据,必须使用ref
  2. 若需要一个响应式对象,层级不深,refreactive都可以。
  3. 若需要一个响应式对象,且层级较深,推荐使用reactive

在这里插入图片描述

在这里插入图片描述

5. toRefs / toRef

( 1 ) toRefs

<template>
    <div class="test">
        <h1>Hello,World!</h1>
        <h2>名字:{{ person.name }}</h2>
        <h2>年龄:{{ person.age }}</h2>
        <button @click="changeName">修改姓名</button>
        <button @click="changeAge">修改年龄</button>
    </div>
</template>

<script lang="ts" setup name="Test">
import { reactive, toRefs } from 'vue'

let person = reactive({ name: 'zhangsan', age: 40 })

let { name, age } = person

function changeName() {
    name = 'lisi'
}

function changeAge() {
    age-=1
}
</script>

对person 数据进行解构赋值,这样的数据并不是响应式数据,并不能改变页面中的数据。

使用toRefs

let { name, age } = toRefs(person)
console.log(name,age);

在这里插入图片描述

toRefs 会将person对象的每一对键值对都转换成ref 形式的响应式数据。

( 2 ) toRef

let nl = toRef(person, 'age')
console.log(nl);

在这里插入图片描述
toRef 可以将person对象的某个属性转换为ref形式,其中nl 改变,那person.age 也会改变。

6. computed 计算属性

<input type="text" value="xxx">

v-bind :单项绑定 — 数据流向页面;
简写:

:value=“…”

v-model — 双向绑定 — 数据在页面和
简写:

v-model=“…”

在这里插入图片描述

let firstName = 'zhang'
let lastName = 'san'

let fullName = computed(() => {
    return firstName + lastName
})

这样使用computed 属性,fullName只是一个只读的计算属性;因为fullName只有只读属性,修改时只能通过修改firstName和lastName进行修改。

let fullName = computed({
    get() {
       return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + ' ' + lastName.value
    }, 
    set(val) {
        const [str1, str2] = val.split(' ')
        firstName.value = str1
        lastName.value = str2
    }
})

7. watch 监视

( 1 ) 五种情况

  • 作用:监视数据的变化(和Vue2中的watch作用一致)
  • 特点:Vue3中的watch只能监视以下四种数据:
  1. ref 定义的数据
  2. reactive 定义的数据。
  3. 函数返回一个值(getter())。
  4. 一个包含上述内容的数组
  1. 监视ref定义的基本类型数据
    监视ref定义的【基本类型】数据:直接写数据名即可,监视的是其value值的改变
let sum = ref(0)
function changesum() {
    sum.value += 1
}

const stopWatch = watch(sum, (newValue,oldValue) => {
    console.log(newValue, oldValue);
    if(newValue > 10){
        stopWatch()
    }
})

在这里插入图片描述

  1. 监视ref定义的对象类型数据
    监视ref 定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。

deep: true

watch(person1, (newValue,oldValue) => {
    console.log(newValue,oldValue);
}, { deep: true,immediate:true })

进行输出源数据、改变person1的name,age属性、修改person1对象操作的结果:
在这里插入图片描述

注意:

  • 若修改的是ref 定义的对象中的属性,newValue和oldValue都是新值,因为它们是同一个对象。
  • 若修改整个ref 定义的对象,newValue是新值,oldValue是旧值,因为不是同一个对象了。

在这里插入图片描述
watch的配置对象:

  • deep: true
  • immediate: true
  1. 监视reactive定义的对象类型数据
    监视【reactive】定义的【对象类型】数据,默认是开启深度监视的

  2. 监视ref 或reactive 定义的对象类型数据中的某个属性
    注意点如下:

  • 若该属性值不是【对象类型】,需要写成函数形式(一般说的是getter())。
  • 若该属性值是依然是【对象类型】,可直接编,也可写成函数,不过建议写成函数。
  • 结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。
watch(() => person.name, (newValue,oldValue) => {
    console.log(newValue,oldValue);
})

在这里插入图片描述

  1. 监视上述的多个数据
// 监视上述类型的多个属性
watch([() => person1.value.name, () => car.price], (newValue, oldValue) => {
    console.log('监视上述类型的多个属性',newValue, oldValue);
})

( 2 ) watchEffect

  • 官网:立即运行一个函数,同时响应式追踪其依赖并在依赖更改时重新执行该函数。
  • watch对比watchEffect
  1. 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
  2. watch: 要明确指出监视的数据
  3. watchEffect: 不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)。
watchEffect(() => {
    if (person1.value.age <= 15) {
        console.log('发送请求');
    }
})

8. 标签的ref 属性

  • 作用:用于注册模板引用。
    • 用在普通DOM标签上,获取的是DOM节点。
    • 用在组件标签上,获取的是组件实例对象。

用在普通DOM标签上:
在不同文件中有相同标签设置了相同的id 会出现只能获取第一个符合条件的标签;但是使用ref 时,不同文件只能获取到自身的相应标签。

例:APP.vue 和Test.vue同时设置以下标签

<template>
 <h2 ref="title">Test</h2>
        <button @click="logInfo">测试2</button>
</template>
<script>
let title = ref()
function logInfo() {
    console.log(title.value);
}
</script>

在这里插入图片描述

用在组件标签上:

<Test ref="test"/>
<button @click="logcomp">测试2</button>

此时的test.value是Test组件的一个实例对象,但是看不到其中的数据,需要通过difineExpose到导出
在这里插入图片描述

let a = ref(0)
let b = ref(1)
let c = ref(2)
defineExpose({a,b,c})

在这里插入图片描述

9. TS 中的_接口_泛型_自定义类型_

personInter 接口:

export interface personInter {
    name: string,
    age:number
}
  1. 定义某个对象符合personInter 接口规范
    @表示根目录src
import type { personInter } from '@/types'
let person:personInter = { name: 'zhangsan', age: 40 }
  1. 定义一个数组中每个对象都符合personInter 接口规范
    第一种方法 ---- 使用泛型
let persons:Array<personInter> = [
    { name: 'zhangsan', age: 40 },
    { name: 'lisi', age: 20 },
    { name: 'wamgwu', age: 30 }
]

第二种方法 ---- 自定义类型

export type Persons = Array<personInter>
let persons:Persons = [
    { name: 'zhangsan', age: 40 },
    { name: 'lisi', age: 20 },
    { name: 'wamgwu', age: 30 }
]

响应式数据优雅写法:

let persons = reactive<Persons>([
    { name: 'zhangsan', age: 40 },
    { name: 'lisi', age: 20 },
    { name: 'wamgwu', age: 30 }
])

10. props

defineProps:获取组件传值

  1. 只接收普通的值:
let list = defineProps(['list'])
  1. 接收限制类型:
let list1 = defineProps<{list: Persons}>()
  1. 接收限制类型+限制必要性+指定默认值:
let list2 = withDefaults(defineProps<{ list?: Persons }>(), {
    list: () => [{ id:'1',name: 'zhangsan', age: 40 }]
})

11. 生命周期

生命周期:Vue组件实例在创建时要经历一系列的初始化步骤,在此过程中Vue会在合适的时机,调用特定的函数,从而让开发者有机会在特定阶段运行自己的代码,这些特定的函数统称为:生命周期钩子

以下生命周期函数都需要手动引入

11.1 Vue2 的生命周期

学习vue3 需要先进行这步操作:

npm install -g @vue/cli

创建脚手架

vue create xxx

启动项目

npm run serve

  1. 创建阶段:beforeCreate / created
  2. 挂载阶段:beforeMount / mounted
  3. 更新阶段:beforeUpdate / updated
  4. 销毁阶段:beforeDestroy / destroyed

组件属性

v-show =“isShow”: 组件是否显示(True / False)
v-if =“isShow”: 组件是否销毁(True / False)

11.2 Vue3 的生命周期

  1. 创建阶段:setup
  2. 挂载阶段:onBeforeMount / onMounted
  3. 更新阶段:onBeforeUpdate / onUpdated
  4. 卸载阶段:onBeforeUnmount / onUnmounted

vue 解析过程:
index.html --> main.ts --> APP.vue --> 子组件.vue

也就是子组件总是先比APP.vue先挂载完成

常用的钩子:onMounted / onUpdated / onBeforeUnmount

11.3 自定义Hooks

我们一般将有联系的数据或方法放在一个hook文件文件中进行管理,这大大实现了模块化开发;比如有一些关于dog的变量或者方法,我们会将其放在useDog.ts中。(hook文件的命名以use开头)

import { ref } from 'vue'

export default function () {
  let dog = ref(0)

    function addDog() {
      dog.value++
    }
  return {
    dog
  }
}

注意:文件中的变量或者方法都必须使用return 返回出去

创建hooks 文件夹

  • 30
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值