Vue3入门教程

1. 简介

🔍 深入探索Vue 3

想象一下,你正在用一台老旧的电脑玩最新的3D游戏大作。虽然游戏还能运行,但画面卡顿、加载缓慢,有时候甚至还会出现一些莫名其妙的小错误。这就是Vue 2在面对现代前端开发挑战时可能遇到的状况,而Vue 3就像是那台升级换代后的超级电脑,专为高效运行复杂应用而生。
不是Vue 2不好,而是Vue 3通过一系列创新和优化,为我们带来了更加优秀的开发体验和性能表现。随着前端技术的不断发展,选择Vue 3无疑是一个明智的决定。

虽然Vue3以其先进性吸引着众多开发者的目光,但在正式踏入这一新阶段之前,掌握Vue2作为基石,将是你快速且深入理解Vue3内容的宝贵财富,Vue3虽然带来了许多变革,但它也保留了Vue2中的许多优秀特性,并在此基础上进行了优化与扩展。
其实深入理解一项技术的最佳途径,莫过于直接查阅其官方文档,掌握有效查阅文档的能力,是每位合格程序员不可或缺的知识技能。
点击查阅官网进入学习 Vue.js

2. Vue2 选项式API vsVue3 组合式API

在这里插入图片描述
左为vue2,相对于vue2,vue3特点:代码量变少、分散式维护变成集中维护

3. vue3优势

  • 更容易维护

    • 组合式API
    • 更好的TypeScript支持
  • 更快的速度

    • 重写diff算法
    • 模板编译优化
    • 更高效的组件初始化
  • 更小的体积

    • 良好的TreeSnaking
    • 按需引入
  • 更优的数据响应式

    • proxy

4. 搭建Vue3项目

4.1 create-vue

create-vue是Vue官方新的脚手架工具,底层切换到了 vite (下一代前端工具链),为开发提供极速响应

Vue2是在webpack构建工具基础上,使用脚手架Vue-CLI构建;

Vue3是在vite构建工具基础上,使用create-vue脚手架构建,

4.2 使用create-vue项目

需已安装16.0或更高版本的Node.js

node -v //查看版本号

(1)安装并执行 create-vue

在需要创建项目的目录终端下,执行如下命令:

npm init vue@latest

指令将会安装并执行 create-vue
在这里插入图片描述

(2)启动项目

npm run dev

注:若这里报’vite’ 不是内部或外部命令,也不是可运行的程序或批处理文件。

安装vite后启动项目

npm install vite --save-dev

4.3 vue3项目结构

请添加图片描述
main.js将创建实例进行了封装,vue2使用new()而vue3使用createApp(),createRouter(),createStore()创建实例,将实例进行封装,保证了每个实例的独立封闭性。

在组件文件里,将脚本script和模板template顺序进行调整,且在script上加上setup,表示允许在script中书写组合式API。

对于组件,vue3直接导入使用,相对于vue2的注册效率更高。

对于模板template不再要求唯一根元素。

插件的升级(vue2-vetur vue3-volar 插件提高了开发效率和代码的可读性,在vscode中, volar扩展已弃用。请改用Vue - Official扩展。

5. 组合式API

5.1 组合式API-setup

(1)语法规则

<script>
  export default {
    setup(){
      
    },
    beforeCreate(){
      
    }
  }
</script>

(2)语法特点

特点:setup在beforeCreate钩子之前执行;
注意:setup中的this指向组件实例,其指向undefined,原因是它的创建太早了(beforeCreate钩子之前执行)
使用:setup函数可以书写数据,函数,但需要在末尾以return的形式返回对象,才能给模板使用。

<script>
export default {
  setup(){
    // 数据
    const message='我是vue3'
    // 函数
    const logMessage = ()=>{
        console.log(message)
      }
      //return之后才能使用
      return {
        message,
        logMessage
      }
  }

}
</script>

(3)语法糖

存在问题:每次都要return,太麻烦?
解决方法:使用语法糖:在script标签添加 setup标记,不需要再写导出语句,默认会添加导出语句。在这里插入图片描述

5.2 组合式API-reactive和ref函数

(1)reactive函数

作用:接收对象类型数据的参数传入并返回一个响应式对象
记住:接收的是对象类型数据
使用步骤

<script setup>
// 导入
import {reactive} from 'vue'
// 传入对象参数
const state=reactive({
  count:100
})
const addCount=()=>{
  state.count++
}
</script>

<template>
 <div>{{ state.count }}</div>
 <button @click="addCount">+1</button>
</template>

(2)ref函数

作用:接收简单类型或者对象类型的数据传入并返回一个响应式的对象
本质:是在原有传入数据的基础上,外层包了一个对象,包为复杂对象。
底层:ref函数内部的实现依赖于reactive函数

<script setup>
 // 导入
 import { ref } from 'vue'
 // 执行函数 传入参数 变量接收
 const count = ref(0)
 const setCount = ()=>{
   // 修改数据更新视图必须加上.value
   count.value++
 }
</script>

<template>
  <button @click="setCount">{{count}}</button>
</template>

注意:访问数据,如果是在脚本中访问数据,必须添加.value,在template中,不需要添加。

(3)reactive 对比 ref

  • 两者都是用来生成响应式数据
  • reactive不能处理简单类型的数据
  • ref参数类型支持更好,但是必须通过.value做访问修改
  • ref函数内部的实现依赖于reactive函数。
  • 实际使用,推荐使用ref函数

5.3 组合式API-computed

(1)语法规则


<script setup>

// 导入

import {ref,computed} from 'vue'
// 执行函数 变量接收,在回调函数中return计算值
const computedState=computed(()=>{
  return 基于响应式数据做计算之后的值
})

(2)示例

<script setup>

// 导入

import {ref,computed} from 'vue'
// 原始数据

const list=ref(
  [1,2,3,4,5,6,7,8]
)
// 从list中 过滤出>2 
const filterList = computed(()=>{
  return list.value.filter(item=>item>2)
})
</script>

<template>
<div>{{ filterList }}</div>
<!-- [3,4,5,6,7,8] -->
</template>

5.4 组合式API-watch函数

作用:侦听一个或多个数据的变化,数据变化时执行回调函数
两个额外参数:immediate(立即执行)deep(深度侦听)

(1)侦听单个数据

<script setup>

// 导入watch
  import { ref, watch } from 'vue'

const count=ref(0)
// 调用watch 侦听count的变化
watch(count,(newValue,oldValue)=>{
  console.log(`count变化了,老值为${oldValue},新值为${newValue}`);
})

const addCount=()=>{count.value++}
</script>
<template>
<div></div>

<button @click="addCount">count+1</button>

</template>

结果:点击一次按钮,数据变化了,执行watch函数,故控制台输出:count变化了,老值为0,新值为1

(2)侦听多个数据

侦听多个数据,第一个参数可以改写成数组的写法。

<script setup>

// 导入watch
  import { ref, watch } from 'vue'

const count=ref(0)
const name = ref('zs')
// 调用watch 侦听count的变化

watch([count, name], ([newCount, newName],[oldCount,oldName])=>{
 
    console.log('count或者name变化了'+" "+[newCount,newName],[oldCount,oldName]);

  })
const addCount=()=>{
  count.value++  
}
const setName=()=>{
  name.value='ys'
}
</script>
<template>


<button @click="addCount">count+1</button>
<button @click="setName">修改name</button>

</template>

(3)immediate

在侦听器创建时立即触发回调,响应式数据变化之后继续执行回调。

<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const count = ref(0)
  // 2. 调用watch 侦听变化
  watch(count, (newValue, oldValue)=>{
    console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
  },{
    immediate: true
  })
</script>

(4)deep

通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep.
const ref1=ref(简单类型) 可以直接进行监视
const ref2=ref(复杂类型)监视不到复杂类型内部数据的变化。

const userInfo=ref({
  name:'zs',
  age:19
})
const setUserInfo=()=>{
  userInfo.value.name='ls'
}
// 复杂类型的侦听
watch(userInfo,()=>{
  console.log('数据变化了');
})
</script>
<template>

<button @click="setUserInfo">修改复杂对象</button>

</template>

此时点击按钮,没有触发侦听,需要添加深度deep侦听

// 复杂类型的侦听
watch(userInfo,()=>{
  console.log('数据变化了');
},{deep:true})

(5)精确侦听对象某个属性

可以在不开启deep的前提下,侦听对象具体的某个属性。如有对象userInfo里有age属性,只对age进行侦听

watch(()=>userInfo.value.age,()=>{//侦听回调函数})

5.5 组合式API-生命周期函数

选项式API组合式API
beforeCreate/createdsetup
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted

在这里插入图片描述

(1)基本使用

<scirpt setup>
//导入函数
import { onMounted } from 'vue'
//执行生命周期函数,传入回调
onMounted(()=>{
  // 自定义逻辑
})
</script>

生命周期函数可以执行多次,但会按照顺序依次执行。

<scirpt setup>
import { onMounted } from 'vue'
onMounted(()=>{
  // 自定义逻辑
})

onMounted(()=>{
  // 自定义逻辑
})
</script>

5.6 组合式API-组件通信

(1)父传子

  • 使用步骤
    • 父组件给子组件绑定属性。
    • 子组件内部通过props选项接收。

注意:子组件通过定义使用defineProps编译器宏‘接收传递过来的数据

在这里插入图片描述
defineProps原理:就是编译阶段的一个标识,实际编译器解析时,遇到后会进行编译转换,本质还是props。

(2)子传父

  • 使用步骤:
    • 父组件给子组件标签通过@绑定事件
    • 子组件内部通过emit方法触发事件
      在这里插入图片描述

5.7 组合式API-模板引用

模板引用:通过 ref标识 获取真实的 dom对象或者组件实例对象

(1)基本使用

  • 调用ref函数生成一个ref对象
  • 通过ref标识绑定ref对象到标签
<script setup>
import { onMounted, ref } from "vue"
// 调用ref'函数声明对象
const h1Ref=ref(null)
onMounted(()=>{
  console.log(h1Ref.value);//我是dom标签h1
})
</script>


<template>
  <h1 ref="h1Ref">我是dom标签h1
  </h1>
</template>

(2) defineExpose

默认情况下在 script setup语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose编译宏指定哪些属性和方法容许访问
·

5.8 组合式API-provide和inject

顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
请添加图片描述

(1)跨层传递普通数据

  • 使用步骤:
    • 顶层组件通过provide提供数据
    • 底层组件通过inject函数获取数据
      顶层数据
provide('key',顶层组件中的数据)

底层数据

const message=inject('key')

(2)跨层传递响应式数据

在调用provide函数时,第二个参数设置为ref对象
顶层数据

provide('key',ref对象)

底层数据

const message=inject('key')

(3)跨层传递函数

注意:数据传递遵循谁的数据谁负责的原则
跨层传递函数->子孙后代组件传递可以修改数据的方法
顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件的数据

//顶层组件提供函数
provide('changeCount',(newCount)=>{
count.value=newCount})
}
//底层使用
const changeCount=inject('changeCount')
//底层函数调用
const clickFn=()=>{
changeCount(1000)
}

6. Vue3.3 新特性

6.1 defineOptions

在引入setup 之前,如果要定义 props, emits 可以直接添加属性。

<script>
export default{
  name:'',
  props:'',
 // ...
}
</script>

但添加了setup之后,无法设置平级属性。
所以在 Vue 3.3 中新引入了 defineOptions 宏。顾名思义,主要是用来定义 Options API 的选项。可以用 defineOptions 定义任意的选项, props, emits, expose, slots 除外(因为这些可以使用 defineXXX 来做到)


<script setup>

defineOptions({

  name:'LoginPage',
  inheritAttrs:false
  //...更多自定义属性
})
defineProps({
  count:Number,
  //...
})
//...其他definexxx
</script>

6.2 defineModel

v-model 可以在组件上使用以实现双向绑定。
从 Vue 3.4 开始,推荐的实现方式是使用 defineModel() 宏:
App.vue

<script setup>
import Child from './Child.vue'
import { ref } from 'vue'

const msg = ref('Hello World!')
</script>

<template>
  <h1>{{ msg }}</h1>
  <Child v-model="msg" />
</template>

child.vue

<script setup>
const model = defineModel()
</script>

<template>
  <span>My input</span> <input v-model="model">
</template>

7. Pinia-状态管理工具

Pinia是vuex最新状态管理工具,是vuex的替代品。

  • Pinia优势:
    • 通过了更加简单的API,(去掉了mutation);
    • 提供符合组合式风格的API(和Vue3新语法统一);
    • 去掉了modules的概念,每一个store都是一个独立的模块;
    • 配合TypeScript更加友好,提供可靠的类型判断;

7.1 安装使用

(1)安装Pinia

yarn add pinia
 或者使用 npm
npm install pinia

(2)创建实例
创建一个 pinia 实例 (根 store) 并将其传递给应用:
main.js

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()//创建pinia实例
const app = createApp(App)//创建根实例

app.use(pinia)
app.mount('#app')

7.2 核心概念

(1)定义store

Store 是用 defineStore() 定义的,它的第一个参数要求是一个独一无二的名字。

import { defineStore } from 'pinia'

// 你可以任意命名 `defineStore()` 的返回值,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。
// (比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useAlertsStore = defineStore('alerts', {
  // 其他配置...
})

defineStore() 的第二个参数可接受两类值:Setup 函数Option 对象

  • Option对象
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

可以认为 state 是 store 的数据 (data),getters 是 store 的计算属性 (computed),而 actions 则是方法 (methods)。

  • setup函数

与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})

在 Setup Store 中:ref() 就是 state 属性,computed() 就是 getters,function() 就是 actions。
推荐使用SetUp函数

(2) getters实现

Pinia中的 getters 直接使用 computed函数 进行模拟, 组件中需要使用需要把 getters return出去

  const doubleCount=computed(()=>{
    return  count.value*2
return {
doubleCount
}
  })

(3)action异步实现

方式:异步action函数的写法和组件中获取异步数据的写法完全一致。

  // 异步action
  const getList=async()=>{
    const res=await axios.get('xxx')
    //向外暴露
    return {
    getList
    }
  }

(4)示例使用

新建store/counter.js


import {defineStore} from 'pinia'

import { ref } from 'vue'
// 1.定义store 参数:id,setup函数
export const userCountStore=defineStore('counter',()=>{
  // 2.声明数据 state

  const count=ref(0)
  // 3.声明操作数据的方法 相对于action
  function addCount(){
    count.value++
  }
  // 可声明基于数据派生的计算属性getters
  //Pinia中的 getters 直接使用 computed函数 进行模拟, 组件中需要使用需要把 getters return出去
  const doubleCount=computed(()=>{
    return  count.value*2
  })
 

  // 声明数据2:
  const msg=ref('hello Pinia')
   
  // return暴露使用
  return{
    count,
    msg,
    addCount
  }
})

在组件中使用
App.vue

<script setup>
// 使用pinia
import {userCountStore} from '@/store/counter'
const countStore=userCountStore()
console.log(countStore);//对象

</script>

<template>
<h1> 我是根组件
  {{ countStore.count }}
</h1>
<div>  {{ countStore.msg }}</div>
<button @click="countStore.addCount">+</button>
</template>

7.3 storeToRefs工具函数

定义了store。在组件中进行使用,如果使用解构来使用store里面的数据,那么会存在响应丢失的问题

//响应式丢失,视图不再更新
const{count,msg,doubleCount}=countStore

若想解构之后继续保持数据的响应式,借助storeToRefs工具函数

const{count,msg}=storeToRefs(countStore)

而对于store中的方法,可以直接解构

//作为action的increment可以直接解构使用
const {increment}=store

7.4 Pinia-持久化

之前对数据的持久化,是使用localstorage进行封装,现在pinia支持持久化插件,直接使用。
可查阅插件的官方文档:Pinia持久化插件

(1)基本使用

  • 安装插件
npm i pinia-plugin-persistedstate
  • 将插件添加到 pinia 实例上
    main.js
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
  • 创建 Store 时,将 persist 选项设置为 true。
    组合式
import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useStore = defineStore(
  'main',
  () => {
    const someState = ref('你好 pinia')
    return { someState }
  },
  {
    persist: true,
  },
)

选项式语法

import { defineStore } from 'pinia'

export const useStore = defineStore('main', {
  state: () => {
    return {
      someState: '你好 pinia',
    }
  },
  persist: true,
})

现在,Store 将使用默认持久化配置保存。

(2)持久化配置

插件使用默认持久化配置,也可以进行自定义。

  • 插件的默认配置为:

    • 使用 localStorage 进行存储
    • store.$id 作为 storage 默认的 key
    • 使用 JSON.stringify/JSON.parse 进行序列化/反序列化
    • 整个 state 默认将被持久化
  • 自定义配置
    将一个对象传递给 Store 的 persist 属性来配置持久化。

import { defineStore } from 'pinia'

export const useStore = defineStore('main', {
  state: () => ({
    someState: '你好 pinia',
  }),
  persist: {
    // 在这里进行自定义配置
     key: 'my-custom-key',
     storage: sessionStorage,
    //...配置项查看官网说明
    },
  },
})
  • 自定义配置项
    可查阅官方文档说明:配置说明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值