[TOC]

既然使用了vue3,那就使用最新的语法规则

setup

setup是组合式API的基础用法
注意:在setup()中不能用this

基础介绍(老语法)


<script>
    export default {
      props: {
        title: {
          type: String,
          default:()=>{return '测试信息'}
        }
      },
      setup(props, context) {
        // Attribute (非响应式对象)
        console.log(context.attrs)
        // 插槽 (非响应式对象)
        console.log(context.slots)
        // 触发事件 (方法)
        console.log(context.emit)
      }
    }
</script>

setup语法糖(高级语法)

<script setup lang="ts"><script>是在单文件组件(SFC)中使用组合式API的编译时的语法糖。相比普通的语法,它具有更多优势:

  • 更少的样板内容,更简洁的代码,比如:省略了组件的注册声明,对象暴露return,methods,。
  • 能够使用纯 Typescript 声明 props 和发出事件。
  • 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。
  • 更好的 IDE 类型推断性能 (减少语言服务器从代码中抽离类型的工作)。

1、在setup语法糖中导入组件不需要注册声明,直接在视图中使用即可;
2、vue文件默认结构发生改变,js默认放到页面顶部,而视图template放到js下面,style放到页面底部;可以根据自己的喜好更改
3、导入vue文件必须写上文件后缀名.vue, 否则ts无法识别vue文件。

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
</template>
<script setup lang="ts">
    import HelloWorld from './components/HelloWorld.vue'
    const props = defineProps({
        title: {
            type: String,
            default:()=>{return '测试信息'}
        }
    })
    console.log(props.title);
</script>

ref

ref是一个函数,用于定义处理基本数据类型,也可以定义应用类型数据
使用ref定义的数据,如果是基础类型数据,会转化为引用类型数据,可以实现响应式

  • 在模板里使用ref直接使用变量名
  • 在script里使用需要 变量名.value ```javascript

<a name="BjVUK"></a>
# reactive

- 作用:定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
- 语法:const代理对象reactive(源对象)接收一个对象(或数组),返回一个代理对象(proxy对象)
- reactive定义的响应式数据是“深层次的”。
- 内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作。

使用reactive定义的数据不需要使用value
```javascript
//引入
import { reactive } from 'vue';
let job = reactive({
        type:"前端开发",
        salary:"20K"
})
let job = reactive([1,2,3,4])
job.salary = "100k"
console.log(job,job.type)

//使用解构,会失去响应式
let {age,sex} = reactive({
        age:"18",
      sex:"男"
})
//此时修改age,sex页面上的age和sex不会更新

注意:reactive不能使用解构,否则不能实现响应式

  • ref用来定义:基本类型数据。
  • reactive用来定义:对象(或数组)类型数据。
  • 备注:ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象。
  • 从原理角度对比:
    ref通过Object.defineProperty()getset来实现响应式(数据动持)

reactive通过使用Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据。

  • 从使用角度对比:

ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。
reactive定义的数据:操作数据与读取数据:均不需要.value。

父组件传值给子组件 defineProps

vue2是使用props接收父组件的值
vue3使用的是defineProps
**注意:defineProps****defineEmits** 都是只在 **<script setup>** 中才能使用的编译器宏
子组件在接收值之前不需要先引入 defineProps

//子组件

<template>
   <h1> {{props.msg}}</h1>
   <h1> {{props.age}}</h1>
</template>
<script setup lang="ts">
import { ref } from 'vue';
    const props = defineProps({
         msg:{
            type: String,
            default: () => '默认值'
         },
          age:Number,
    })
</script>

传递回调函数

不需要引入defineEmits,直接可以使用
defineEmits里面定义的是要传递的事件名称
//子组件

<template>
   <button @click="handle">不欢迎</button>
</template>
<script setup lang="ts">
    //要传递给父组件的事件on-change
    const  emit = defineEmits(['on-change'])
    const handle =()=>{
         emit('on-change', '传递成功了')
    }
</script>

//父组件

<template>
    <Child :msg="msg" @on-change="change"></Child>
</template>

<script setup lang="ts">
//使用之前先引入
    import { ref,reactive,watchEffect } from 'vue';
    import Child from './components/child.vue'
    let msg=ref("欢迎光临")

    const change=(value)=>{
        console.log("父组件执行了",value)
    }
</script>

计算属性 computed

使用之前先引入

<template>
    <h2>{{message}}</h2>
    <h2>{{message2("是一个中国人")}}</h2>
</template>

<script setup lang="ts">
//使用之前先引入
    import { reactive,computed } from 'vue';

    let person = reactive({
        name:"oldUath",
        age:"20岁"
    })
    let message = computed(()=>{
        return person.name+'今年'+person.age
    })
  //传参的计算属性的写法
    let message2=computed(()=>(aaa)=>{
        return person.name+'今年'+person.age+aaa
    })
</script>

watch监听

监听ref基本类型数据

可以正常监听ref定义的基本类型数据

<template>
    <h2>{{sum}}-{{msg}}</h2>
    <button @click="sum++,msg+='!'">点我+1</button>
</template>

<script setup lang="ts">
//使用之前先引入
    import { ref,watch } from 'vue';

    let sum = ref(0)
    let msg = ref("你好")

    //监视ref定义的数据
    // watch(sum,(newValue,oldValue)=>{
    //     console.log("sum变化了",newValue,oldValue)
    // })

    //监视多个数据,把数据用数组包裹
    watch([sum,msg],(newValue,oldValue)=>{
        console.log("sum-msg变化了",newValue,oldValue)
        //打印出来的也是两个数组
    })
</script>

image.png

watch也可以传入第三个参数

//让watch立即执行,使用immediate
watch(sum,(newValue,oldValue)=>{
    console.log("sum变化了",newValue,oldValue)
},{immediate:true})

监听reactive

监听reactive数据或者ref定义的引用对象数据时,无法获取到正确的oldVale

//让watch监听reactive
let person = reactive({
    name:"你好呀",
  age:18
})
watch(person,(newValue,oldValue)=>{
    console.log("person",newValue,oldValue)
})

//让watch监听ref对象类型数据
let person1 = ref({
    name:"你好呀",
  age:18
})
//需要使用value
watch(person1.value,(newValue,oldValue)=>{
    console.log("person",newValue,oldValue)
})

image.png

watchEffect

watchEffect和watch一样,都是监听,但是watchEffect只传一个函数,并且是用到了谁就监听谁

  • watch的套路是:既要指明监视的属性,也要指明监视的回调。
  • watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。

watchEffect有点像computed:

  • 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
  • 而watchEffect更注亚的是过程(回调函数的函数体),所以不用写返回值。 ```javascript

```