Vue3.0到底做了哪些事情

本文详细介绍Vue3.0的新特性及其实战应用,包括composition API的使用、响应式数据处理、计算属性、侦听器等功能,同时涵盖组件通信、依赖注入等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、vue3.0实例,仅供参考

//1. vue-cli3创建项目:vue create my-project  
//2.npm安装compisition-api: npm install @vue/compisition-api --save 
//3. main.js import VueCompisitionAPI from '@Vue-Compisition-api' Vue.use(VueCompisitionAPI)

// 组件
<template>
  <div>
    <p>count: {{count}}</p>
    <p>refCount: {{refCount}}</p>
    <button @click="add"></button>
  </div>
</template>
<script>
import { reactive, ref, isRef, toRefs, computed, watch, onBeforeMount, onMounted } from '@vue/compisition-api'
export default {
  beforeCreate() {
  },
  /**
   * props: 外部传入的props参数,需要在下边的props定义,否则拿不到对应的值
   * context:相当于vue2.0中的this, 在vue3.0中拿不到this
   */
  setup(props, context) {
    // beforeCreate之后,created()之前执行
    console.log(props, context) // { p1: 'aaa' }
    // reactive 接受一个对象,返回一个响应式的数据对象, x相当于vue2.0中的observable
    const state = reactive({ count : 0})
    count++
    return state // 页面就可以访问了
    // ref:用ref做值类型响应式, ref是一个对象, .value获取值;新的ref会覆盖旧的ref
    const refCount = ref(0)
    console.log(refCount.value) // 0
    refCount.value++
    return{
      refCount,
      name: ref('zx')
    }
    // isRef: 用来判断某个值是否为 ref() 创建的
    const unwrapped = isRef(foo) ? foo.value : foo
    
    // toRefs: 将reactive()创建出来的响应式对象转换为普通对象,每一个属性节点都是一个ref
    const state = reactive({count: 0, name: 'zx'})
    // 定义自增+1的函数
    const add = () => {
      state.count += 1
    }
    return {
      // ...state, // 每个展开的数据不再是响应式,而是固定的值了
      ...toRefs(state),
      add
    }
    // computed() 传入一个function,可以得到一个只读的计算属性,返回值是一个 ref的实例
    const count = ref(0)
    const plusOne = computed(()=> count.value+1)
    console.log(plusOne.value) // 1
    plusOne.value = 9 // 报错
    // 创建可读可写的计算属性: 传入对象
    const plusOne = computed({
      get: () => {
        count.value + 1
      },
      set: val => {
        count.value = val
      }
    })
    return {
      count,
      plusOne
    }
    // watch监听某些数据的变化,从而触发某些行为
    const ref = ref(0)
    watch(()=> cosnole.log(ref.value))
    setTimeout(()=>{
      ref.value += 1
    },1500)
    // 监视 reactive类型数据源
    const state = reactive({count:0})
    watch(()=> state.count, (newVal,oldVal)=>{
    },{lazy: true}) // lazy:true 组件第一次渲染  由undefined-0 不执行监听
    // 监视 ref类型数据源
    const ref = ref(0)
    watch(()=>ref, (newVal,oldVal)=>{})
    //监听多个reactive类型数据源
    watch([()=> state.count, ()=>state.name], ([newCount, newName],         [oldCount,oldName]) => {
    })
    //监听多个ref类型数据源
    const count = ref(0)
    const name = ref(name)
    watch([count,name], ([newCount,newName],[oldCoount,oldName]) => {
    })
    //清除监视: 在组件还存在时,清除; watch会在组件被销毁时自动停止
    const stop = watch(()=>{})
    stop()
    //在watch中清除异步任务
    // 生命周期:写在setUp中
    onBeforeMount(()=>{
      
    })
    onMounted(()=>{
    })
  },
  created() {
  },
  props: {
    p1: String
  }
}
</script>
<style>
</style>

二、Vue3

官方文档

目前已支持的UI库 

element-plus:pc组件库

Button 按钮 | Element Plus

我们建议您使用包管理器(如 NPM、Yarn 或 pnpm)安装 Element Plus,
然后您就可以使用打包工具,例如 Vite 或 webpack。

# 选择一个你喜欢的包管理器

# NPM
$ npm install element-plus --save

# Yarn
$ yarn add element-plus

# pnpm
$ pnpm install element-plus

ant-design-vue:pc组件库

https://antdv.com/components/button-cn

引入 ant-design-vue #
1. 安装脚手架工具 #
vue-cli

$ npm install -g @vue/cli
# OR
$ yarn global add @vue/cli
2. 创建一个项目 #
使用命令行进行初始化。

$ vue create antd-demo
并配置项目。

若安装缓慢报错,可尝试用 cnpm 或别的镜像源自行安装:rm -rf node_modules && cnpm install。

3. 使用组件 #
安装 #
$ npm i --save ant-design-vue

vant:移动端Vue组件库

Vant 3 - Lightweight Mobile UI Components built on Vue

 Vue3新特性:vue3 性能更高, 体积更小, 更利于复用, 代码维护更方便

优势:

        1、更好的逻辑复用 与 代码组织 (composition组合式api)

        optionsAPI(旧) => compositionAPI(新), 优点: 代码组织更方便, 逻辑复用更方便 ,便于维护

        2、更好的类型推导 (typescript支持)

        vue3 源码用 ts 重写的, vue3 对 ts 的支持更友好了 

vue3新特性:

        数据响应式原理重新实现 (ES6 proxy 替代了 ES5 的 Object.defineProperty)

优势: 数组的更新检测等bug, 大大优化了响应式监听的性能 ---覆写

(原来检测对象属性的变化, 需要一个个对属性递归监听) proxy 可以直接对整个对象劫持

        虚拟DOM - 新算法 (更快 更小)

        提供了composition api, 可以更好的逻辑复用

        模板可以有多个根元素

        源码用 typescript 重写, 有更好的类型推导 (类型检测更为严格, 更稳定)

        废弃了 eventbus 过滤器等等

Vite:是一种新型前端构建工具

优势:

  •  极速的服务启动,使用原生 ESM 文件,无需打包

  •  轻量快速的热重载,始终极快的模块热重载(HMR)

  • 丰富的功能,对 TypeScript、JSX、CSS 等支持开箱即用

对比webpack

        webpack启动项目 -> webpack进行打包编译->将打包的结果交给浏览器 ->浏览器运行

        vite启动项目 -> 将打包编译的工作交给了浏览器->浏览器直接解析业务

基本使用

如果想要快速创建一个vue3项目,可以使用如下命令

创建普通vue项目

yarn create vite vite-demo --template vue
创建基于ts模板的项目

yarn create vite vite-demo-ts --template vue-ts

# npm 6.x
npm create vite@latest my-vue-app --template vue

# npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-app -- --template vue

# yarn
yarn create vite my-vue-app --template vue

# pnpm
pnpm create vite my-vue-app --template vue

Vue3项目详解

一、组合式API: 相似的逻辑, 容易复用

vue2 采用的就是 optionsAPI

(1) 优点:易于学习和使用, 每个代码有着明确的位置 (例如: 数据放 data 中, 方法放 methods中)

(2) 缺点: 相似的逻辑, 不容易复用, 在大项目中尤为明显

(3) 虽然 optionsAPI 可以通过mixins 提取相同的逻辑, 但是也并不是特别好维护

vue3 新增的就是 compositionAPI

(1) compositionAPI 是基于 逻辑功能 组织代码的, 一个功能 api 相关放到一起

(2) 即使项目大了, 功能多了, 也能快速定位功能相关的 api

(3) 大大的提升了 代码可读性 和 可维护性

vue3 推荐使用 composition API, 也保留了options API

即就算不用composition API, 用 vue2 的写法也完全兼容

// 功能: 鼠标移动显示鼠标坐标 x, y

// options API 版本

<template>
  <div>当前鼠标位置</div>
  <div>x: {{ mouse.x }}</div>
  <div>y: {{ mouse.y }}</div>
  <div>当前点击次数:{{ count }}</div>
  <button @click="add">点击</button>
</template>
​
<script>
export default {
  // vue2 中采用的是 options API
  // 常见的配置项: data created methods watch computed components
  data() {
    return {
      mouse: {
        x: 0,
        y: 0,
      },
      count: 0,
    }
  },
  mounted() {
    document.addEventListener('mousemove', this.move)
  },
  methods: {
    move(e) {
      this.mouse.x = e.pageX
      this.mouse.y = e.pageY
    },
    add() {
      this.count++
    },
  },
  destroyed() {
    document.removeEventListener('mousemove', this.move)
  },
}
</script>


// composition API 版本

<template>
  <div>当前鼠标位置</div>
  <div>x: {{ mouse.x }}</div>
  <div>y: {{ mouse.y }}</div>
  <div>当前点击次数:{{ count }}</div>
  <button @click="add">点击</button>
</template>
​
<script>
import { onMounted, onUnmounted, reactive, ref } from 'vue'
​
export default {
  setup() {
    const count = ref(0)
    const add = () => {
      count.value++
    }
​
    const mouse = reactive({
      x: 0,
      y: 0,
    })
​
    const move = (e) => {
      mouse.x = e.pageX
      mouse.y = e.pageY
    }
    onMounted(() => {
      document.addEventListener('mousemove', move)
    })
    onUnmounted(() => {
      document.removeEventListener('mousemove', move)
    })
    return {
      count,
      add,
      mouse,
    }
  },
}
</script>


// 抽离逻辑

function useMouse() {
  const mouse = reactive({
    x: 0,
    y: 0,
  })
  const move = (e) => {
    mouse.x = e.pageX
    mouse.y = e.pageY
  }
  onMounted(() => {
    document.addEventListener('mousemove', move)
  })
  onUnmounted(() => {
    document.removeEventListener('mousemove', move)
  })
  return mouse
}
​
function useCount() {
  const count = ref(0)
  const add = () => {
    count.value++
  }
  return {
    count,
    add,
  }
}

二、setup 函数

composition api的使用, 需要配置一个setup 函数

setup 函数是一个新的组件选项, 作为组件中 compositionAPI 的起点

从生命周期角度来看, setup 会在 beforeCreate 钩子函数之前执行

setup 中不能使用 this, this 指向 undefined

在模版中需要使用的数据和函数,需要在 setup 返回

三、reactive 函数:用来定义响应式 对象数据

传入一个复杂数据类型,将复杂类型数据, 转换成响应式数据 (返回该对象的响应式代理)

<template>
  <div>{{ obj.name }}</div>
  <div>{{ obj.age }}</div>
  <button @click="obj.name = 'ls'">改值</button>
</template>
​
<script>
import { reactive } from 'vue'
​
export default {
  setup () {
    // 1. setup 需要返回值, 返回的值才能在模板中使用
    // 2. 默认的普通的值不是响应式的, 需要用 reactive 函数
    const obj = reactive({
      name: 'zs',
      age: 18
    })
​
    return {
      obj
    }
  }
}
</script>

四、ref 函数

reactive 处理的数据, 必须是复杂类型, 如果是简单类型无法处理成响应式, 所以有 ref 函数

作用: 对传入的数据(一般简单数据类型),包裹一层对象, 转换成响应式。

ref 函数接收一个的值, 返回一个ref 响应式对象, 有唯一的属性 value

在 setup 函数中, 通过 ref 对象的 value 属性, 可以访问到值

在模板中, ref 属性会自动解套, 不需要额外的 .value

ref函数也支持传入复杂类型,传入复杂类型,也会做响应式处理

<template>
  <div>{{ money }}</div>
  <button @click="money++">改值</button>
</template>
​
<script>
import { reactive, ref } from 'vue'
export default {
  setup() {
    let money = ref(100)
    money.value++
    return {
      money
    }
  }
}
</script>

五、计算属性computed函数

<template>
  <div>我今年的年纪 <input type="text" v-model="age" /></div>
  <div>我明年的年龄 {{ nextAge }}</div>
  <div>我后年的年龄 <input type="text" v-model="nextAge2" /></div>
</template>

// script setup是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 script 语法更加简洁
<script setup>
import { computed, ref } from 'vue'
const age = ref(10)
// 不带set的计算属性
const nextAge = computed(() => {
  return +age.value + 1
})

// 带set的计算属性
const nextAge2 = computed({
  get() {
    return +age.value + 2
  },
  set(value) {
    age.value = value - 2
  },
})
</script>

六、侦听器watch函数

watch监视, 接收三个参数
1. 参数1: 监视的数据源
2. 参数2: 回调函数
3. 参数3: 额外的配置
// 监听单个ref
const money = ref(100)
watch(money, (value, oldValue) => {
  console.log(value)
})

// 监听多个ref
const money = ref(100)
const count = ref(0)
watch([money, count], (value) => {
  console.log(value)
})

// 监听ref复杂数据
const user = ref({
  name: 'zs',
  age: 18,
})
watch(
  user,
  (value) => {
    console.log('user变化了', value)
  },
  {
    // 深度监听,,,当ref的值是一个复杂数据类型,需要深度监听
    deep: true,
    immediate: true
  }
)

// 监听对象的某个属性的变化
const user = ref({
  name: 'zs',
  age: 18,
})
watch(
  () => user.value.name,
  (value) => {
    console.log(value)
  }
)

七、钩子函数的使用

import { onMounted, onUpdated, onUnmounted } from 'vue'

const MyComponent = {
  setup() {
    onMounted(() => {
      console.log('mounted!')
    })
    onUpdated(() => {
      console.log('updated!')
    })
    onUnmounted(() => {
      console.log('unmounted!')
    })
  }
}

八、组件通讯

父传子

// 父组件

<script setup>
import { ref } from 'vue'
// 在setup语法中,组件导入之后就能够直接使用,不需要使用components进行局部注册
import Son from './components/Son.vue'

const money = ref(100)
const car = ref('玛莎拉蒂')
</script>

<template>
  <div>
    <h1>我是父组件</h1>
    <div>金钱:{{ money }}</div>
    <div>车辆:{{ car }}</div>
    <hr />
    <Son :money="money" :car="car"></Son>
  </div>
</template>

<style lang="less" scoped></style>

// 子组件

<script setup>
import { computed } from 'vue'

// defineProps: 接收父组件传递的数据
const props = defineProps({
  money: Number,
  car: String,
})

const myMoney = computed(() => {
  return props.money + 100
})
</script>

<template>
  <div>
    <h3>我是子组件</h3>
    <div>{{ money }} --- {{ car }}</div>
  </div>
</template>

<style lang="less" scoped></style>
注意:如果使用defineProps接收数据,这个数据只能在模板中渲染,如果想要在script中也操作props属性,应该接收返回值。

子传父

  1. 子组件通过defineEmit获取emit对象(因为没有this)

  2. 子组件通过emit触发事件,并且传递数据

  3. 父组件提供方法

  4. 父组件通过自定义事件的方式给子组件注册事件

    // 子组件
    
    <script setup>
    defineProps({
      money: Number,
      car: String,
    })
    
    const emit = defineEmits(['changeMoney'])
    
    const change = () => {
      emit('changeMoney', 10)
    }
    </script>
    
    // 父组件
    
    <script setup>
    import { ref } from 'vue'
    // 在setup语法中,组件导入之后就能够直接使用,不需要使用components进行局部注册
    import Son from './components/Son.vue'
    
    const money = ref(100)
    const car = ref('玛莎拉蒂')
    const changeMoney = (num) => {
      money.value = money.value - num
    }
    </script>
    
    
    <Son :money="money" :car="car" @changeMoney="changeMoney"></Son>

 九、依赖注入 - provide 和 injec

依赖注入, 可以非常方便的实现 跨层级的 组件通信

父组件利用 provide 提供数据

<script setup>
import { provide, ref } from 'vue'
import Son from './components/Son.vue'
const money = ref(100)
provide('money', money)
</script>

<template>
  <div>
    <h1>我是父组件</h1>
    <div>金钱:{{ money }}</div>
    <hr />
    <Son></Son>
  </div>
</template>

<style lang="less" scoped></style>
子组件 (子孙后代, 都可以拿到这个数据)

<script setup>
import { inject } from 'vue'

const money = inject('money')
</script>

<template>
  <div>
    <h3>我是子组件--{{ money }}</h3>
    <button>修改数据</button>
  </div>
</template>

<style lang="less" scoped></style>

// 如果希望子传父, 可以 provide 传递一个方法

// 父组件

<script setup>
import { provide, ref } from 'vue'
import Son from './components/Son.vue'
const money = ref(100)
const changeMoney = (num) => {
  money.value = money.value - num
}
provide('money', money)
provide('changeMoney', changeMoney)
</script>
// 子组件

<script setup>
import { inject } from 'vue'

const money = inject('money')
const changeMoney = inject('changeMoney')
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值