Vue3.0基础

Vue3.0新特性

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

2、源码使用typescript进行重新编写(更好的类型推导)

3、虚拟DOM新算法(更快、更小)

4、提供了composition api ,为了更好的逻辑复用与代码组织

5、自定义渲染器(可以根据需求自定义渲染器,运行在不同的终端)

如:小程序端:http://mpvue.com/;
	游戏开发:https://vugel.planning.nl/#application

6、Fragment,模板可以有多个根元素

Vue2.0和Vue3.0响应式原理对比

Vue2.0响应式原理

Vue2.0中使用ES5的Object.defineProperty方法实现响应式数据。

缺点:1、无法监测到对象属性的动态添加和删除;2、无法监测到数组的下标和长度。

解决方案:Vue2.0提供Vue.set方法用于动态给对象添加属性;提供Vue.delete方法用于动态删除对象的属性;重写vue中数组的方法,用于监测数组的变更。

Vue3.0响应式原理

Vue3.0中使用ES6中的proxy语法实现响应式数据

优点:1、可以监测到代理对象属性的动态添加和删除;2、可以监测到数组的下标和length属性的变更;

缺点:ES6的proxy语法对于低版本浏览器不支持,如ie11;Vue3.0会针对ie11出一个特殊的版本用于支持ie11

创建vue3.0项目

使用vue-cli创建vue3.0项目

vue --version  查看vue/cli版本 ,只有4.5.0之后的版本支持vue3.0

vue create vue3_project  // 创建项目

vue add vue-next   // 2.0项目升级到3.0,不建议直接升级,2.0很多在3.0不支持会导致原项目跑不起来

使用vite创建vue3.0项目

Vite介绍

Vite是一个由原生ESM驱动的Web开发构建工具,在开发环境下基于浏览器原生ES imports开发,在生产环境下基于Rollup打包。

npm init vite-app vue3_project    // 创建vue3.0项目,vue3_project

composition API 和 options API 对比

options API (选项API)

1、优点:容易学习和使用,代码有明确的书写位置

2、缺点:相似逻辑不容易复用,在大项目中尤为明细

3、可以通过mixins 提取相同的逻辑,但容易发生命名冲突且来源不清晰

composition API(组合API)

1、根据逻辑功能来组织代码的,一个功能所有的api放到一起

2、即便项目很大,功能很多,都能够快速的定位到该功能所有的API

3、提高了代码的可读性和可维护性

【vue3.0中推荐使用composition API,也保留了options API】

composition API的使用

1、setup

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

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

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

2、reactive

reactive函数接收一个普通对象(需要是复杂类型),返回该对象的响应式代理(返回代理对象,即实现数据响应式)

3、ref

ref函数接收一个简单类型,返回一个可改变的ref对象。返回的对象有唯一的属性value

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

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

如果ref接收的是一个对象,系统会自动将ref转换为reactive

【Vue3中实现响应式数据的方法是ref和reactive】

4、toRefs

把一个响应式对象转换成普通对象,该普通对象的每个属性都是一个ref

reactive的响应式功能是赋予给对象的,但是如果给对象解构或者展开的时候,会让简单类型的数据丢失响应式的能力

使用toRefs可以保证该对象展开的每一个属性都是响应式的

5、readonly

传入一个对象(响应式或普通)或ref属性,返回一个原始对象的只读代理

一个只读的代理是"深层的",即对象内部任何嵌套的属性也都是只读的

可以防止对象被修改

如:父组件给子组件传数据,父组件不希望子组件修改此数据,可以用readonly包裹此数据

6、computed

computed函数用于创建一个计算属性

若传入的是一个getter函数,会返回一个不允许修改的计算属性

若传入的是一个带有getter和setter函数的对象,会返回一个允许修改的计算属性

7、watch

watch函数接受三个参数:①数据源,可以是ref或者getter函数;②回调函数(newValue,oldValue)=>{};③额外选项,deep和immediate。

可以监听一个ref或者一个带有返回值的getter函数。

可以监听单个数据源,也可以监听多个数据源

watch函数会有返回值,用于停止监听

示例

<template>
  <div>{{ obj.brand }}--{{ obj.price }}</div>
  <button @click="obj.brand = '奔驰'">修改</button>
  <!-- ref在模板中使用,会自动解套 -->
  <div>{{ money }}</div>  
  <button @click="money++">money+1</button>  
  <!--  toRefs -->
  <div>{{ yellow }}</div>
  <div>{{ red }}</div>
  <button @click="yellow='mango'"></button>
  <!--  readonly -->
  <div>{{ animals.one }}</div>
  <div>{{ animals.two }}</div>
  <button @click="animals.one = 'rabbit'">不会变</button>
  <!--  computed -->
  <div>
  今年的年龄:<input type="text" v-model = "age" />
  明年的年龄:<input type="text" v-model = "nextAge" />
  后年的年龄:<input type="text" v-model = "nextAge2" />
  </div>
  <!-- watch -->
  <div>{{ num }}</div>
  <button @click="num++">按钮</button>
  <div>{{ colors.one }}</div>
  <button @click="colors.one = 'purple'">按钮</button>
  <!-- 同时监听 -->
  <div>{{ qincai }}</div>
  <button @click="qincai = 'nangua'">qingcai按钮</button>
  <div>{{ green.cong }}</div>
  <button @click="green.cong = 'baicai'">cong按钮</button>
</template>
<script>
import { reactive, toRefs,ref, readonly, computed,watch } from 'vue'

export default {
  setup(){
    console.log('setup执行了');
    // reactive函数接收一个复杂类型,实现数据响应式
    const obj = reactive({
      brand:'宝马',
      price:100
    })
    // ref函数接收一个简单类型,返回响应式的对象;这个响应式对象只有一个属性value;在模板中使用ref,会自动解套(即会自动调用value)
    const money = ref(100)
    money.value++;
    // toRefs
    const fruits = reactive({
      yellow:'banana',
      red:'watermelon',
      green:'avocado',
      price:{
        one:111,
        two:222,
        three:333
      }
    })
    // readonly
    const animals = readonly({
      one:'dog',
      two:'cat'
    })
    // computed
    const age = ref(18)
    // computed是一个函数
    // 传入一个函数getter 返回一个不允许修改的计算属性
    // 若改动nextAge 控制台会出现警告,computed value is readonly
    const nextAge = computed(()=>{
      return parseInt(age.value) + 1
    })
    // 传入一个对象,包括get和set,可以创建一个可以修改的计算属性
    const nextAge2 = computed({
      get(){
        return parseInt(age.value) + 2
      },
      set(value){
        age.value = value-2;
        // nextAge2改变,age改变,nextAge也会改变
      }
    })
    // watch
    const num = ref(10)
    watch(num,(value,oldValue)=>{
      // watch监听简单类型
      console.log('num变化了',value);
    })
    const color = reactive({
      colors:{
        one:'red',
        two:'orange',
        three:'yellow',
        four:'green'
      }
    })
    watch(()=>color.colors,(value,oldValue)=>{
      // watch监听复杂类型,colors,深度监听
      console.log('color.colors变化了',value);
    },
    {
      deep:true,
      immediate:true
    }
    )
    // 监听多个值
    const vegetables = reactive({
      qincai:5,
      green:{
        cong:7,
        jiucai:3
      }
    })
    watch([()=>vegetables.qincai,()=>vegetables.green],([qincai,green])=>{
      // 同时监听green中的qingcai、cong
      console.log('数据变化了',qincai,green);
    },{
        deep:true
      })
    return {
      obj,
      money,
      // toRefs:直接展开对象,其中得到的复杂类型的属性仍是响应式的,而得到的简单类型的属性不是响应式的,需要toRefs包裹才行
      ...toRefs(fruits),
      // readonly
      animals,
      age,
      nextAge,
      nextAge2,
      num,
      ...toRefs(color),
      ...toRefs(vegetables) 
    }
  },
  beforeCreate(){
    console.log('beforeCreate执行了');
  }
}
</script>

生命周期钩子函数

vue3.0提供的生命周期钩子函数只能在setup() 期间同步使用

vue3.0生命周期钩子函数与vue2对比:

beforeCreate    --->  使用setup()
created			--->  使用setup()
beforeMount     --->  onBeforeMount
mounted		    --->  onMounted
beforeUpdate    --->  onBeforeUpdate
updated		    --->  onUpdated
beforeDestroy   --->  onBeforeUnmount
destroyed		--->  onUnmounted
errorCaptured   --->  onErrorCaptured     // 错误捕获

依赖注入

Vue3中提供了provide、inject提供依赖注入,用于实现组件之间的通讯。类似于vue2中的provide、inject。

vue3提供的provide、inject可以用于跨多级组件(父传子,父传孙,孙传父,孙传祖父)进行通讯。vue3中仍可以使用props、$emit进行父子间的通讯。

<!-- src/App.vue -->
<template>
    <div>我是父组件: {{ num }}</div>
    <button @click="num++">父传子</button>
    <demo></demo>
</template>
<script>
import {ref,provide} from 'vue';
import demo from './components/demo.vue';
export default {
    components:{
        demo
    },
    setup(){
        // 组件通讯:依赖注入provide 、 inject  (推荐)
        const num = ref(10)
        // 父传子 父传孙
        provide('num',num)   
        // 子传父 孙传父  父提供函数
        const changeMoney = (n)=>{
            num.value -= n;
        }
        provide('changeMoney',changeMoney)
        // 无论父传子还是子传父 ,都是provide 提供
        return {
            num,
            changeMoney
        }
    }
}
</script>
<!-- src/components/demo.vue -->
<template>
   <div class="demo">我是子组件 : {{ num }}</div>
   <demoson></demoson>
</template>
<script>
import {inject} from 'vue'
import demoson from './demoson.vue';
export default {
    components:{
        demoson
    },
    setup() {
        // 组件通讯:依赖注入provide 、 inject 父传子
        const num = inject("num");
        return {
            num
        };
    },
}
</script>
<!-- src/components/demoson.vue -->
<template>
    <div>我是子组件的子组件:{{ num }}</div>
    <button @click="fn">子传父</button>
</template>
<script>
import {inject} from 'vue'
export default {
    setup() {
        // 组件通讯:依赖注入provide 、 inject   父传孙
        const num = inject("num");
        // 孙传父 拿函数调用
        const changeMoney = inject('changeMoney');
        const fn = ()=>{
            changeMoney(5)
        }
        return {
            num,
            fn
        };
    },
}
</script>

模板ref

为了获得对模板内元素或组件实例的引用,我们可以像往常一样在setup()中声明一个ref并返回它。

<template>
    <div ref="root">模板ref</div>
</template>
<script>
import { onMounted,ref } from 'vue';
export default {
    setup(){
        const root = ref(null);
        onMounted(()=>{
            console.log(root.value);
        })
        return {
            root
        }
    }
}
</script>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值