V3简单基础语法记录

311 阅读3分钟

汇总→:

image.png

Vue2对比Vue3

-   响应式原理api的改变 Vue2响应式原理采用的是defineProperty,(defineProperty的缺点!!!)而vue3选用的是proxy。
这两者前者是修改对象属性的权限标签,后者是代理整个对象。性能上proxy会更加优秀。

-   diff算法,渲染算法的改变 Vue3优化diff算法。不再像vue2那样比对所有dom,而采用了block tree的做法。
此外重新渲染的算法里也做了改进,利用了闭包来进行缓存。这使得vue3的速度比vue2快了6倍。
vue3更好的Tree-shaking,也使得性能大幅提升。

    -   建立数据 data 这里就是Vue2与Vue3 最大的区别 — Vue2使用`选项类型API(Options API)`对比Vue3`
合成型API(Composition API)` 旧的选项型API在代码里分割了不同的属性(properties):data,computed属性,
methods,等等。新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便
和整洁。理论上更易于维护变量和方法。

Vue3的一些新特性--

说起Vue3,不得不提起一些老生常谈,可以脱口而出的V3的特点。

1. Vue3支持向下兼容,可兼容Vue2语法,同时青出于蓝而胜于蓝。
2. 性能的提升,大幅提升。据相关不可靠数据统计,打包大小减少41%,初次渲染快55%,热更新快133%,内存使用减少54%。
3. Composition Api的加持,让你的代码可维护性进一步提升。它是一系列Api的集合。
4. 优化很好的Tree-shaking、充分体现了权衡的艺术。
5. 更好的Typescript支持。

书写方式的变更: image.png

Vue3生命周期

将 Vue2 的生命周期钩子代码更新到 Vue3
这个从Vue2 到Vue3的生命周期映射是直接从Vue 3 Composition API文档中获得的:

image.png

介绍:Composition Api之setUp(props,context)

props:组件外部传递过来,且组件内部声明接收了的属性。 context:上下文对象

1、attrs: 相当于this.$attrs

2、emit: 相当于this.$emits

3、solts: 相当于this.$slot

<template>
  <div>
    <h2>Vue3新语法之setUp()</h2>
    <div>{{Car}}</div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
  name: "App",
  setup(props,context) {
    const Car = ref('Mercedes-Benz');
    return {
      Car
    };
  },
});
</script>

vue2中声明的变量需要放在data中声明使用。而vue3中通过ref声明变量,并且在setup函数中返回出去才可以在页面上使用。

export default defineComponent({
  name: "App",
  setup() {
    const Car = ref('Mercedes-Benz');
    //在setUp里定义方法
    const changCar = () => {
        Car.value = 'Porsche'
    }
    return {
      Car,
      changCar
    };
  },
});

通过ref声明的变量在赋值的时候需要通过变量.value去进行赋值和读取操作。并且事件方法不在需要声明在methods中了。 而是直接写在setup函数中就可以了。

<template>
  <div>
    <h2>vue3新语法reactive</h2>
    <div>{{ data.car }}</div>
    <button @click="data.changeCar">改变我的车</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive } from "vue";
export default defineComponent({
  name: "App",
  setup() {
    const data = reactive({
      car: "Mercedes-Benz",
      changeCar: () => {
        data.car = "BMW";
      },
    });
    return {
      data
    };
  },
});
</script>

setUp语法糖

直接在script标签中添加setup属性就可以直接使用setup语法糖了。
使用setup语法糖后,不用写setup函数;组件只需要引入不需要注册;属性和方法也不需要再返回,可以直接在template模板中使用
1.它只是简化了以往的组合API(compositionApi)的必须返回(return)的写法,并且有更好的运行时性能。
2.在setup函数中所有 ES 模块导出都被认为是暴露给上下文的值,并包含在 setup() 返回对象中。相对于之前的写法,使用后,语法也变得更简单。

    <template>
        <my-component @click="func" :numb="numb"></my-component>
    </template>
    <script lang="ts" setup>  //直接在script标签中使用setUp语法糖
        import {ref} from 'vue';
        import myComponent from '@/component/myComponent.vue';
        //此时注册的变量或方法可以直接在template中使用而不需要导出
        const numb = ref(0);
        let func = ()=>{
            numb.value++;
        }
    </script>

介绍-- ref和reactive

reactive 和 ref 都是用来定义响应式数据的 reactive更推荐去定义复杂的数据类型 ref 更推荐定义基本类型 ref 和 reactive 本质我们可以简单地理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value

使用ref定义基本数据类型,ref也可以定义数组和对象。
注:ref定义基本数据类型,形成响应式依赖于Object.defineProperty( )

reactive: 用proxy 定义响应式
注:使用reactive定义响应式数据时,若数据不是对象类型直接就返回了,就不会进行后续的数据响应式处理了

介绍-- watch:

watch改进可以监听多个属性:

    setup() {
        const car = ref('BNMW')
        const list= reactive({ 
            name: '张三', 
            nickName: '三儿',
            soulmate: {
                name: '李四',
                nickName: '四儿' 
            }
        })
        
        //1. watch监听单个属性*
        watch(car,(newVal,oldVal)=>{
            console.log(newVal,oldVal)
        })
        //2.---监听对象里面的某一个属性---
        watch(()=>list.name,(newValue,oldValue)=>{ 
            console.log('watch innier', newValue)
        })
        //3. 注意这里是箭头函数,加了deep为true,对象里的子属性孙属性都会监听到 
        watch(()=>list,(newValue,oldValue)=>{ 
          console.log('watch innier', newValue) 
        },
         {deep: true
          //添加immediate,会让监听立即执行 
          immediate:true
         },
        )
       //4.监听多个属性,以数组的形式,返回数组***
       watch([car,list],([newCar,newList],[oldCar,oldList])=>{
           console.log(.....)
       })
    }

watchEffect 与 watch的immediate类似 :传入的一个函数,当依赖项变化的时候,重新执行该函数。


watchEffect(() => {
    //'pre' 在组件更新更新前运行,默认为'pre'
    //'post'在组件更新更新后运行
    //'sync'强制效果始终同步触发。然而,这是低效的,应该很少需要。
    flush:'post'
    console.log(`${sum.person.age} 的值变化了!`)
}, {
    onTrack(e) { //追踪其依赖的时候触发,只能在开发者模式下使用
    console.log(e.target)
    },
    onTrigger(e) {  //依赖项被改变的时候触发,只能在开发者模式下使用
    console.log(e.target)
    }
})
## watchPostEffect():使用 `flush: 'post'` 选项时的别名。
## watchSyncEffect(): 使用 `flush: 'sync'` 选项时的别名。

简介computed

<template>
  <div>
    <div>姓:<input type="text" v-model="per.surname"></div>
    <div>名:<input type="text" v-model="per.name"></div>
    <div>姓名:<input type="text" v-model="per.fullName"></div>
  </div>
</template>

<script>
import { computed, reactive } from 'vue'
 
export default {
  setup(){
    let per=reactive({
      surname:'王',
      name:'小陈'
    })
    per.fullName=computed(()=>{
      return per.surname+'~'+per.name
    })
    return{
      per
    }
  }
}

2.setup语法糖中新增的api

defineProps:子组件接收父组件中传来的props
defineEmits:子组件调用父组件中的方法
defineExpose:子组件暴露属性,可以在父组件中拿到

defineProps:案例
1.接收值什么也不定义
<script setup>
import { defineProps, withDefaults } from "vue"; 
const definepr = defineProps(["width", "height"]);
console.log(definepr); 
</script>
2.接收值定义类型和默认值
<script setup>
import { defineProps, withDefaults } from "vue";
const propsObj = defineProps({
  width: {
    type: Number,
    default: "200",
  },
  height: {
    type: Number,
    default: "100",
  },
  name:{
      type:Array,
      default:()=>[]
  }
});
console.log(propsObj.width)    //200;
</script>

3.接收值 ts定义类型和默认值 ---withDefaults


type Props = {
  id: string
  placeholder?: string
  label?: string
  labelWidth: string
  modelValue: string
  // 小数点位数
  fix: number
  // 最大输入位数
  maxlength: number
  disabled?: boolean
  inputAlign?: 'left' | 'center' | 'right'
}

const props = withDefaults(defineProps<Props>(), {
  placeholder: '请输入金额',
  label: '金额',
  fix: 2,
  maxlength: 14,
  inputAlign: 'left',
  modelValue: '',
  disabled: false,
})
defineExpose:案例
原因:使用 <script setup> 语法糖的组件是默认关闭的,也即通过模板 ref 或者 \$parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。
方法:为了在 <script setup> 语法糖组件中明确要暴露出去的属性,,使用 defineExpose 编译器宏将需要暴露出去的变量与方法放入暴露出去就可以

!!!!!
简单说:父组件要调用子组件的方法或变量。需要子组件defineExpose暴露出实例或者方法。否则,会报错变量/方法不存在
    
const emit = defineEmits<{
  (e: 'confirm', value: unknown, index: number, columns: Array<any>): void
  (e: 'cancel', value: unknown, index: number, columns: Array<any>): void
}>()
//使用
emit('confirm', 参数paramsObj)
emit('cancel', 参数)
介绍 toRef/toRefs:

ref和toRef区别: ref->复制,修改响应式数据不会影响以前的数据
toRef->引用,修改响应式数据会影响以前的数据

ref->数据发生改变,界面就会自动更新
toRef->数据发生改变,界面也不会自动更新

使用场景:如果想让响应式数据和以前的数据关联起来,并且更新响应数据之后不想更界面UI,就用toRef

toRef --- 代理一个对象
toRefs --- 代理多个对象

案例:
const obj = reactive({
    name:'张三';
    sex:'男'
})
let {name,sex} = toRefs(obj) //toRefs用解构的方式,把响应式对象的属性新建为多个新的ref
name = '牛二'
sex = '女'
console.log(obj) // {name:'牛二',sex:'女'}  说明原始对象也被改变,仍然具有响应式
介绍:shallowReactive 与 shallowRef:

shallowReactive 与 shallowRef
shallowReactive:只处理对象最外层属性的响应式(浅响应式)。

shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。

什么时候使用?

如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。

如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。

谨慎使用!!!!!
浅层数据结构应该只用于组件中的根级状态。请避免将其嵌套在深层次的响应式对象中,因为
它创建的树具有不一致的响应行为,这可能很难理解和调试。

作用:性能优化!!!
介绍:readonly:

接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理

const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => { 
// 用来做响应性追踪
console.log(copy.count)
}) 
// 更改源属性会触发其依赖的侦听器 
original.count++ 
// 更改该只读副本将会失败,并会得到一个警告
copy.count++ // warning!

使用useAttrs和useSlots
在 `<script setup>` 使用 `slots` 和 `attrs` 的情况应该是相对来说较为罕见的
,因为可以在模板中直接通过 `$slots` 和 `$attrs` 来访问它们。在你的确需要使用它们的罕见
场景中,可以分别用 `useSlots` 和 `useAttrs` 两个辅助函数:

// 旧 
<script setup>   
import { useContext } from 'vue'  
const { slots, attrs } = useContext() 
</script>

// 新
<script setup> 
    import { useSlots, useAttrs } from 'vue' 
    const slots = useSlots() 
    const attrs = useAttrs() 
</script>
概括:
useAttrs是获取defineProps父级没有传过来的其他属性 ---  defineProps剩余的属性
若defineProps未声明任何属性,则useAttrs可获取所有属性
useSlots:拿到从父组件插槽传过来的值

详情可参考vue.js官方文档: cn.vuejs.org/guide/intro…

........

感谢阅读! 栓Q歪瑞马奇~