vue 2-3版本过渡| 青训营笔记

101 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第2天

vue3 语法

vue3 语法有了新的变化相较于vue2

从编写方式,以及到api 变动都有所所变化

从选项式api 过渡到了组合式api,编写业务代码的逻辑从杂乱无章,到,从上往下,有了质一样的飞跃

选项式api

image.png

过渡vue3 之前,我们需要了解下vite

vite

vite官网

vite是开发前端项目的脚手架,其具有快速启动,强大的热重载特点 之前使用vue都是使用webpack,webpack 的功能也挺强的的,但是随着项目的扩大,依赖增加,每次项目的启动时间在5-10s 之间,非常缓慢,而vite,启动速度极快,初始项目大概只需要400ms 左右就能启动,所以,我非常推荐使用vite 来进行开发

在命令行输入 npm create vite@latest 就可以快速创建一个vue 项目,接着就可以愉快的开发了

template标签 变动

现在 template 标签下 可以写多个根标签,不在是只能写一个根标签

<template>
  <div>dsad</div>
  <div>dsad</div>
</template>

setup 语法

setup 是vue3 新增语法糖,简化 js

<script setup lang="ts">

</script>

使用了setup 后,当前组件页面内,使用外部组件无需使用 export default components 属性声明,在setup 内的变量会全部自动导出,并且在setup 的变量会全部导出到vue 对象种,也就是我们之前使用的data 属性,因此,我们只需要关注我们的业务逻辑,就行了,并不需要,再使用this 关键词引用data 属性

vue2 写法

<template>
  <hello-world msg="dsads"></hello-world>
</template>
<script lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
export default {
  components:{
    HelloWorld
  }
}
</script>

vue3 写法

<template>
  <hello-world msg="dsads"></hello-world>
</template>

<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
</script>

ref

ref 是vue3 声明响应式数据的方式 由于vue3 不推荐使用 export default 方式,因此改为以下方式

<template>
  <hello-world :msg="num"></hello-world>
  <button @click="change">change</button>
</template>

<script setup lang="ts">

import HelloWorld from "./components/HelloWorld.vue";
import {ref} from "vue";
// 使用 ref 绑定数据
let num = ref<string>("111")
const change =()=>{
  num.value= "dsadsa"
}

</script>

ref 适用了简单数据类型,并且如果要更改ref 绑定的数据,需要 num.value= "dsadsa"方式,才能动态更改

ref 也可以用于复杂类型,源码中进行了判断,如果是复杂数据类型会转换成 reactive 类型

reactive

也是声明响应式数据的方式

<template>
  <button @click="change">change</button>
  <div>{{list}}</div>
</template>

<script setup lang="ts">
import {ref,reactive} from "vue";

let list =  reactive<number[]>([1,2,34,5]);
const change =()=>{
  list = [2]
  console.log(list)
}
console.log(list)

</script>

修改响应式数据为数组时,可以直接修改,不需要再调用value 属性

但是当修改值为数组时,会破坏响应数据,从而变成普通数据

解决方法1

<template>
  <button @click="change">change</button>
  <div>{{list}}</div>
</template>

<script setup lang="ts">
import {ref,reactive} from "vue";

type o ={
  list:number[]
}

let list =  reactive<o>({
  list:[1,2,34,5]
});
const change =()=>{
  list.list = [2]
  console.log(list)
}
console.log(list)

</script>

通过定义一个临时类型对象来赋值

解决方法2

<template>
  <button @click="change">change</button>
  <div>{{list}}</div>
</template>

<script setup lang="ts">
import {ref,reactive} from "vue";


let list =  reactive<number[]>([1,2,34,5]);
const change =()=>{
  let a = [2]
  list.push(...a)
  console.log(list)
}
console.log(list)

</script>

# 响应性语法糖 $ref

使用ref()可以有效的避免我们操作ref带来的.value这样的操作,ref() 可以有效的避免我们操作ref 带来的.value 这样的操作,ref 本质上也是ref 注意:响应性语法糖目前是一个实验性功能,默认是禁用的,需要显式选择使用

需要在vite 的配置文件中


// vite.config.js
export default {
  plugins: [
    vue({
      reactivityTransform: true
    })
  ]
}

如果使用了ref则不需要关心可能会丢失响应式的操作,并且,ref 则不需要 关心可能会丢失响应式的操作,并且,ref 并不需要引入,它是一个编译时的宏命令 更多的内容可以查阅文档 响应性语法糖 | Vue.js (vuejs.org)

computed

计算属性,当函数内部使用到的外部变量发生变动时,就会除非计算属性方法

totalPrice = computed(() => {
  let $total = 0
  shopList.forEach(e => {
    $total += (e.price * e.total)
  })
  return $total;
})

计算属性可以在一些动态计算的变量中实现,例如,购物车,当用户修改购物车的商品或者数量时就会动态计算总价格等等

watch

监听变量

<template>
  <input type="text" v-model="obj">
</template>

<script setup lang="ts">
import {ref, reactive, watch} from "vue";

let obj=  ref(111)

watch(obj,(newVal,oldVal)=>{
  console.log("新值:===",newVal);
  console.log("旧值:===",oldVal);
})

</script>

这样当我们修改obj 时,就会出发监听函数,

但是当我们监听复杂类型时,ref 绑定的数据,是不会监听深层次的值的,

例如

let obj=  ref({
	name:'zs'
})

vue 并不会帮我们监听name的值,

需要开启深层次监听 deep:true

<template>
  <input type="text" v-model="obj.name">
</template>

<script setup lang="ts">
import {ref, reactive, watch} from "vue";

let obj=  ref({
  name:"zs"
})

watch(obj,(newVal,oldVal)=>{
  console.log("新值:===",newVal);
  console.log("旧值:===",oldVal);
},{deep:true})

</script>

如果使用reactive 来绑定,则不需要开启deep:true

注意,如果监听对象的话,会导致旧值与新值相同,这不是bug,这是因为vue 绑定的是数据的引用地址原因

监听对象中的某个值

<template>
  <input type="text" v-model="obj.name">
</template>

<script setup lang="ts">
import {ref, reactive, watch} from "vue";

let obj=  ref({
  name:"zs"
})

// 使用监听函数,返回需要监听的值
watch(()=>obj.value.name,(newVal,oldVal)=>{
  console.log("新值:===",newVal);
  console.log("旧值:===",oldVal);
})

</script>

生命周期函数

<script setup lang="ts">
import {onMounted} from "vue";


// 类比vue2 中的 mounted() 函数
onMounted(()=>{
  
})

</script>

所有的生命周期函数都发生了变化,都在原始的api方法上添加了onXXXX

defineProps

props 也是开发中常用的内容之一,如果配合ts 使用,效果会非常好

props 属性,父组件向子组件传值使用了 defineProps

<!--父组件-->
<template>
  <div class="layout">
    <Menu :name="name"></Menu>
    <div class="layout-right">
      <Header></Header>
      <Content></Content>
    </div>
  </div>
</template>

<script setup lang="ts">
import Content from './Content/index.vue'
import Header from './Header/index.vue'
import Menu from './Menu/index.vue'

import {reactive, ref} from 'vue'

let name =  ref<string>("zs")

</script>
<!--子组件-->
<template>
  <div class="menu">
    Menu
    <div>
      {{name}}
    </div>
  </div>
</template>

<script setup lang="ts">

type Props={
  name:string
  
}
// 使用 defineProps 泛型来声明props 的类型
defineProps<Props>()

</script>
<!--子组件-->
<template>
  <div class="menu">
    Menu
    <div>
      {{name}}
    </div>
  </div>
</template>

<script setup lang="ts">

type Props={
  name:string
 data?:number[] // 加问号,表示可以不传递data props值,但是此时没有默认值  
}
// 使用 withDefaults来规定默认值,如果类型是对象,则使用函数返回值形式
withDefaults(defineProps<Props>(),{
    data:()=>[1233,54,768]
})


</script>

defineEmits

事件派发,可以有子组件触发事件,传递给父组件,也可以从子组件传值给父组件

<template>
  <div class="menu">
    Menu
    <div>
      {{name}}
    </div>
    <div>
      <button @click="onClick">派发</button>
    </div>
  </div>
</template>

<script setup lang="ts">
import {reactive} from "vue";
    
// defineEmits  是一个函数,接收一个数组,数组中就是传递的事件名称,返回值是 派发对象
const emits =  defineEmits(['on-click'])
let list = reactive([1,23,5])
const onClick = ()=>{
  // 触发子组件事件时,给父组件传递一个事件名称,并且传值给父组件
  emits('on-click',list)
}
</script>
<template>
  <div class="layout">
     <!-- 父组件需要使用 @事件名称 来绑定事件 -->
    <Menu :name="name" @on-click="getData"></Menu>
    <div class="layout-right">
      <Header></Header>
      <Content></Content>
    </div>
  </div>
</template>

<script setup lang="ts">
import Content from './Content/index.vue'
import Header from './Header/index.vue'
import Menu from './Menu/index.vue'

import {reactive, ref} from 'vue'

let name =  ref<string>("zs")

// 子组件派发的事件,参数为子组件传递的参数
const getData = (list:number[])=>{
  console.log(list)
}
</script>

样式穿透

在使用ui库时,可能需要修改原本组件的样式,则,可以使用

:deep(.ui-sdsa){
    color:red
}