国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

vue3 快速入門系列 —— 基礎(chǔ)

這篇具有很好參考價(jià)值的文章主要介紹了vue3 快速入門系列 —— 基礎(chǔ)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

vue3 快速入門系列 - 基礎(chǔ)

前面我們已經(jīng)用 vue2 和 react 做過開發(fā)了。

從 vue2 升級(jí)到 vue3 成本較大,特別是較大的項(xiàng)目。所以許多公司對(duì)舊項(xiàng)目繼續(xù)使用vue2,新項(xiàng)目則使用 vue3。

有些UI框架,比如ant design vue1.x 使用的 vue2。但現(xiàn)在 ant design vue4.x 都是基于 vue3,示例默認(rèn)是 TypeScript。比如 table 組件管理。

另外 vue3 官網(wǎng)介紹也使用了 TypeScript,例如:響應(yīng)式 API:核心

本篇主要介紹:vite 創(chuàng)建vue3項(xiàng)目、組合式api、響應(yīng)式數(shù)據(jù)、計(jì)算屬性、監(jiān)聽、ref、ts、生命周期、自定義hooks。

vue3 簡(jiǎn)介

Vue.js 3.0,代號(hào)海賊王,于2020年9月18日發(fā)布 —— v3.0.0 海賊王

主要有如下改進(jìn):

  • 性能改進(jìn):與 Vue 2 相比,Vue 3 在包大?。ㄍㄟ^ Tree-Shaking 減少最多 41%)、初始渲染(快 55%)、更新(快 133%)和內(nèi)存使用方面表現(xiàn)出了顯著的性能改進(jìn)(最多減少 54%)。
  • 擁抱 TypeScript:更好的支持 TS。有的公司在 vue2 中就用 TS 了
  • 用于應(yīng)對(duì)規(guī)模問題的新 API:引入了Composition API——一組新的 API,旨在解決大規(guī)模應(yīng)用程序中 Vue 使用的痛點(diǎn)。Composition API 構(gòu)建在反應(yīng)性 API 之上,支持類似于 React hooks 的邏輯組合和重用、更靈活的代碼組織模式以及比 2.x 基于對(duì)象的 API 更可靠的類型推斷。
  • 分層內(nèi)部模塊:還公開了較低級(jí)別的 API,可解鎖許多高級(jí)用例

創(chuàng)建 vue3 工程

vue-cli 創(chuàng)建

前面我們用 vue-cli 創(chuàng)建過 vue2 的項(xiàng)目,用其構(gòu)建 vue3 也類似,差別就是選擇 vue3 版本。最后生成的項(xiàng)目結(jié)構(gòu)如下:
vue3 快速入門系列 —— 基礎(chǔ)

Vue CLI 是官方提供的基于 Webpack 的 Vue 工具鏈,它現(xiàn)在處于維護(hù)模式。我們建議使用 Vite 開始新的項(xiàng)目,除非你依賴特定的 Webpack 的特性。在大多數(shù)情況下,Vite 將提供更優(yōu)秀的開發(fā)體驗(yàn) —— 官網(wǎng) - 項(xiàng)目腳手架

vite 創(chuàng)建

另一種方式是使用 vite。有如下優(yōu)勢(shì):

  • 對(duì) TypeScript、JSX、CSS 等支持開箱即用。
  • 無論應(yīng)用程序大小如何,都始終極快的模塊熱替換(HMR)
  • 極速的服務(wù)啟動(dòng)。使用原生 ESM(參考 mdn esm) 文件,無需打包

Tip:

  1. vue腳手架(vue-cli) 和創(chuàng)建 react的腳手架(create-react-app)都是基于 webpack。而 vite 也是一種構(gòu)建工具,和 webpack 類似,也有一些區(qū)別,其作者就是 Vue.js 的創(chuàng)始人尤雨溪
  2. HMR 它用于開發(fā)環(huán)境,不適用于生產(chǎn)環(huán)境。更多介紹請(qǐng)看這里。
  3. jsx 在學(xué)習(xí) react 中用到過(請(qǐng)看這里),vue 中用 template 寫視圖部分,react 用 jsx。在 Vue 3 項(xiàng)目中使用 JSX 時(shí),Vite 會(huì)將 JSX 語(yǔ)法編譯為 Vue 3 的渲染函數(shù)。

筆者首先使用 npm create vite@latest 創(chuàng)建項(xiàng)目,自己根據(jù)需要選擇對(duì)應(yīng)預(yù)設(shè)(比如要 TypeScript or javascript),創(chuàng)建完成后根據(jù)提示進(jìn)入項(xiàng)目,安裝依賴,本地啟動(dòng):

npm install
npm run dev

結(jié)果報(bào)錯(cuò):

> vite-vue3@0.0.0 dev \test-projects\vite-vue3
> vite

(node:40312) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected token '??='
    at Loader.moduleStrategy (internal/modules/esm/translators.js:145:18)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:40312) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:40312) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

說是 node 版本可能低了。

Tip: Vite 需要 Node.js 版本 14.18+,16+。然而,有些模板需要依賴更高的 Node 版本才能正常運(yùn)行,當(dāng)你的包管理器發(fā)出警告時(shí),請(qǐng)注意升級(jí)你的 Node 版本 —— vite 官網(wǎng)-搭建第一個(gè) Vite 項(xiàng)目

于是使用 nvm 安裝 18.16.0。步驟如下:

// 目前版本 14.19
PS \test-projects\vite-vue3> node -v
v14.19.0

// nvm 已安裝
PS \test-projects\vite-vue3> nvm -v
1.1.10

// nvm 安裝 18.16.0
PS \test-projects\vite-vue3> nvm install 18.16.0
Downloading node.js version 18.16.0 (64-bit)...
Extracting node and npm...
Complete
npm v9.5.1 installed successfully.


Installation complete. If you want to use this version, type

nvm use 18.16.0

根據(jù)提示切換到 18.16.0

PS \test-projects> nvm use 18.16.0
Now using node v18.16.0 (64-bit)
PS \test-projects> node -v
v18.16.0
npm create vue

使用 npm create vue@latest 創(chuàng)建 vue3 項(xiàng)目 —— vue3 官網(wǎng) 創(chuàng)建一個(gè) Vue 應(yīng)用(這里提到 node 需要18+):

PS \test-projects>  npm create vue@latest
Need to install the following packages:
  create-vue@3.9.2
Ok to proceed? (y) y

Vue.js - The Progressive JavaScript Framework

√ 請(qǐng)輸入項(xiàng)目名稱: ... hello_vue3
√ 是否使用 TypeScript 語(yǔ)法? ... 否 / 是
√ 是否啟用 JSX 支持? ... 否 / 是
√ 是否引入 Vue Router 進(jìn)行單頁(yè)面應(yīng)用開發(fā)? ... 否 / 是
√ 是否引入 Pinia 用于狀態(tài)管理? ... 否 / 是
√ 是否引入 Vitest 用于單元測(cè)試? ... 否 / 是
√ 是否要引入一款端到端(End to End)測(cè)試工具? ? 不需要
√ 是否引入 ESLint 用于代碼質(zhì)量檢測(cè)? ... 否 / 是

正在構(gòu)建項(xiàng)目 \test-projects\hello_vue3...

項(xiàng)目構(gòu)建完成,可執(zhí)行以下命令:

  cd hello_vue3
  npm install
  npm run dev

npm notice
npm notice New major version of npm available! 9.5.1 -> 10.4.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.4.0
npm notice Run npm install -g npm@10.4.0 to update!
npm notice

根據(jù)提示按照依賴,本地啟動(dòng)項(xiàng)目成功:

PS \test-projects> cd .\hello_vue3\
PS \test-projects\hello_vue3> npm install

added 63 packages, and audited 64 packages in 20s

7 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
PS \test-projects\hello_vue3> npm run dev

> hello_vue3@0.0.0 dev
> vite


  VITE v5.1.3  ready in 3045 ms

  ?  Local:   http://localhost:5173/
  ?  Network: use --host to expose
  ?  press h + enter to show help
npm create vite/vue

npm create vite@latest 和 npm create vue@latest 作用和用途不同,兩者效果也不同,總的來說前者創(chuàng)建 Vite 項(xiàng)目,而 npm create vue@latest 是用來創(chuàng)建 Vue.js 項(xiàng)目。

PS \test-projects>  npm create vite@latest
Need to install the following packages:
  create-vite@5.2.0
Ok to proceed? (y) y
√ Project name: ... hello-vue3
√ Select a framework: ? Vue
√ Select a variant: ? TypeScript

Scaffolding project in \test-projects\hello-vue3...

Done. Now run:

  cd hello-vue3
  npm install
  npm run dev
vite 本地啟動(dòng)非???/h5>

vite 本地啟動(dòng)非???。真正按需編譯,不在等待整個(gè)應(yīng)用編譯完成。

用 webpack 本地啟動(dòng)服務(wù)器,需要經(jīng)歷如下幾步:entry->route->module->bundle->服務(wù)器啟動(dòng)(下圖左);而用 vite 啟動(dòng)服務(wù)器,服務(wù)器啟動(dòng)卻從末尾移到開頭(下圖右)
vue3 快速入門系列 —— 基礎(chǔ)

有點(diǎn)像懶加載,你需要訪問哪個(gè)路由,就加載哪個(gè),非??焖?。

vue3項(xiàng)目目錄結(jié)構(gòu)淺析

前面我們用 vite 創(chuàng)建了 hello_vue3 項(xiàng)目。目錄結(jié)構(gòu)如下:
vue3 快速入門系列 —— 基礎(chǔ)

我們先說其他文件,最后在分析src文件夾

extensions.json

內(nèi)容如下:

// .vscode/extensions.json
{
  "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
}

推薦你安裝這兩個(gè)插件,當(dāng)你用 vscode 啟動(dòng)項(xiàng)目,點(diǎn)擊切換到其他文件上,vscode 右下角就會(huì)提示你是否安裝這兩個(gè)插件。就像這樣:

vue3 快速入門系列 —— 基礎(chǔ)

這兩個(gè)是vue官方給 vscode 提供的插件:

  • TypeScript Vue Plugin (Volar)
  • Vue Language Features

env.d.ts

內(nèi)容如下:

/// <reference types="vite/client" />

是一個(gè)在 Vue.js 項(xiàng)目中使用 Vite 構(gòu)建工具時(shí)引入的指令,它的作用是讓 TypeScript 編譯器能夠識(shí)別并利用 Vite 客戶端類型聲明文件提供的類型信息,以提供更好的智能編碼功能和類型檢查支持。

Tip:如果你刪除 node_modules 文件夾,你在vscode 中會(huì)發(fā)現(xiàn) vite/client 下有紅色波浪線。

TypeScript 主要用于處理 JavaScript 代碼,并且在處理模塊時(shí),它會(huì)關(guān)注 .ts、.tsx、.js 和 .jsx 這些與 JavaScript 相關(guān)的文件類型。

TypeScript 默認(rèn)情況下并不會(huì)識(shí)別或處理像 .txt、.gif 這樣的非 TypeScript 文件類型。這個(gè)文件的作用就是讓 ts 認(rèn)識(shí) txt、jpg、gif等。

比如你在src 下新建 a.txt、b.ts,然后在 b.ts 中編寫:

import a from 'a.txt'
console.log(a)

當(dāng)你清空 env.d.ts,你會(huì)發(fā)現(xiàn) import a from 'a.txt'中 a.txt 下有紅色波浪線。再次還原 env.d.ts 則好了。

通過 ctrl + 鼠標(biāo)點(diǎn)擊進(jìn)入 vite/client,你會(huì)發(fā)現(xiàn) vue 給我們聲明好了我們需要使用的其他類型文件。比如 txt:

declare module '*.txt' {
  const src: string
  export default src
}

index.html

index.html 這就是我們的入口文件。內(nèi)容如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

你可以嘗試改成

<body>
  a
</body>

無需重啟服務(wù),頁(yè)面就顯示 a。

其他

  • tsconfig 文件,ts 配置相關(guān),不要?jiǎng)h,ts 可能會(huì)有問題:
tsconfig.app.json
tsconfig.json
tsconfig.node.json
  • vite.config.ts 項(xiàng)目配置文件。比如代理、安裝插件

  • public/favicon.ico 頁(yè)簽圖標(biāo)

  • package.json、package-lock.json

src

src 就是我們編碼的地方。

我們先將 src 中的文件都刪除,我們自己重新創(chuàng)建。

創(chuàng)建 main.ts 和 App.vue 兩個(gè)文件。內(nèi)容如下:

  • main.ts 是index.html加載的入口文件
// src/main.ts
import {createApp} from 'vue'
// 項(xiàng)目的根
import App from './App.vue'

// Vue.js 3.x 中用于創(chuàng)建和掛載應(yīng)用
// 創(chuàng)建一個(gè)新的 Vue 應(yīng)用,并將根組件指定為 App。.mount('#app') 將應(yīng)用掛載到指定的 DOM 元素上
createApp(App).mount('#app')
// src/App.vue
<template>
    <div>
        你好 vue3
    </div>
</template>

<!-- 可以指定語(yǔ)言是 ts,ts中也可以寫js -->
<script lang="ts">

</script>

<style scoped>

</style>

瀏覽器訪問,頁(yè)面顯示 你好 vue3。

前面我們說到 vite 啟動(dòng)后,服務(wù)器就已就緒。然后會(huì)根據(jù)用戶請(qǐng)求哪里,就會(huì)給你加載哪里。

vue3 向下兼容 vue2 語(yǔ)法

有些項(xiàng)目使用了 vue3,但寫法還是 vue2 —— 不建議這么做。

為了證明 vue3 中能寫 vue2,筆者在 vue3 項(xiàng)目中寫一個(gè) vue2 示例。請(qǐng)看代碼:

// src/App.vue
<template>
  <section>
    <p>name: {{ name }}</p>
    <p>date: {{ date }}</p>
    <p><button @click="changeDate">change date</button></p>
  </section>
</template>

<script lang="ts">
export default {
    name: 'App',
    data() {
        return {
          name: 'pengjiali',
          date: -1,
        }
    },
    methods: {
      changeDate() {
        this.date = new Date().getTime();
      }
    }
}
</script>

瀏覽器顯示:

name: pengjiali

date: -1

// 按鈕,點(diǎn)擊后,date 后的數(shù)字就會(huì)變化
change date

options Api 和 compositionApi

Vue 2 使用的是選項(xiàng)式 API,而 Vue 3 引入了組合式 API

雖然 Vue 3 推薦使用組合式 API,但它仍然完全支持 Vue 2 的選項(xiàng)式 API,以保持向下兼容性。所以在 Vue 3 中,你可以自由選擇使用選項(xiàng)式 API 或組合式 API 來編寫你的組件邏輯。

選項(xiàng)式API有一個(gè)缺點(diǎn):新增一個(gè)功能,需要分別在 data、methods、computed、watch等選項(xiàng)中修改代碼,如果代碼上千,修改或抽取封裝這部分功能,有困難。

Tip:我們用 大帥老猿 的圖說明以下這個(gè)問題

vue3 快速入門系列 —— 基礎(chǔ)

vue3 快速入門系列 —— 基礎(chǔ)

而組合式 api 可以簡(jiǎn)化這個(gè)問題,我們可以感受下(代碼如何實(shí)現(xiàn)暫時(shí)不用管):

vue3 快速入門系列 —— 基礎(chǔ)

vue3 快速入門系列 —— 基礎(chǔ)

Tip: 具體如何拆分,請(qǐng)看本篇最后自定義 hooks章節(jié)。

setup

setup 函數(shù)是組合式 API 的入口,用于組合組件的邏輯和功能。

setup 概述

首先我們用 vue2 語(yǔ)法寫一個(gè)示例:展示名字和日期,點(diǎn)擊按鈕能改變?nèi)掌?。代碼如下:

<template>
  <section>
    <p>name: {{ name }}</p>
    <p>date: {{ date }}</p>
    <p><button @click="changeDate">change date</button></p>
  </section>
</template>

<script lang="ts">
export default {
    name: 'App',
    data() {
        return {
          name: 'pengjiali',
          date: -1,
        }
    },
    methods: {
      changeDate() {
        this.date = new Date().getTime();
      }
    }
}
</script>

現(xiàn)在我們把 data 和 methods 兩個(gè)配置去除,改成 setup 就完成了 vue3 示例的重構(gòu)

<template>
不變...
</template>

<script lang="ts">
export default {
    name: 'App',
    setup() {
      let name = 'pengjiali2'
      let date = -1

      function changeDate(){
        date = new Date().getTime();
        console.log('date: ', date);
      }
      // 將數(shù)據(jù)和方法都交出去
      return {name, date, changeDate}
    }
}
</script>

setup 是一個(gè)方法,平時(shí)如何定義變量和方法,這里就怎么寫,最后將方法和變量都交出去。

這里其實(shí)還有一個(gè)問題,點(diǎn)擊 button 日期在界面沒變,但方法卻執(zhí)行了。這是因?yàn)?date 變量不是響應(yīng)式的。

Tip:現(xiàn)在我們先說 setup,后面在將響應(yīng)式的東西。這里要修復(fù)可以使用 ref(這個(gè) ref 和 vue2 中指向元素或組件的ref,不是同一個(gè)東西):

 <script lang="ts">
+import {ref} from 'vue'
 export default {

     name: 'App',
     setup() {
       let name = 'pengjiali2'
-      let date = -1
+      let date = ref(-1)

       function changeDate(){
-        date = new Date().getTime();
+        date.value = new Date().getTime();
         console.log('date: ', date);
       }
       // 將數(shù)據(jù)和方法都交出去

另外 setup 中的 this 是undefined,vue3 開始弱化 this。

最后說一下 setup 執(zhí)行時(shí)機(jī),比 beforeCreat 還早:

  name: "App",
  beforeCreate() {
    console.log(1);
  },
  setup() {
    console.log(2);

先輸出 2 再輸出 1。

setup 返回函數(shù)

setup 返回值也可以是一個(gè)函數(shù),比如這個(gè):

return () => 'hello vue3'

頁(yè)面就會(huì)顯示hello vue3,模板是什么都不重要了,直接根據(jù)這個(gè)函數(shù)返回值渲染

這種用法不多,常用的還是返回對(duì)象。

setup 和配置項(xiàng)的關(guān)系

  • setup 能否和 data、method 能否同時(shí)寫,如果沖突,以誰(shuí)為準(zhǔn)?
  • 配置項(xiàng)能否讀取setup 中的東西,setup 能否讀取setup 中的東西?
setup 能和 data、method 同時(shí)存在

請(qǐng)看示例:

     <p>name: {{ name }}</p>
     <p>date: {{ date }}</p>
+    <p>age: {{ age }}</p>                                                                                                                                                    
+    <p><button @click="sayAge">獲取年齡</button></p>       
   </section>                                                                                                                                                                 
   
 </template>

export default {
   beforeCreate() {
     console.log("1: ", 1);
   },
+  data() {
+    return {
+      age: 18
+    }
+  },
+  methods: {
+    sayAge() {
+      console.log('我的年齡', this.age)
+    }
+  },
   setup() {
     console.log("2: ", 2);
     let name = "pengjiali2";

屬性 age和方法 sayAge 都能正常使用。

setup 和 beforeCreate 執(zhí)行順序

beforeCreate() {
  console.log("beforeCreate");
},
setup() {
  console.log("setup");
  return () => 'hello vue3'
},
setup
beforeCreate

data 讀取 setup 中的屬性

data 能夠讀取 setup 中的屬性。請(qǐng)看示例:

     <p><button @click="sayAge">獲取年齡</button></p>
+    <p>dataName: {{ dataName }}</p>
   </section>
 </template>

export default {
   },
   data() {
     return {
       age: 18,
+      dataName: this.name
     }
   },
   methods: {

setup 是最早的生命周期(將vue2 中beforeCreat、created合并),這里證明 data 中可以取得 setup 中的數(shù)據(jù)。就像 vue2 中 data 可以讀取 props 中的數(shù)據(jù),因?yàn)?props 比 data 先初始化 —— initstate 初始化狀態(tài)。

在 setup 中無法使用 data 中的數(shù)據(jù)。請(qǐng)看示例,直接報(bào)錯(cuò):

// vscode 報(bào)錯(cuò)
let newAge = age,
// vscode 報(bào)錯(cuò) - setup 中沒有this
let newAge2 = this.age,

setup 語(yǔ)法糖

每次都得寫 setup(),還需要將方法或?qū)傩越怀鋈ィ芊裰粚憣傩院头椒?,自?dòng)交出去?

方式1
setup() {
  let name = "pengjiali";
  let date = ref(-1);

  function changeDate() {
    date.value = new Date().getTime();
    console.log("date: ", date);
  }
  // 將數(shù)據(jù)和方法都交出去
  return { name, date, changeDate };
},

有的。將 setup() 專門提取出去。就像這樣:

<script lang="ts">
import { ref } from "vue";
export default {
  name: "App",
};
</script>

<script lang="ts" setup>
// 屬性和方法自動(dòng)交出去

let name = "pengjiali";
let date = ref(-1);

function changeDate() {
  date.value = new Date().getTime();
  console.log("date: ", date);
}
</script>
方式2

方式一還是需要寫l了兩個(gè) <script>,其中一個(gè)專門用于定義組件名。

<script lang="ts">
import { ref } from "vue";
export default {
  name: "App",
};
</script>

不想寫兩個(gè) <script>,可以利用插件 vite-plugin-vue-setup-extend。

先安裝:

PS \test-projects\hello_vue3> npm i vite-plugin-vue-setup-extend -D
npm WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead

added 3 packages, and audited 67 packages in 6s

7 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

修改 vite.config.ts 配置文件:

 import { defineConfig } from 'vite'
 import vue from '@vitejs/plugin-vue'
+import setupExtend from 'vite-plugin-vue-setup-extend'
 
 // https://vitejs.dev/config/
 export default defineConfig({
   plugins: [
     vue(),
+    setupExtend(),
   ],
   resolve: {
     alias: {

最后應(yīng)用:

-<script lang="ts" setup>
+<script lang="ts" setup name="App3">

響應(yīng)式數(shù)據(jù)

vue2 中放在 data 中的數(shù)據(jù)都是響應(yīng)式的,在vue3 中可以通過 ref和reactive 兩種方式來處理響應(yīng)式。

通過 vue devtools,我們知道數(shù)據(jù)為尊,因?yàn)榉椒ǚ旁诤竺妫ǔ朔椒?,其他的也?huì)放在這里),而數(shù)據(jù)放在前面。

vue3 快速入門系列 —— 基礎(chǔ)

ref創(chuàng)建基本類型響應(yīng)式數(shù)據(jù)

想讓哪個(gè)數(shù)據(jù)是響應(yīng)式的,就將數(shù)據(jù)用 ref 包裹一下。

:這里的 ref 和 vue2 中 ref 不是一個(gè)東西

用法請(qǐng)看示例(和注釋):

<template>
  <section>
    <p>name: {{ name }}</p>
    <!-- 不能寫 date.value,這里自動(dòng)會(huì)給 value -->
    <p>date: {{ date }}</p>
    <p><button @click="changeDate">change date</button></p>

  </section>
</template>

<script lang="ts" setup name="App">

import { ref } from "vue";

let name = "pengjiali";
// 通過 ref 創(chuàng)建一個(gè)基本類型的響應(yīng)式數(shù)據(jù)
let date = ref(-1);

// 使用 ref 函數(shù)創(chuàng)建的響應(yīng)式變量是一個(gè)包裝過的對(duì)象,你需要通過 .value 來訪問和修改其值
// 使用 ref 創(chuàng)建變量時(shí),實(shí)際上你得到的是一個(gè)包含了值的對(duì)象,而不是直接的值。因此,在修改這個(gè)變量時(shí),你需要通過 .value 來訪問和修改實(shí)際的值,這樣 Vue 才能夠正確地追蹤變化并進(jìn)行響應(yīng)。
// 使用 ref 創(chuàng)建的變量必須通過 .value 來訪問和修改其值,這是為了確保 Vue 能夠正確捕捉變化并更新視圖。
function changeDate() {
  // date: RefImpl {__v_isShallow: false, dep: Map(1), __v_isRef: true, _rawValue: -1, _value: -1}
  console.log('date: ', date);
  // 通過 value 修改響應(yīng)式數(shù)據(jù)。
  date.value = new Date().getTime();
  console.log("date: ", date);
}
</script>

變量用ref包裹后,類型變成 RefImpl。需要通過 .value 來訪問和修改實(shí)際的值。

Tip:越過 .value 直接整體替換是不可以的,就像這樣:

let count = ref(0)

function changeCount(){
  // 生效
  count = 9

  // 失效
  // count = ref(9)
}

:模板中不需要 .value

有點(diǎn)像 proxy 的感覺:

// 創(chuàng)建一個(gè)普通的對(duì)象作為目標(biāo)對(duì)象
let target = {
  name: 'Alice',
  age: 30
};

// 創(chuàng)建一個(gè) Proxy 對(duì)象,用來代理目標(biāo)對(duì)象
let proxy = new Proxy(target, {
  // 攔截屬性讀取的操作
  get: function(target, property) {
    console.log(`Reading ${property} property`);
    return target[property]; // 返回目標(biāo)對(duì)象相應(yīng)的屬性值
  },
  // 攔截屬性設(shè)置的操作
  set: function(target, property, value) {
    console.log(`Setting ${property} property to ${value}`);
    target[property] = value; // 設(shè)置目標(biāo)對(duì)象相應(yīng)的屬性值
  }
});

// 通過 Proxy 訪問和修改屬性
// Reading name property
// Alice
console.log(proxy.name); // 讀取屬性

// Setting age property to 35
// 35
proxy.age = 35; // 設(shè)置屬性

Tip:Proxy 是 ES6 引入的一個(gè)特性,它允許你創(chuàng)建一個(gè)代理對(duì)象,可以用來攔截并自定義目標(biāo)對(duì)象的基本操作,比如屬性查找、賦值、刪除等

reactive 定義響應(yīng)式數(shù)據(jù)

利用 reactive 將對(duì)象轉(zhuǎn)成響應(yīng)式,重寫上述示例:

<template>
  <section>
    <p>name: {{ person.name }}</p>
    <p>date: {{ person.date }}</p>
    <p><button @click="changeDate">change date</button></p>

  </section>
</template>

<script lang="ts" setup name="App">

import { ref, reactive } from "vue";

const person = reactive({
  name: "pengjiali",
  date: -1,
})
function changeDate() {
  // Proxy(Object)?{name: 'pengjiali', date: -1}
  console.log('person: ', person);
  person.date = new Date().getTime();
}
</script>

經(jīng)過 reactive 封裝后的對(duì)象類型變成 Proxy。專業(yè)術(shù)語(yǔ)叫響應(yīng)式對(duì)象

reactive 同樣可以處理數(shù)組(數(shù)組也是對(duì)象),請(qǐng)看示例:

<ul>
  <li v-for="(item, index) in ages" :key="index">{{ item }}</li>
</ul>

const ages = reactive([18, 19, 20])

對(duì)深層次對(duì)象也同樣起作用。請(qǐng)看示例:

<p>d: {{ obj.a.b.d }} <button @click="changeD">change d</button></p>

let obj = reactive({
  a: {
    b: {
      d: 10
    }
  }
})

function changeD(){
  obj.a.b.d = new Date().getTime()
}

不能定義基本類型,比如將字符串轉(zhuǎn)成響應(yīng)式,vscode 和瀏覽器控制臺(tái)報(bào)錯(cuò)如下:

// vscode:類型“string”的參數(shù)不能賦給類型“object”的參數(shù)。
// 控制臺(tái):value cannot be made reactive: #abc
const color = reactive('#abc');

ref 定義對(duì)象類型數(shù)據(jù)

直接看示例,我們將 reactive 示例中的 reactive 換成 ref,修改值時(shí)加 .value 即可,模板不用動(dòng)。

 import { ref, reactive } from "vue";

-const person = reactive({
+const person = ref({
   name: "pengjiali",
   date: -1,
 })

 function changeDate() {
-  person.date = new Date().getTime();
+  person.value.date = new Date().getTime();
 }

 </script>

能顯示,能修改,一切正常。

雖然 ref 能處理基本類型和對(duì)象,但是遇到對(duì)象,實(shí)際上是搖人了。請(qǐng)看示例:

const person = ref({
  name: "pengjiali",
  date: -1,
})

const count = ref(1)
// count: RefImpl {__v_isShallow: false, dep: undefined, __v_isRef: true, _rawValue: 1, _value: 1}
console.log('count: ', count);
// person:  RefImpl?{__v_isShallow: false, dep: undefined, __v_isRef: true, _rawValue: {…}, _value: Proxy(Object)}
console.log('person: ', person);

查看 person 對(duì)象的 value 屬性,發(fā)現(xiàn)了 Proxy(Object),所以本質(zhì)上是 reactive 處理了對(duì)象

ref vs reactive

宏觀:

  • ref 能定義基本類型和對(duì)象的響應(yīng)式數(shù)據(jù)
  • reactive 只能用于對(duì)象
ref 自動(dòng)生成 .value

寫代碼時(shí)還得記著是 ref 類型,需要增加 .value,好麻煩。可以使用 vscode 插件:

vscode 直接安裝 Vue - Official(vscode 提示 TypeScript Vue Plugin (Volar) 已棄用,使用 Vue - Official 替代)

通過 vscode 設(shè)置,勾選 Auto-complete Ref value with .value,并設(shè)置 Applies to all profiles
vue3 快速入門系列 —— 基礎(chǔ)

重啟后,只要輸入 ref 變量,則會(huì)自動(dòng)添加 .value,非常方便。

const person = ref({
  name: "pengjiali",
  date: -1,
})
const person2 = reactive({
  name: "pengjiali",
  date: -1,
})
// 輸入 person 則會(huì)自動(dòng)添加 .value
person.value

// 對(duì)于非 ref 則不會(huì)添加 .value
person2
reactive 的局限性

reactive 重新分配一個(gè)對(duì)象,會(huì)失去響應(yīng)式(可使用 Object.assign 整體替換)。請(qǐng)看示例:

<template>
  <section>
    <p>name: {{ person.name }}</p>
    <p>age: {{ person.age }}</p>
    <p><button @click="changePerson">change person</button></p>
  </section>
</template>

<script lang="ts" setup name="App">

import { ref, reactive } from "vue";

let person = reactive({
  name: "pengjiali",
  age: 18,
})

function changePerson() {
  // 失效 - 響應(yīng)性連接已丟失!
  // person = reactive({name: 'peng', age: 25})

  // 失效
  // person = {name: 'peng', age: 25}

  // 正常
  Object.assign(person, {name: 'peng', age: 25})
}
</script>

Tip: Object.assign() 靜態(tài)方法將一個(gè)或者多個(gè)源對(duì)象中所有可枚舉的自有屬性復(fù)制到目標(biāo)對(duì)象,并返回修改后的目標(biāo)對(duì)象。

let target = {a: 1, b: 2};
let source1 = {b: 4, c: 5};
let source2 = {c: 6, d: 7};

Object.assign(target, source1, source2);

console.log(target); // 輸出: {a: 1, b: 4, c: 6, d: 7}

如果是 ref,直接替換即可。就像這樣

let person = ref({
  name: "pengjiali",
  age: 18,
})

function changePerson() {
  // 直接替換
  person.value = {name: 'peng', age: 25}
}

ref 和 reactive 使用場(chǎng)景

由于這些限制,我們建議使用 ref() 作為聲明響應(yīng)式狀態(tài)的主要 API —— 官網(wǎng) - reactive 局限性

筆者習(xí)慣:

  • 需要一個(gè)基本類型的響應(yīng)式數(shù)據(jù),只可使用 ref
  • 對(duì)象使用 reactive
  • 如果是表單,使用 ref 會(huì)出現(xiàn)很多 .value,不好看

toRefs

將一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)換為一個(gè)普通對(duì)象,這個(gè)普通對(duì)象的每個(gè)屬性都是指向源對(duì)象相應(yīng)屬性的 ref。每個(gè)單獨(dú)的 ref 都是使用 toRef() 創(chuàng)建的。

不明白請(qǐng)看下面代碼。

比如這段代碼:

<template>
  <section>
    <p>name: {{ person.name }}</p>
    <p>age: {{ person.age }}</p>
    <p><button @click="changePerson">change person</button></p>
  </section>
</template>

<script lang="ts" setup name="App">

import { ref, reactive } from "vue";

let person = reactive({
  name: "pengjiali",
  age: 18,
})

function changePerson() {
  Object.assign(person, {name: 'peng', age: 25})
}
</script>

我從響應(yīng)式對(duì)象中解構(gòu)出 age,然后通過方法修改 age 的值,發(fā)現(xiàn)頁(yè)面沒更新:

+    <p><button @click="changeAge">change age</button></p>      
     <p><button @click="changePerson">change person</button></p>
   </section>
 </template>
let person = reactive({
   age: 18,
 })

+let {age} = person
+
+function changeAge(){
+  age += 1;
+}
+

這是因?yàn)榻鈽?gòu)出的 age 不在是響應(yīng)式??梢允褂?toRefs,就像這樣:

-import { ref, reactive } from "vue";
+import { ref, reactive, toRefs } from "vue";

 let person = reactive({
   name: "pengjiali",
   age: 18,
 })

-let {age} = person
+let {age} = toRefs(person)
+// age: ObjectRefImpl {_object: Proxy(Object), _key: 'age', _defaultValue: undefined, __v_isRef: true}
+console.log('age: ', age);

 function changeAge(){
-  age += 1;
+  age.value += 1;
 }

toRef

說 toRef 用的較少。

比如層級(jí)比較深的場(chǎng)景,請(qǐng)看示例:

<template>
  <h4>姓名:{{ name }}</h4>
  <h4>薪資:{{ salary }}</h4>
  <button @click="name += '!'">修改姓名</button>
  <button @click="salary++">漲薪</button>
</template>

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

let person = reactive({
  name: "張三",
  age: 18,
  job: {
    ja: {
      salary: 20,
    },
  },
});
let name = toRef(person, "name");
let salary = toRef(person.job.ja, "salary");
</script>

計(jì)算屬性

作用和vue2相同,先回憶下 vue2 中的計(jì)算屬性。寫法如下:

computed: {
  now: function () {
    
  }
}

改成 vue3 需要使用 computed 方法。就像這樣:

let now = computed(() => {
  return Date.now()
})

請(qǐng)看示例:

   <section>
     <p>name: {{ person.name }}</p>
     <p>age: {{ person.age }}</p>
-
+    <p>name_age: {{ name_age }}</p>
     <p><button @click="changePerson">change person</button></p>
   </section>
 </template>

 <script lang="ts" setup name="App">
-import { ref, reactive } from "vue";
+import { ref, reactive, computed } from "vue";

 let person = reactive({
   name: "pengjiali",
   age: 18,
 });

+const name_age = computed(() => `${person.name}-${person.age}`)
 function changePerson() {
   Object.assign(person, { name: "peng", age: 25 });
 }

Tip:和 vue2 中類似,set很少用。不多介紹,用法大致如下:


let fullname = computed({
  get(){

  },
  set(){

  }
})

// 觸發(fā) set 方法
fullName.value = 'li-si'

watch

vue3 中 watch 作用應(yīng)該和 vue2 中相同,先回憶下vue2 中 watch 寫法。就像這樣:

new Vue({
  data: {
    message: 'Hello, Vue!'
  },
  watch: {
    message: function(newValue, oldValue) {
      console.log('消息從', oldValue, '變?yōu)?, newValue);
    }
  }
});

vue3 中說 watch 只能監(jiān)視4種數(shù)據(jù):

  • ref定義的數(shù)據(jù)
  • reactive 定義的數(shù)據(jù)
  • 函數(shù)返回一個(gè)值(getter函數(shù))
  • 一個(gè)包含上述內(nèi)容的數(shù)組

Tip: vue2 watch 中有deep、immediate、unwatch,下文 vue3 中 watch 也都有。

ref 基本類型

請(qǐng)看示例:

<template>
  <section>
    <p>age: {{ age}}</p>
    <p><button @click="age += 1">change age</button></p>
    <p><button @click="stopWatch">停止監(jiān)聽 age 變化</button></p>
  </section>
</template>

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

let age = ref(18)
// watch(age.value, ... ) 錯(cuò)誤寫法 
let stopWatch = watch(age, (newValue, oldValue) => {
  console.log('年齡從', oldValue, '變?yōu)?, newValue);
});

</script>
  • watch 監(jiān)視的ref變量,無需增加 .value。安裝好vscode 插件,在這種情況下也不會(huì)自動(dòng)給你加 .value。
  • watch 返回一個(gè)函數(shù),執(zhí)行后將解除監(jiān)視。就像 vue2 中的 vm.$watch 方法,返回 unwatch。

ref 對(duì)象類型

核心語(yǔ)法:

watch(person, (newValue, oldValue) => {

}, { deep: true});

比如用 ref 定義一個(gè)對(duì)象,里面有兩個(gè)按鈕,一個(gè)只改變“年齡”,一個(gè)改變整個(gè) ref 對(duì)象。就像這樣:

<template>
  <section>
    <p>name: {{ person.name }}</p>
    <p>age: {{ person.age }}</p>
    <p><button @click="person.age += 1">change age</button></p>
    <p><button @click="changePerson">change person(替換整個(gè)對(duì)象)</button></p>
  </section>
</template>

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

let person = ref({
  name: "pengjiali",
  age: 18,
});

// 完全替換person,newValue 和 oldValue 不同
// 只替換person中屬性,newValue 和 oldValue 相同。通常工作只關(guān)心新值
watch(person, (newValue, oldValue) => {
      console.log('Person changed');
      console.log('New person:', newValue);
      console.log('Old person:', oldValue);
    }, );

function changePerson() {
  person.value = {name: 'peng', age: 100}
}
</script>

只有改變整個(gè)對(duì)象時(shí) watch 中的方法才會(huì)執(zhí)行,而改變r(jià)ef對(duì)象中的屬性,watch 方法卻不會(huì)執(zhí)行。

加上一個(gè)配置項(xiàng),這樣改變整個(gè)對(duì)象,以及改變r(jià)ef對(duì)象中的屬性,watch 中的方法都會(huì)執(zhí)行。

       console.log('New person:', newValue);
       console.log('Old person:', oldValue);
-    }, );
+    }, {deep: true});

其實(shí)還有一個(gè)屬性 immediate,初始時(shí)就會(huì)執(zhí)行 watch 中的方法。就像這樣:

// 完全替換person,newValue 和 oldValue 不同
// 只替換person中屬性,newValue 和 oldValue 相同。通常工作只關(guān)心新值
watch(person, (newValue, oldValue) => {
      console.log('Person changed');
      console.log('New person:', newValue);
      console.log('Old person:', oldValue);
    }, { deep: true, immediate: true });

reactive

核心語(yǔ)法:

watch(person, (newValue, oldValue) => {
     
});

完整示例:

<template>
  <section>
    <p>name: {{ person.name }}</p>
    <p>age: {{ person.age }}</p>
    <p><button @click="person.age += 1">change age</button></p>
    <p><button @click="changePerson">change person(替換整個(gè)對(duì)象)</button></p>
  </section>
</template>

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

let person = reactive({
  name: "pengjiali",
  age: 18,
});

// 默認(rèn)開啟深度監(jiān)聽,而且通過 {deep: false} 也關(guān)閉不了
watch(person, (newValue, oldValue) => {
      console.log('Person changed');
      console.log('New person:', newValue);
      console.log('Old person:', oldValue);
    }, {deep: false});

function changePerson() {
  // 不能整個(gè)替換,只能用 Object.assign。不能像 ref.value = {...} 
  Object.assign(person, {name: 'peng', age: 100})
}
</script>

監(jiān)視 ref 或 reactive 的對(duì)象中的某屬性

前面我們監(jiān)視的都是整個(gè)對(duì)象,比如現(xiàn)在要監(jiān)視對(duì)象中的某個(gè)屬性。這里分為基本類型對(duì)象類型。

// reactive 和 ref 都可以用如下形式
// 利用 getter。如果需要?jiǎng)t增加 deep
watch(() => person.car, () => {

}, {deep: true})
基本類型

就以 reactive 對(duì)象為例,直接將監(jiān)視源改為 person.name vscode 就會(huì)出現(xiàn)紅色波浪線:

<template>
  <section>
    <p>name: {{ person.name }}</p>
    <p>age: {{ person.age }}</p>
    <p><button @click="person.age += 1">change age</button></p>
    <p><button @click="person.name += '~'">change name</button></p>
  </section>
</template>

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

let person = reactive({
  name: "pengjiali",
  age: 18,
});

-watch(person, (newValue, oldValue) => {
+watch(person.name, (newValue, oldValue) => {
       console.log('Person changed');
 });

</script>

運(yùn)行后在瀏覽器控制臺(tái)中報(bào)錯(cuò)更明顯:

// 無效的監(jiān)視源:只能是 getter 函數(shù)、ref、reactive object、或這些類型的數(shù)組
App.vue:17 [Vue warn]: Invalid watch source:  pengjiali A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types. 
  at <App>

現(xiàn)在 person.name 不屬于上述4種類型。

將 person.name 改成 getter。代碼如下:

Tip:getter 一個(gè)函數(shù),返回一個(gè)值 —— vue3 watch

watch(() => person.name, (newValue, oldValue) => {
      console.log('Person changed');
});

這樣修改 age 時(shí)不會(huì)觸發(fā) watch,只有 name 改變時(shí)才會(huì)觸發(fā) watch。

對(duì)象類型

這里給 person 定義了一個(gè) jineng 的對(duì)象屬性,并定義兩個(gè)按鈕,一個(gè)會(huì)改變 jineng 的屬性,一個(gè)改變整個(gè)技能。代碼如下:

<template>
  <section>
    <p>jineng.a: {{ person.jineng.a }}</p>
    <p><button @click="person.jineng.a += '~'">change jineng.a</button></p>
    <p><button @click="changeJineng">替換 jineng</button></p>

  </section>
</template>

<script lang="ts" setup name="App">
import { reactive, ref, watch } from "vue";
let person = reactive({
  name: "pengjiali",
  age: 18,
  jineng: {
    a: '吃飯',
    b: '睡覺',
  }
});
console.log('person: ', person);
// person.jineng:  Proxy(Object)?{a: '吃飯', b: '睡覺'}
console.log('person.jineng: ', person.jineng);
function changeJineng(){
  person.jineng = {a: 'a吃飯', b:'a睡覺'}
}
</script>

首先我們這么寫,發(fā)現(xiàn)只能監(jiān)聽 jineng 里面的屬性改變:

// 點(diǎn)擊`change jineng.a` 執(zhí)行
// 點(diǎn)擊`替換 jineng` 不執(zhí)行
watch(person.jineng, () => {
  console.log('watch jineng');
})

Tip:通過打印我們知道 person.jineng 類型是Proxy,也就是 reactive 類型,根據(jù)前文我們知道 reactive 默認(rèn)開啟深度監(jiān)視,而且不能整個(gè)替換,之前用的都是 Object.assign,這里用的是 person.jineng = {a: 'a吃飯', b:'a睡覺'}

改成 getter 發(fā)現(xiàn)只能監(jiān)聽替換整個(gè) jineng:

// 點(diǎn)擊`change jineng.a` 不執(zhí)行
// 點(diǎn)擊`替換 jineng` 執(zhí)行
watch(() => person.jineng, () => {
  console.log('watch jineng');
})

在 getter 基礎(chǔ)上增加 {deep: tree} 則都能監(jiān)視到:

// 點(diǎn)擊`change jineng.a` 執(zhí)行
// 點(diǎn)擊`替換 jineng` 執(zhí)行
// 說官網(wǎng)一直都是用函數(shù)
watch(() => person.jineng, () => {
  console.log('watch jineng');
}, {deep: true})

Tip:將上述示例從 reactive 改成 ref,watch 監(jiān)視方式還是不變。請(qǐng)看代碼:

<template>
  <section>
    <p>jineng.a: {{ person.jineng.a }}</p>
    <p><button @click="person.jineng.a += '~'">change jineng.a</button></p>
    <p><button @click="changeJineng">替換 jineng</button></p>

  </section>
</template>

<script lang="ts" setup name="App">
import { reactive, ref, watch } from "vue";
let person = ref({
  name: "pengjiali",
  age: 18,
  jineng: {
    a: '吃飯',
    b: '睡覺',
  }
});
// person.jineng:  Proxy(Object)?{a: '吃飯', b: '睡覺'}
console.log('person.jineng: ', person.value.jineng);
function changeJineng(){
  person.value.jineng = {a: 'a吃飯', b:'a睡覺'}
}

watch(() => person.value.jineng, () => {
  console.log('watch jineng');
}, {deep: true})

</script>

監(jiān)視多個(gè)

核心語(yǔ)法:

watch([() => xx.name, () => xx.xx.age], (newValue, oldValue) {
  // newValue oldValue 是整個(gè)數(shù)組
})

// 通常這么寫
watch([() => xx.name, () => xx.xx.age], (value) {
  const [name, age] = value;
  // ...
})

前面幾種學(xué)完了,監(jiān)視多個(gè)就是贈(zèng)送。請(qǐng)看示例:

<template>
  <section>
    <p>age: {{ person.age }}</p>
    <p>jineng.a: {{ person.jineng.a }}</p>
    <p><button @click="person.age += 1">change age</button></p>
    <p><button @click="person.jineng.a += '~'">change jineng.a</button></p>
    <p><button @click="changeJineng">替換 jineng</button></p>

  </section>
</template>

<script lang="ts" setup name="App">
import { reactive, ref, watch } from "vue"; 
let person = reactive({
  name: "pengjiali",
  age: 18,
  jineng: {
    a: '吃飯',
    b: '睡覺',
  }
});
function changeJineng(){
  person.jineng = {a: 'a吃飯', b:'a睡覺'}
}

watch([() => person.name, () => person.jineng.a], (newVal, oldVal) => {
  console.log('newVal: ', newVal, 'oldVal: ', oldVal);
})
</script>

總結(jié)

用的較多的有:

  • ref 基本類型
  • 監(jiān)視對(duì)象中某個(gè)屬性,反手就是一個(gè)函數(shù),無論是基本類型、ref還是reactive都可以。

watchEffect

核心語(yǔ)法:

// watchEffect 是一個(gè)立即執(zhí)行的副作用操作,因此回調(diào)函數(shù)會(huì)在組件渲染時(shí)立即執(zhí)行一次,并在每個(gè)相關(guān)響應(yīng)式數(shù)據(jù)變化時(shí)再次執(zhí)行。
watchEffect(() => {
   // 立即執(zhí)行
  console.log('立即執(zhí)行');
  if(temp.value > 60 || height.value >80){
    ...
  }
})

比如我需要在”溫度“和”高度“大于20的時(shí)候發(fā)出請(qǐng)求,用 watch 可以這么實(shí)現(xiàn):

<template>
  <section>
    <p>Temperature: {{ temp }}</p>
    <p>Height: {{ height }}</p>
    <button @click="increaseTemp">Increase Temperature by 10</button> <br>
    <button @click="increaseHeight">Increase Height by 10</button>
  </section>
</template>

<script lang="ts" setup name="App">
import { reactive, ref, watch, watchEffect } from "vue";
const temp = ref(0);
const height = ref(0);

const increaseTemp = () => {
  temp.value += 10;
};

const increaseHeight = () => {
  height.value += 10;
};

watch([temp, height], (val) => {
  const [temp, height] = val
  // console.log('val: ', val);
  if (temp > 20 || height > 20) {
    // 在條件滿足時(shí)執(zhí)行副作用代碼
    console.log("watch: Temperature is greater than 20 or height is greater than 20", temp, height);
    // 可以在這里進(jìn)行一些邏輯處理
  }
})
</script>

可以直接替換成 watchEffect(變量直接用就好,框架會(huì)自動(dòng)幫你監(jiān)視),效果和上述例子相同,但代碼量少一些。

watchEffect(() => {
  if (temp.value > 20 || height.value > 20) {
    // 在條件滿足時(shí)執(zhí)行副作用代碼
    console.log("Temperature is greater than 20 or height is greater than 20", temp.value, height.value);
  }
});

Tip:筆者最初測(cè)試 watchEffect 時(shí)遇到了問題。筆者認(rèn)為每次修改 watchEffect 監(jiān)視的變量應(yīng)該都會(huì)執(zhí)行,如果條件有滿足的就應(yīng)該觸發(fā),但沒有。后來用 watch 重寫后發(fā)現(xiàn) watchEffect 又符合期望??赡苁潜镜丨h(huán)境出了點(diǎn)問題。

ref

vue2 中 ref 可以作用于普通dom元素,也可以作用于vue 組件。vue3 中也是這樣。

普通dom元素

請(qǐng)看示例:

<template>
  <section>
    <p ref="pElem">hello</p>
    <button @click="say">click</button>
  </section>
</template>

<script lang="ts" setup name="App">
import { reactive, ref } from "vue";
// 創(chuàng)建一個(gè)容器
const pElem = ref();

function say(){
  // <p>hello</p>
  console.log(pElem.value)
}
</script>

點(diǎn)擊按鈕,將打印 p 元素。

vue 組件

下面我們定義個(gè)組件 Dog.vue,然后在 App.vue 引入。請(qǐng)看示例:

在 Dog 中定義了兩個(gè)變量,通過 defineExpose 將 a 交出去:

// Dog.vue
<template>
  <section>
    dog
  </section>
</template>

<script lang="ts" setup name="Dog">
import { ref } from 'vue';

const a = ref(1)
const b = ref(2)

// 無需引入
defineExpose({a})
</script>

Tip: defineExpose 是一個(gè)用于在組合式 API 中將組件的屬性或方法暴露給父組件的函數(shù)。它可以讓父組件直接訪問子組件內(nèi)部的屬性和方法。

App.vue 中直接引入Dog,無需注冊(cè)即可使用,然后用 ref 指向 Dog,點(diǎn)擊按鈕則能通過 ref 訪問 Dog 暴露出的變量:

// App.vue:
<template>
  <section>
    <Dog ref="box"/>
    <p><button @click="handle1">click</button></p>
  </section>
</template>

<script lang="ts" setup name="App">
// 自動(dòng)幫你注冊(cè)組件
import { ref } from "vue";
// 筆者 vscode 在Dog這里有紅色波浪線,提示:vue3 Module has no default export.Vetur(1192),筆者將 Vetur 插件卸載重啟就好了。
// vetur 可以高亮 .vue 文件,禁用后,筆者安裝 Vue - Official 插件也能高亮 .vue 
import Dog from "./Dog.vue";

const box = ref()

function handle1(){
  // Proxy(Object)?{a: RefImpl, __v_skip: true}
  console.log('box.value: ', box.value);
  // 1
  console.log(box.value.a);
}
</script>

Tip: 這里的 ref 用法和 react 中的 create Ref 用法很像。

簡(jiǎn)單引入 TypeScript

Tip:若不熟悉 ts,可以參考:前端 Typescript 入門

新建 ts 文件,定義兩個(gè)類型:

// src/types/index.ts
export interface Person{
    name: string,
    age: number,
}

export type Persons = Person[]

App.vue 引用 ts 類型:


<script lang="ts" setup name="App">

//  注:需要增加 type,因?yàn)檫@是一個(gè)規(guī)范,不是值
import { type Person, type Persons } from '@/types';

let p2: Person = { name: 'peng', age: 18 }

//   let persons: Person[] = [
//   let persons: Array<Person> = [
let persons: Persons = [
  { name: 'peng', age: 18, id: 3 },
  { name: 'peng2', age: 18 },
  { name: 'peng3', age: 18 }
]

</script>

Tip:由于 Person 是一個(gè)規(guī)范,所以引入時(shí)需要增加 type,告訴自己這是一個(gè)規(guī)范。筆者中間報(bào)錯(cuò):文件 "...../src/types/index.ts" 不在項(xiàng)目 "...../tsconfig.app.json" 的文件列表中。項(xiàng)目必須列出所有文件,或使用 "include" 模式。其實(shí)不用到 tsconfig.app.js 中修改 include 屬性值。

:將類型用于 reactive,可使用如下泛型形式:

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

import {type Person, type Persons} from '@/types';

// 筆者這樣寫不起作用。多了 id 也沒給錯(cuò)誤提示。
let person:Persons = reactive([
  { name: 'peng', age: 18, id: 3},
  { name: 'peng2', age: 18},
  { name: 'peng3', age: 18}
]);

// 調(diào)用函數(shù) reactive 時(shí)增加泛型,會(huì)提示: “id”不在類型“Person”中
let person2 = reactive<Persons>([
  { name: 'peng', age: 18, id: 3},
  { name: 'peng2', age: 18},
  { name: 'peng3', age: 18}
]);

</script>

props

父組件通過 props 給子組件傳遞數(shù)據(jù),而通過事件給子組件傳遞方法。

首先回顧下 vue2 props

核心語(yǔ)法

// 孩子沒脾氣
defineProps(['persons'])

// 接收+限制類型
defineProps<{persons:Persons}>()

// 接收+限制類型+限制必要性 —— 可以不傳
defineProps<{persons?:Persons}>()

// 接收+限制類型+限制必要性+默認(rèn)值
import {withDefaults} from 'vue'
withDefaults(defineProps<{persons?:Persons}>(), {
  persons: () => []
})

defineProps 基本使用

父組件傳遞兩個(gè)屬性:

<template>
  <section>
  <Dog name="peng" :age="18"/>
  </section>
</template>

<script lang="ts" setup name="App">
import Dog from './Dog.vue'

</script>

子組件通過 defineProps 接收(較vue2 中更靈活),可以直接在模板中使用:

<template>
  <section>
    
    <p>props.name:{{ props.name}}</p>
    <!-- props 在模板中直接用即可 -->
    <p>name:{{ name}}</p>
    <p>{{ props.age}}</p>
  </section>
</template>

<script lang="ts" setup name="Dog">
import { ref } from 'vue';
import { defineProps } from 'vue';
const props = defineProps(['name', 'age'])
// props: Proxy(Object)?{name: 'peng', age: 18}
console.log('props: ', props);

if(props.age < 20){
  // 在 Vue 2.x 中,子組件不應(yīng)該直接修改 props。單向數(shù)據(jù)流,如果需要修改可以讓父組件修改
  // props.age += 10;
}


</script>

有兩點(diǎn):

  • defineProps 接收一個(gè)也需要數(shù)組
// 即使一個(gè)也需要使用數(shù)組。
// 沒有與此調(diào)用匹配的重載。
// const props2 = defineProps('name')
  • defineProps 返回值能接收 props
  • 子類中不能修改 props 屬性,否則報(bào)錯(cuò)

傳遞一個(gè)對(duì)象給子組件,核心代碼如下:

// 父組件
 <Dog name="peng" :persons="persons"/>

  let persons = reactive<Persons>([
    { name: 'peng', age: 18},
    { name: 'peng2', age: 19},
    { name: 'peng3', age: 20}
  ]);
// 子組件
<ul>
  <li v-for="(p, index) in persons" :key="index">{{ p.name }} - {{ p.age }}</li>
</ul>


import { defineProps } from 'vue';
defineProps(['persons'])

接收+限制類型+限制必要性+默認(rèn)值

vue3官網(wǎng)針對(duì) ts 寫法介紹如下:

const props = defineProps<{
  foo: string
  bar?: number
}>()

請(qǐng)看示例:

// 子組件
<template>
  <section>
    <ul>
      <li v-for="(p, index) in persons" :key="index">{{ p.name }} - {{ p.age }}</li>
    </ul>
   
  </section>
</template>

<script lang="ts" setup name="Dog">
import { withDefaults } from 'vue';
import {type Persons} from '@/types'

// 只接收。不傳也不報(bào)錯(cuò)
// defineProps(['persons'])

// 接收 persons + 類型。不傳,父組件報(bào)錯(cuò):Missing required prop: "persons" 
// defineProps<{persons:Persons}>()

// 接收 persons + 類型 + 必要性
// 通過 ? 表明可以不傳,父組件不會(huì)報(bào)錯(cuò)
// defineProps<{persons?:Persons}>()
withDefaults(defineProps<{persons?:Persons}>(), {
  // 注:默認(rèn)值需要通過函數(shù)返回,類似 vue2 中數(shù)據(jù)返回也是通過函數(shù)
  // persons: [{ name: '空2', age: 0},]
  persons: () => [{ name: '空', age: 0},]
})
</script>

:defineExpose、defineProps 不需要引入。defineXXx 是宏函數(shù),在vue3 中無需引入(筆者自測(cè)通過)。

生命周期

創(chuàng)建、掛載、更新、銷毀

vue2

4個(gè)階段,8個(gè)鉤子:

  1. 創(chuàng)建階段:
    beforeCreate: 在實(shí)例初始化之后,數(shù)據(jù)觀測(cè) (data observer) 和 event/watcher 事件配置之前被調(diào)用。
    created: 實(shí)例已經(jīng)創(chuàng)建完成之后被調(diào)用。在這一步,實(shí)例已經(jīng)完成了數(shù)據(jù)觀測(cè)、屬性和方法的運(yùn)算,但是尚未開始掛載到頁(yè)面上。

  2. 掛載階段:
    beforeMount: 在掛載開始之前被調(diào)用:相關(guān)的 render 函數(shù)首次被調(diào)用。
    mounted: el 被新創(chuàng)建的 vm.$el 替換,并掛載到實(shí)例上去之后調(diào)用該鉤子。

  3. 更新階段:
    beforeUpdate: 數(shù)據(jù)更新時(shí)調(diào)用,發(fā)生在虛擬 DOM 重新渲染和打補(bǔ)丁之前??梢栽谠撱^子中進(jìn)一步地更改狀態(tài),不會(huì)觸發(fā)附加的重渲染過程。
    updated: 由于數(shù)據(jù)更改導(dǎo)致的虛擬 DOM 重新渲染和打補(bǔ)丁后調(diào)用。

  4. 銷毀階段:
    beforeDestroy: 在實(shí)例銷毀之前調(diào)用。實(shí)例仍然完全可用。
    destroyed: 在實(shí)例銷毀之后調(diào)用。該鉤子被調(diào)用時(shí),Vue 實(shí)例的所有指令都被解綁定,所有事件監(jiān)聽器被移除,所有子實(shí)例也被銷毀。

vue3

和 vue2 類似,4個(gè)階段,8個(gè)鉤子,但稍微有差異:

  • 沒有 beforeCreat、created,由 setup 替代(setup 比 beforeCreat 早)
  • beforeMount 改成 onBeforeMount,mounted 改成 onMounted (加on和駝峰,其他幾個(gè)也這樣)
  • 銷毀改成卸載,和掛載對(duì)應(yīng)
  • 生命周期鉤子函數(shù)語(yǔ)法改為 function onBeforeMount(callback: () => void): void

Tip:這只是最基本的生命周期鉤子,比如路由也會(huì)有,現(xiàn)學(xué)現(xiàn)查即可。

請(qǐng)看示例:

// 子組件
<template>
  <section>
    {{ count }}
    <button @click="count += 1">change count</button>
  </section>
</template>

<script lang="ts" setup name="Dog">
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'

import {ref} from 'vue'

let count = ref(0);

// 沒有 beforeCreat、created,由 setup 替代
console.log('創(chuàng)建')


onBeforeUpdate(() => {
  console.log('更新前');
})
onUpdated(() => {
  console.log('更新后');
})
onBeforeUnmount(() => {
  console.log('卸載前');
})
onUnmounted(() => {
  console.log('卸載后');
})

// 故意將其放在末尾
onBeforeMount(() => {
  console.log('掛載前');
})
onMounted(() => {
  console.log('掛載后');
})
</script>
// 父組件
<template>
  <section>
    <Dog name="peng" v-if="isShow" />
    <button @click="isShow = !isShow">toggle show</button>
  </section>
</template>

<script lang="ts" setup name="App">
import Dog from './Dog.vue'

import { ref } from "vue";

let isShow = ref(true)
</script>

點(diǎn)擊“change count”更新子組件,點(diǎn)擊“toggle show”會(huì)銷毀或創(chuàng)建子組件??刂婆_(tái)輸出:

創(chuàng)建
掛載前
掛載后
更新前
更新后
卸載前
卸載后

vue3 父組件子組件生命周期

在上述示例中,我們給父組件也增加對(duì)應(yīng)的生命周期,然后看一下生命周期鉤子函數(shù)的順序。

// 父組件
<template>
  <section>
    <Dog name="peng" v-if="isShow" />
    <button @click="isShow = !isShow">toggle show</button>
  </section>
</template>

<script lang="ts" setup name="App">
import Dog from './Dog.vue'

import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'
import { ref } from "vue";

let isShow = ref(true)

let count = ref(0);

console.log('父創(chuàng)建')

onBeforeUpdate(() => {
  console.log('父更新前');
})
onUpdated(() => {
  console.log('父更新后');
})
onBeforeUnmount(() => {
  console.log('父卸載前');
})
onUnmounted(() => {
  console.log('父卸載后');
})

// 故意將其放在末尾
onBeforeMount(() => {
  console.log('父掛載前');
})
onMounted(() => {
  console.log('父掛載后');
})

</script>

頁(yè)面初始時(shí)輸出如下(和 vue2 中父元素、子元素的順序一致,甚至和 react 中幾乎相同):

父創(chuàng)建
父掛載前

子創(chuàng)建
子掛載前
子掛載后

父掛載后

點(diǎn)擊“change count”,輸出:子更新前 子更新后

點(diǎn)擊“toggle show”,輸出(和筆者猜測(cè)相同):

父更新前

子卸載前
子卸載后

父更新后

常用生命鉤子

在實(shí)際開發(fā)中,最常用的 Vue2 生命周期鉤子函數(shù)通常是:

  • created: 在實(shí)例創(chuàng)建完成后立即調(diào)用,通常用于進(jìn)行初始化操作、數(shù)據(jù)請(qǐng)求等。
  • mounted: 在實(shí)例掛載到 DOM 后調(diào)用,通常用于執(zhí)行 DOM 操作、訪問第三方庫(kù)等與 DOM 相關(guān)的操作。
  • updated: 當(dāng)數(shù)據(jù)更新導(dǎo)致虛擬 DOM 重新渲染和打補(bǔ)丁后調(diào)用,通常用于在更新后執(zhí)行一些需要基于 DOM 的操作。
  • beforeDestroy: 在實(shí)例銷毀之前調(diào)用,通常用于進(jìn)行一些清理工作、清除定時(shí)器、解綁事件監(jiān)聽器等。

vue3 中常用的和vue2 類似:onMountedonUpdated、onBeforeUnmount。

自定義hooks

在 Vue 3 中,自定義 Hooks 是指開發(fā)者自己定義的可復(fù)用的 Hooks 函數(shù),用于組件邏輯的封裝和復(fù)用。

前面我們說到 vue3 的組合式Api,比如下面這個(gè) vue 包含兩部分的功能,我們利用 hooks 將其拆分:

<template>
  <main>
    <section>
    功能A:
    <p>name: {{ name }}</p>
    <p><button @click="changeName">change name</button></p>
  </section>

  <section>
    功能B:
    <p>age: {{ age }}   放大2倍: {{ bigAge }}</p>
    <p><button @click="changeAge">change age</button></p>
  </section>
  </main>

</template>

<script lang="ts" setup name="App">

import {onMounted, computed} from 'vue'
import { ref } from "vue";

let name = ref('peng');

let age = ref(18);

function changeName(){
  name.value += '~'
}

function changeAge(){
  age.value += 1
}

let bigAge = computed(() => {
  return age.value * 2
})
onMounted(() => {
  age.value += 2
  console.log('B mounted: 將age增加2')
})
</script>

使用 hooks 將變成如下樣子:

  • App.vue
<template>
  <main>
   // 不變
  </main>

</template>

<script lang="ts" setup name="App">
import FunctionA from '@/hooks/FunctionA'
import FunctionB from '@/hooks/FunctionB'

// 引入功能A
const {name, changeName} = FunctionA()
// // 引入功能B
const {age, changeAge, bigAge,} = FunctionB()
</script>
  • FunctionA.ts - 將app.vue 中的<script代碼復(fù)制,放入 function 中,需要導(dǎo)出(export)和暴露(return)
// 所有功能A的數(shù)據(jù)、方法、鉤子、計(jì)算屬性等等
import { ref } from "vue";

// 必須導(dǎo)出
// 用函數(shù)包裹
export default function () {
    let name = ref('peng');

    function changeName() {
        name.value += '~'
    }

    // 暴露出去
    return {name, changeName}
}
  • FunctionB.ts
import { onMounted, computed } from 'vue'
import { ref } from "vue";

export default function () {
    let age = ref(18);

    function changeAge() {
        age.value += 1
    }

    let bigAge = computed(() => {
        return age.value * 2
    })
    onMounted(() => {
        age.value += 2
        console.log('B mounted: 將age增加2')
    })

    return {age, changeAge, bigAge,}
}

這樣運(yùn)行后效果和改動(dòng)之前完全相同。

Tip:自定義 Hooks 函數(shù)本身不能直接包含模板代碼,因?yàn)?Hooks 函數(shù)主要用于組件邏輯的封裝和復(fù)用,并不包含視圖邏輯。

vs vue2中的mixin

相似:組件邏輯的封裝和復(fù)用

不同:

  • 作用域不同:混入的邏輯會(huì)影響到所有使用該 Mixin 的組件,自定義 Hooks 由開發(fā)者有選擇地在組件中引入和使用
  • 組織邏輯方式不同:Mixin 通常將邏輯分散在多個(gè)生命周期鉤子函數(shù)中,自定義 Hooks 將邏輯封裝在一個(gè)函數(shù)中,更加集中

其他

Vue Devtools

vue-devtools是一款基于chrome游覽器的插件,可以用于調(diào)試vue應(yīng)用

有兩種方法安裝,一種是有條件,直接通過 chrome 應(yīng)用商店搜索 vue 安裝

沒有條件的,可以訪問 極簡(jiǎn)插件,搜索,下載,解壓后,打開 chrome 開發(fā)者模式,拖拽到擴(kuò)展插件

vue3 快速入門系列 —— 基礎(chǔ)

三個(gè)花括號(hào)

在使用 vscode 編寫 vue 模板時(shí),有時(shí)會(huì)遇到輸入一個(gè)花括號(hào) {,結(jié)果出現(xiàn)三個(gè)花括號(hào) { }},還得手動(dòng)刪除一個(gè),非常煩人。

解決辦法:打開設(shè)置 -> 搜索Closing Brackets -> 找到 Auto Closing Brackets -> 將 aways 改成beforeWhitespace。請(qǐng)看下圖

vue3 快速入門系列 —— 基礎(chǔ)文章來源地址http://www.zghlxwxcb.cn/news/detail-844266.html

可以多個(gè)根標(biāo)簽

<Person/>
<Person/>
<Person/>

到了這里,關(guān)于vue3 快速入門系列 —— 基礎(chǔ)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Vue3實(shí)戰(zhàn)教程(快速入門)

    Vue3實(shí)戰(zhàn)教程(快速入門)

    本教程通過搭建一個(gè)簡(jiǎn)單項(xiàng)目,幫助讀者快速入門Vue3項(xiàng)目實(shí)戰(zhàn),掌握Vue3、TS、Element Plus、axios等技術(shù)棧。 vue -V 查看vue版本,需要在4.5.1版本之后,即可進(jìn)行以下操作。 (1)使用命令 vue create vue3-elementplus-demo 創(chuàng)建Vue項(xiàng)目。 (2)進(jìn)入選項(xiàng)配置,選擇 Manually select features ,進(jìn)行

    2024年02月03日
    瀏覽(27)
  • Vue3.0快速入門(速查)

    Vue3.0快速入門(速查)

    Vue 也是基于狀態(tài)改變渲染頁(yè)面, Vue 相對(duì)于 React 要好上手一點(diǎn)。有兩種使用 Vue 的方式,可以直接導(dǎo)入 CDN ,也可以直接使用 CLI 創(chuàng)建項(xiàng)目,我們先使用 CDN 導(dǎo)入,學(xué)一些 Vue 的基本概念。 我們?cè)趯?shí)例化Vue這個(gè)對(duì)象的時(shí)候,會(huì)傳入一些參數(shù),例如 攜帶 v- 前綴的都叫做指令 v-i

    2024年02月08日
    瀏覽(16)
  • 快速入門vue3組合式API

    快速入門vue3組合式API

    (創(chuàng)作不易,感謝有你,你的支持,就是我前行的最大動(dòng)力,如果看完對(duì)你有幫助,請(qǐng)留下您的足跡) 目錄 使用create-vue創(chuàng)建項(xiàng)目 熟悉項(xiàng)目目錄和關(guān)鍵文件? 組合式API? setup選項(xiàng) setup選項(xiàng)的寫法和執(zhí)行時(shí)機(jī) script setup?語(yǔ)法糖 reactive和ref函數(shù) reactive() ref() computed watch 偵聽單個(gè)數(shù)據(jù)

    2024年02月12日
    瀏覽(23)
  • electron+vite+vue3 快速入門教程

    electron+vite+vue3 快速入門教程

    本文將介紹electron基本使用和構(gòu)建electron+vite+vue3腳手架開發(fā)項(xiàng)目,帶你快速入門。 Electron 是一個(gè)使用 JavaScript、HTML 和 CSS 構(gòu)建桌面應(yīng)用的框架。 通過將 Chromium 和 Node.js 嵌入到其二進(jìn)制文件中,Electron 允許你維護(hù)一個(gè) JavaScript 代碼庫(kù)并創(chuàng)建可在 Windows、macOS 和 Linux 上運(yùn)行的跨平

    2024年01月19日
    瀏覽(19)
  • open cv快速入門系列---數(shù)字圖像基礎(chǔ)

    open cv快速入門系列---數(shù)字圖像基礎(chǔ)

    目錄 一、數(shù)字圖像基礎(chǔ) 1.1 數(shù)字圖像和圖像單位 1.2 區(qū)分圖片分辨率與屏幕分辨率 1.3 圖像的灰度與灰度級(jí) 1.4 圖像的深度 1.5 二值圖像、灰度圖像與彩色圖像 1.6 通道數(shù) 二、數(shù)字圖像處理 2.1 圖像噪聲及其消除 2.2 數(shù)字圖像處理技術(shù) 2.2.1 圖像變換 2.2.2?圖像增強(qiáng) 2.2.3?圖像分割

    2024年02月11日
    瀏覽(21)
  • uniapp快速入門系列(1)- 概述與基礎(chǔ)知識(shí)

    uniapp快速入門系列(1)- 概述與基礎(chǔ)知識(shí)

    1.1.1 什么是uniapp? uniapp是一款基于Vue.js框架的跨平臺(tái)應(yīng)用開發(fā)框架,它可以讓開發(fā)者使用一套代碼,同時(shí)構(gòu)建多個(gè)平臺(tái)(包括但不限于微信小程序、支付寶小程序、抖音小程序等)的應(yīng)用程序。 在過去,我們可能需要分別使用不同的技術(shù)和工具來開發(fā)不同平臺(tái)的應(yīng)用,但是

    2024年02月07日
    瀏覽(30)
  • 【Python數(shù)據(jù)科學(xué)快速入門系列 | 06】Matplotlib數(shù)據(jù)可視化基礎(chǔ)入門(一)

    【Python數(shù)據(jù)科學(xué)快速入門系列 | 06】Matplotlib數(shù)據(jù)可視化基礎(chǔ)入門(一)

    這是機(jī)器未來的第52篇文章 原文首發(fā)地址:https://robotsfutures.blog.csdn.net/article/details/126899226 【Python數(shù)據(jù)科學(xué)快速入門系列 | 01】Numpy初窺——基礎(chǔ)概念 【Python數(shù)據(jù)科學(xué)快速入門系列 | 02】創(chuàng)建ndarray對(duì)象的十多種方法 【Python數(shù)據(jù)科學(xué)快速入門系列 | 03】玩轉(zhuǎn)數(shù)據(jù)摘?。篘umpy的索引

    2024年02月03日
    瀏覽(54)
  • Vue2基礎(chǔ)一、快速入門

    Vue2基礎(chǔ)一、快速入門

    1、Vue 概念 (1)為什么學(xué) 前端必備技能 崗位多,絕大互聯(lián)網(wǎng)公司都在使用Vue 提高開發(fā)效率 高薪必備技能(Vue2+Vue3) (2)Vue是什么 **概念:**Vue (讀音 /vju?/,類似于 view) 是一套 **構(gòu)建用戶界面 ** 的 漸進(jìn)式 框架 官網(wǎng): https://v2.cn.vuejs.org/ 構(gòu)建用戶界面:基于數(shù)據(jù) 渲染出用

    2024年02月15日
    瀏覽(17)
  • 【Vue 快速入門系列】一文透徹vue中使用axios及跨域問題的解決

    【Vue 快速入門系列】一文透徹vue中使用axios及跨域問題的解決

    Axios(ajax i/o system),是Vue創(chuàng)建者主推的請(qǐng)求發(fā)送方式,因其簡(jiǎn)單的配置與良好的性能被前端愛好者所喜愛。眾所周知,在進(jìn)行網(wǎng)頁(yè)設(shè)計(jì)時(shí)經(jīng)常需要從后端拿數(shù)據(jù),在Web應(yīng)用初期會(huì)將整個(gè)頁(yè)面或者文檔直接拿過來,隨著Web應(yīng)用的發(fā)展,人們對(duì)性能的不斷提升,逐漸向無頁(yè)面刷新

    2024年02月12日
    瀏覽(41)
  • vue系列(三)——手把手教你搭建一個(gè)vue3管理后臺(tái)基礎(chǔ)模板

    vue系列(三)——手把手教你搭建一個(gè)vue3管理后臺(tái)基礎(chǔ)模板

    目錄 一、前言: 二、網(wǎng)站頁(yè)面分析 三、開發(fā)步驟 (一)、安裝element (二)、安裝使用svg插件 (三)、編寫主界面框架代碼 ?(四)、編寫菜單欄 ?(五)、新建頁(yè)面及路由 (六)、定制頁(yè)面標(biāo)簽欄 第一步: 第二步: (七)、修改封裝菜單欄 (八)、添加面包屑 四、結(jié)

    2023年04月24日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包