黑丝 足交 vue3 快速初学系列 —— 基础
前边咱们也曾用 vue2 和 react 作念过开辟了黑丝 足交。
从 vue2 升级到 vue3 本钱较大,极端是较大的方法。是以许多公司对旧方法不时使用vue2,新方法则使用 vue3。
有些UI框架,比如ant design vue1.x 使用的 vue2。但咫尺 ant design vue4.x 王人是基于 vue3,示例默许是 TypeScript。比如 table 组件治理。
另外 vue3 官网先容也使用了 TypeScript,举例:反馈式 API:中枢
本篇主要先容:vite 创建vue3方法、组合式api、反馈式数据、计较属性、监听、ref、ts、生命周期、自界说hooks。
vue3 简介Vue.js 3.0,代号海贼王,于2020年9月18日发布 —— v3.0.0 海贼王
主要有如下创新:
性能创新:与 Vue 2 比较,Vue 3 在包大小(通过 Tree-Shaking 减少最多 41%)、启动渲染(快 55%)、更新(快 133%)和内存使用方面推崇出了显著的性能创新(最多减少 54%)。 拥抱 TypeScript:更好的复古 TS。有的公司在 vue2 中就用 TS 了 用于冒失规模问题的新 API:引入了Composition API——一组新的 API,旨在治理大规模应用要领中 Vue 使用的痛点。Composition API 构建在反应性 API 之上,复古雷同于 React hooks 的逻辑组合和重用、更生动的代码组织模式以及比 2.x 基于对象的 API 更可靠的类型估计。 分层里面模块:还公开了较初级别的 API,可解锁许多高等用例 创建 vue3 工程 vue-cli 创建前边咱们用 vue-cli 创建过 vue2 的方法,用其构建 vue3 也雷同,判袂即是招揽 vue3 版块。临了生成的方法结构如下:
图片
Vue CLI 是官方提供的基于 Webpack 的 Vue 器用链,它咫尺处于珍惜模式。咱们无情使用 Vite 动手新的方法,除非你依赖特定的 Webpack 的特色。在大大王人情况下,Vite 将提供更优秀的开辟体验 —— 官网 - 方法脚手架
vite 创建另一种方式是使用 vite。有如下上风:
对 TypeScript、JSX、CSS 等复古开箱即用。 无论应用要领大小若何,王人历久极快的模块热替换(HMR) 极速的就业启动。使用原生 ESM(参考 mdn esm) 文献,无需打包Tip:
vue脚手架(vue-cli) 和创建 react的脚手架(create-react-app)王人是基于 webpack。而 vite 亦然一种构建器用,和 webpack 雷同,也有一些区别,其作家即是 Vue.js 的独创东说念主尤雨溪 HMR 它用于开辟环境,不适用于坐褥环境。更多先容请看这里。 jsx 在学习 react 顶用到过(请看这里),vue 顶用 template 写视图部分,react 用 jsx。在 Vue 3 方法中使用 JSX 时,Vite 会将 JSX 语法编译为 Vue 3 的渲染函数。笔者最初使用 npm create vite@latest 创建方法,我方凭证需要招揽对应预设(比如要 TypeScript or javascript),创建完成后凭证提醒参预方法,安设依赖,腹地启动:
npm install npm run dev
收尾报错:
> 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 版块材干平常运行,当你的包治理器发出劝诫时,请扎眼升级你的 Node 版块 —— vite 官网-搭建第一个 Vite 方法
于是使用 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
凭证提醒切换到 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.0npm create vue
使用 npm create vue@latest 创建 vue3 方法 —— vue3 官网 创建一个 Vue 应用(这里提到 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 √ 请输入方法称号: ... hello_vue3 √ 是否使用 TypeScript 语法? ... 否 / 是 √ 是否启用 JSX 复古? ... 否 / 是 √ 是否引入 Vue Router 进行单页面应用开辟? ... 否 / 是 √ 是否引入 Pinia 用于情状治理? ... 否 / 是 √ 是否引入 Vitest 用于单位测试? ... 否 / 是 √ 是否要引入一款端到端(End to End)测试器用? » 不需要 √ 是否引入 ESLint 用于代码质地检测? ... 否 / 是 正在构建方法 \test-projects\hello_vue3... 方法构建完成,可施行以下高歌: 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
凭证提醒按照依赖,腹地启动方法顺利:
PS \test-projects> cd .\hello_vue3PS \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 helpnpm create vite/vue
npm create vite@latest 和 npm create vue@latest 作用和用途不同,两者效用也不同,总的来说前者创建 Vite 方法,而 npm create vue@latest 是用来创建 Vue.js 方法。
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 devvite 腹地启动格外快
vite 腹地启动格外快。着实按需编译,不在恭候通盘应用编译完成。
用 webpack 腹地启动就业器,需要履历如下几步:entry->route->module->bundle->就业器启动(下图左);而用 vite 启动就业器,就业器启动却从末尾移到起头(下图右)
图片
有点像懒加载,你需要探听哪个路由,就加载哪个,格外快速。
vue3方法目次结构浅析前边咱们用 vite 创建了 hello_vue3 方法。目次结构如下:
图片
咱们先说其他文献,临了在分析src文献夹
extensions.json内容如下:
// .vscode/extensions.json { 'recommendations': ['Vue.volar', 'Vue.vscode-typescript-vue-plugin'] }
保举你安设这两个插件,当你用 vscode 启动方法,点击切换到其他文献上,vscode 右下角就会提醒你是否安设这两个插件。就像这样:
图片
这两个是vue官方给 vscode 提供的插件:
TypeScript Vue Plugin (Volar) Vue Language Features env.d.ts内容如下:
/// <reference types='vite/client' />
是一个在 Vue.js 方法中使用 Vite 构建器用时引入的指示,它的作用是让 TypeScript 编译器或者识别并诳骗 Vite 客户端类型声明文献提供的类型信息,以提供更好的智能编码功能和类型查验复古。
Tip:要是你删除 node_modules 文献夹,你在vscode 中会发现 vite/client 下有红色海浪线。
TypeScript 主要用于处理 JavaScript 代码,况兼在处理模块时,它会关注 .ts、.tsx、.js 和 .jsx 这些与 JavaScript 连系的文献类型。
TypeScript 默许情况下并不会识别或处理像 .txt、.gif 这样的非 TypeScript 文献类型。这个文献的作用即是让 ts 意志 txt、jpg、gif等。
比如你在src 下新建 a.txt、b.ts,然后在 b.ts 中编写:
import a from 'a.txt' console.log(a)
当你清空 env.d.ts,你会发现 import a from 'a.txt'中 a.txt 下有红色海浪线。再次规复 env.d.ts 则好了。
通过 ctrl 鼠标点击参预 vite/client,你会发现 vue 给咱们声明好了咱们需要使用的其他类型文献。比如 txt:
declare module '*.txt' { const src: string export default src }index.html
index.html 这即是咱们的进口文献。内容如下:
<!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>
无需重启就业,页面就显现 a。
其他 tsconfig 文献,ts 竖立连系,不要删,ts 可能会有问题:tsconfig.app.json tsconfig.json tsconfig.node.json
vite.config.ts 方法竖立文献。比如代理、安设插件
public/favicon.ico 页签图标
package.json、package-lock.json
srcsrc 即是咱们编码的场地。
咱们先将 src 中的文献王人删除,咱们我方重新创建。
创建 main.ts 和 App.vue 两个文献。内容如下:
main.ts 是index.html加载的进口文献// src/main.ts import {createApp} from 'vue' // 方法的根 import App from './App.vue' // Vue.js 3.x 顶用于创建和挂载应用 // 创建一个新的 Vue 应用,并将根组件指定为 App。.mount('#app') 将应用挂载到指定的 DOM 元素上 createApp(App).mount('#app')
// src/App.vue <template> <div> 你好 vue3 </div> </template> <!-- 不错指定谈话是 ts,ts中也不错写js --> <script lang='ts'> </script> <style scoped> </style>
浏览器探听,页面显现 你好 vue3。
前边咱们说到 vite 启动后,就业器就已就绪。然后会凭证用户苦求那儿,就会给你加载那儿。
vue3 向下兼容 vue2 语法有些方法使用了 vue3,但写法如故 vue2 —— 不无情这样作念。
为了讲明 vue3 中能写 vue2,笔者在 vue3 方法中写一个 vue2 示例。请看代码:
// 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 // 按钮,点击后,date 后的数字就会变化 change dateoptions Api 和 compositionApi
Vue 2 使用的是选项式 API,而 Vue 3 引入了组合式 API
天然 Vue 3 保举使用组合式 API,但它仍然全王人复古 Vue 2 的选项式 API,以保合手向下兼容性。是以在 Vue 3 中,你不错解放招揽使用选项式 API 或组合式 API 来编写你的组件逻辑。
选项式API有一个过失:新增一个功能,需要分辨在 data、methods、computed、watch等选项中修改代码,要是代码上千,修改或抽取封装这部分功能,有困难。
嘟嘟嘟在线视频免费观看Tip:咱们用 大帅老猿 的图证实以下这个问题
图片
图片
而组合式 api 不错简化这个问题,咱们不错感受下(代码若何收场暂时毋庸管):
图片
图片
Tip: 具体若何拆分,请看本篇临了自界说 hooks章节。
setupsetup 函数是组合式 API 的进口,用于组合组件的逻辑和功能。
setup 详尽最初咱们用 vue2 语法写一个示例:展示名字和日历,点击按钮能窜改日历。代码如下:
<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>
咫尺咱们把 data 和 methods 两个竖立去除,改成 setup 就完成了 vue3 示例的重构
<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); } // 将数据和方法王人交出去 return {name, date, changeDate} } } </script>
setup 是一个方法,平时若何界说变量和方法,这里就若何写,临了将方法和变量王人交出去。
这里其实还有一个问题,点击 button 日历在界面没变,但方法却施行了。这是因为 date 变量不是反馈式的。
Tip:咫尺咱们先说 setup,后头在将反馈式的东西。这里要培育不错使用 ref(这个 ref 和 vue2 中指向元素或组件的ref,不是淹没个东西):
<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); } // 将数据和方法王人交出去
另外 setup 中的 this 是undefined,vue3 动手弱化 this。
临了说一下 setup 施行时机,比 beforeCreat 还早:
name: 'App', beforeCreate() { console.log(1); }, setup() { console.log(2);
先输出 2 再输出 1。
setup 复返函数setup 复返值也不错是一个函数,比如这个:
return () => 'hello vue3'
页面就会显现hello vue3,模板是什么王人不费事了,平直凭证这个函数复返值渲染
这种用法未几,常用的如故复返对象。
setup 和竖立项的连系 setup 能否和 data、method 能否同期写,要是窒碍,以谁为准? 竖立项能否读取setup 中的东西,setup 能否读取setup 中的东西? setup 能和 data、method 同期存在请看示例:
<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 施行礼貌beforeCreate() { console.log('beforeCreate'); }, setup() { console.log('setup'); return () => 'hello vue3' },
setup beforeCreatedata 读取 setup 中的属性
data 或者读取 setup 中的属性。请看示例:
<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 中的数据。就像 vue2 中 data 不错读取 props 中的数据,因为 props 比 data 先启动化 —— initstate 启动化情状。
在 setup 中无法使用 data 中的数据。请看示例,平直报错:
// vscode 报错 let newAge = age, // vscode 报错 - setup 中莫得this let newAge2 = this.age,setup 语法糖
每次王人得写 setup(),还需要将方法或属性交出去,能否只写属性和方法,自动交出去?
方式1setup() { let name = 'pengjiali'; let date = ref(-1); function changeDate() { date.value = new Date().getTime(); console.log('date: ', date); } // 将数据和方法王人交出去 return { name, date, changeDate }; },
有的。将 setup() 有益索求出去。就像这样:
<script lang='ts'> import { ref } from 'vue'; export default { name: 'App', }; </script> <script lang='ts' setup> // 属性和方法自动交出去 let name = 'pengjiali'; let date = ref(-1); function changeDate() { date.value = new Date().getTime(); console.log('date: ', date); } </script>方式2
方式一如故需要写l了两个 <script>,其中一个有益用于界说组件名。
<script lang='ts'> import { ref } from 'vue'; export default { name: 'App', }; </script>
不思写两个 <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: {
临了应用:
-<script lang='ts' setup> <script lang='ts' setup name='App3'>反馈式数据
vue2 中放在 data 中的数据王人是反馈式的,在vue3 中不错通过 ref和reactive 两种方式来处理反馈式。
通过 vue devtools,咱们知说念数据为尊,因为方法放在后头(除了方法,其他的也会放在这里),而数据放在前边。
图片
ref创建基本类型反馈式数据思让哪个数据是反馈式的,就将数据用 ref 包裹一下。
注:这里的 ref 和 vue2 中 ref 不是一个东西
用法请看示例(和凝视):
<template> <section> <p>name: {{ name }}</p> <!-- 不成写 date.value,这里自动会给 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 创建一个基本类型的反馈式数据 let date = ref(-1); // 使用 ref 函数创建的反馈式变量是一个包装过的对象,你需要通过 .value 来探听和修改其值 // 使用 ref 创建变量时,本质上你得到的是一个包含了值的对象,而不是平直的值。因此,在修改这个变量时,你需要通过 .value 来探听和修改本质的值,这样 Vue 材干够正确地跟踪变化并进行反馈。 // 使用 ref 创建的变量必须通过 .value 来探听和修改其值,这是为了确保 Vue 或者正确捕捉变化并更新视图。 function changeDate() { // date: RefImpl {__v_isShallow: false, dep: Map(1), __v_isRef: true, _rawValue: -1, _value: -1} console.log('date: ', date); // 通过 value 修改反馈式数据。 date.value = new Date().getTime(); console.log('date: ', date); } </script>
变量用ref包裹后,类型酿成 RefImpl。需要通过 .value 来探听和修改本质的值。
Tip:跳跃 .value 平直全体替换是不不错的,就像这样:
let count = ref(0) function changeCount(){ // 收效 count = 9 // 失效 // count = ref(9) }
注:模板中不需要 .value
有点像 proxy 的嗅觉:
// 创建一个平庸的对象行动观念对象 let target = { name: 'Alice', age: 30 }; // 创建一个 Proxy 对象,用来代理观念对象 let proxy = new Proxy(target, { // 遏止属性读取的操作 get: function(target, property) { console.log(`Reading ${property} property`); return target[property]; // 复返观念对象相应的属性值 }, // 遏止属性确立的操作 set: function(target, property, value) { console.log(`Setting ${property} property to ${value}`); target[property] = value; // 确立观念对象相应的属性值 } }); // 通过 Proxy 探听和修改属性 // Reading name property // Alice console.log(proxy.name); // 读取属性 // Setting age property to 35 // 35 proxy.age = 35; // 确立属性
Tip:Proxy 是 ES6 引入的一个特色,它允许你创建一个代理对象,不错用来遏止并自界说观念对象的基本操作,比如属性查找、赋值、删除等
reactive 界说反馈式数据诳骗 reactive 将对象转成反馈式,重写上述示例:
<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>
过程 reactive 封装后的对象类型酿成 Proxy。专科术语叫反馈式对象
reactive 相通不错处理数组(数组亦然对象),请看示例:
<ul> <li v-for='(item, index) in ages' :key='index'>{{ item }}</li> </ul> const ages = reactive([18, 19, 20])
对深档次对象也相通起作用。请看示例:
<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() }
不成界说基本类型,比如将字符串转成反馈式,vscode 和浏览器限定台报错如下:
// vscode:类型“string”的参数不成赋给类型“object”的参数。 // 限定台:value cannot be made reactive: #abc const color = reactive('#abc');ref 界说对象类型数据
平直看示例,咱们将 reactive 示例中的 reactive 换成 ref,修改值时加 .value 即可,模板毋庸动。
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 能处理基本类型和对象,然而碰到对象,本质上是摇东说念主了。请看示例:
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 对象的 value 属性,发现了 Proxy(Object),是以骨子上是 reactive 处理了对象
ref vs reactive宏不雅:
ref 能界说基本类型和对象的反馈式数据 reactive 只能用于对象 ref 自动生成 .value写代码时还得记住是 ref 类型,需要增多 .value,好劳苦。不错使用 vscode 插件:
vscode 平直安设 Vue - Official(vscode 提醒 TypeScript Vue Plugin (Volar) 已弃用,使用 Vue - Official 替代)
通过 vscode 确立,勾选 Auto-complete Ref value with .value,并确立 Applies to all profiles
图片
重启后,只消输入 ref 变量,则会自动添加 .value,格外肤浅。
const person = ref({ name: 'pengjiali', date: -1, }) const person2 = reactive({ name: 'pengjiali', date: -1, }) // 输入 person 则会自动添加 .value person.value // 关于非 ref 则不会添加 .value person2reactive 的局限性
reactive 重新分派一个对象,会失去反馈式(可使用 Object.assign 全体替换)。请看示例:
<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() { // 失效 - 反馈性集合已丢失! // person = reactive({name: 'peng', age: 25}) // 失效 // person = {name: 'peng', age: 25} // 平常 Object.assign(person, {name: 'peng', age: 25}) } </script>
Tip: Object.assign() 静态方法将一个或者多个源对象中扫数可陈设的自有属性复制到观念对象,并复返修改后的观念对象。
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 使用场景
由于这些限定,咱们无情使用 ref() 行动声明反馈式情状的主要 API —— 官网 - reactive 局限性
笔者风俗:
需要一个基本类型的反馈式数据,只能使用 ref 对象使用 reactive 要是是表单,使用 ref 会出现许多 .value,不满目 toRefs将一个反馈式对象转机为一个平庸对象,这个平庸对象的每个属性王人是指向源对象相应属性的 ref。每个单独的 ref 王人是使用 toRef() 创建的。
不解白请看底下代码。
比如这段代码:
<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>
我从反馈式对象中解构出 age,然后通过方法修改 age 的值,发现页面没更新:
<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; }
这是因为解构出的 age 不在是反馈式。不错使用 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 用的较少。
比如层级比较深的场景,请看示例:
<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>计较属性
作用和vue2相通,先回忆下 vue2 中的计较属性。写法如下:
computed: { now: function () { } }
改成 vue3 需要使用 computed 方法。就像这样:
let now = computed(() => { return Date.now() })
请看示例:
<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(){ } }) // 触发 set 方法 fullName.value = 'li-si'watch
vue3 中 watch 作用应该和 vue2 中相通,先回忆下vue2 中 watch 写法。就像这样:
new Vue({ data: { message: 'Hello, Vue!' }, watch: { message: function(newValue, oldValue) { console.log('讯息从', oldValue, '变为', newValue); } } });
vue3 中说 watch 只能监视4种数据:
ref界说的数据 reactive 界说的数据 函数复返一个值(getter函数) 一个包含上述内容的数组Tip: vue2 watch 中有deep、immediate、unwatch,下文 vue3 中 watch 也王人有。
ref 基本类型请看示例:
<template> <section> <p>age: {{ age}}</p> <p><button @click='age = 1'>change age</button></p> <p><button @click='stopWatch'>罢手监听 age 变化</button></p> </section> </template> <script lang='ts' setup name='App'> import { ref, watch } from 'vue'; let age = ref(18) // watch(age.value, ... ) 无理写法 let stopWatch = watch(age, (newValue, oldValue) => { console.log('年级从', oldValue, '变为', newValue); }); </script>watch 监视的ref变量,无需增多 .value。安设好vscode 插件,在这种情况下也不会自动给你加 .value。 watch 复返一个函数,施行后将撤消监视。就像 vue2 中的 vm.$watch 方法,复返 unwatch。 ref 对象类型
中枢语法:黑丝 足交
watch(person, (newValue, oldValue) => { }, { deep: true});
比如用 ref 界说一个对象,里面有两个按钮,一个只窜改“年级”,一个窜改通盘 ref 对象。就像这样:
<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(替换通盘对象)</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 相通。时常职责只关怀新值 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>
唯有窜改通盘对象时 watch 中的方法才会施行,而窜改ref对象中的属性,watch 方法却不会施行。
加上一个竖立项,这样窜改通盘对象,以及窜改ref对象中的属性,watch 中的方法王人会施行。
console.log('New person:', newValue); console.log('Old person:', oldValue); - }, ); }, {deep: true});
其实还有一个属性 immediate,启动时就会施行 watch 中的方法。就像这样:
// 全王人替换person,newValue 和 oldValue 不同 // 只替换person中属性,newValue 和 oldValue 相通。时常职责只关怀新值 watch(person, (newValue, oldValue) => { console.log('Person changed'); console.log('New person:', newValue); console.log('Old person:', oldValue); }, { deep: true, immediate: true });reactive
中枢语法:
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(替换通盘对象)</button></p> </section> </template> <script lang='ts' setup name='App'> import { reactive, ref, watch } from 'vue'; let person = reactive({ name: 'pengjiali', age: 18, }); // 默许开启深度监听,而且通过 {deep: false} 也关闭不了 watch(person, (newValue, oldValue) => { console.log('Person changed'); console.log('New person:', newValue); console.log('Old person:', oldValue); }, {deep: false}); function changePerson() { // 不成通盘替换,只能用 Object.assign。不成像 ref.value = {...} Object.assign(person, {name: 'peng', age: 100}) } </script>监视 ref 或 reactive 的对象中的某属性
前边咱们监视的王人是通盘对象,比如咫尺要监视对象中的某个属性。这里分为基本类型和对象类型。
// reactive 和 ref 王人不错用如下神态 // 诳骗 getter。要是需要则增多 deep watch(() => person.car, () => { }, {deep: true})基本类型
就以 reactive 对象为例,平直将监视源改为 person.name vscode 就会出现红色海浪线:
<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>
运行后在浏览器限定台中报错更彰着:
// 无效的监视源:只能是 getter 函数、ref、reactive object、或这些类型的数组 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>
咫尺 person.name 不属于上述4种类型。
将 person.name 改成 getter。代码如下:
Tip:getter 一个函数,复返一个值 —— vue3 watch
watch(() => person.name, (newValue, oldValue) => { console.log('Person changed'); });
这样修改 age 时不会触发 watch,唯有 name 窜改时才会触发 watch。
对象类型这里给 person 界说了一个 jineng 的对象属性,并界说两个按钮,一个会窜改 jineng 的属性,一个窜改通盘妙技。代码如下:
<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>
最初咱们这样写,发现只能监听 jineng 里面的属性窜改:
// 点击`change jineng.a` 施行 // 点击`替换 jineng` 不施行 watch(person.jineng, () => { console.log('watch jineng'); })
Tip:通过打印咱们知说念 person.jineng 类型是Proxy,也即是 reactive 类型,凭证前文咱们知说念 reactive 默许开启深度监视,而且不成通盘替换,之前用的王人是 Object.assign,这里用的是 person.jineng = {a: 'a吃饭', b:'a寝息'}。
改成 getter 发现只能监听替换通盘 jineng:
// 点击`change jineng.a` 不施行 // 点击`替换 jineng` 施行 watch(() => person.jineng, () => { console.log('watch jineng'); })
在 getter 基础上增多 {deep: tree} 则王人能监视到:
// 点击`change jineng.a` 施行 // 点击`替换 jineng` 施行 // 说官网一直王人是用函数 watch(() => person.jineng, () => { console.log('watch jineng'); }, {deep: true})
Tip:将上述示例从 reactive 改成 ref,watch 监视方式如故不变。请看代码:
<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>监视多个
中枢语法:
watch([() => xx.name, () => xx.xx.age], (newValue, oldValue) { // newValue oldValue 是通盘数组 }) // 时常这样写 watch([() => xx.name, () => xx.xx.age], (value) { const [name, age] = value; // ... })
前边几种学罢了,监视多个即是救济。请看示例:
<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>回归
用的较多的有:
ref 基本类型 监视对象中某个属性,反手即是一个函数,无论是基本类型、ref如故reactive王人不错。 watchEffect中枢语法:
// watchEffect 是一个立即施行的反作用操作,因此回调函数会在组件渲染时立即施行一次,并在每个连系反馈式数据变化时再次施行。 watchEffect(() => { // 立即施行 console.log('立即施行'); if(temp.value > 60
热点资讯
- 2024-08-30【NOP-013】銉嶃偑銉戙兂銈广儓銉曘偋銉嗐偅銉冦偡銉er.13 闅c伀瓒娿
- 2024-09-16国产 女同 北京日坛中学与北京中医药大学联手 鼓舞中医药文化进校园
- 2024-10-26巨乳 无码 台基股份跌7.35% 机构净卖出2.42亿元
- 2024-12-16偷拍自拍 遨游汽车上海首飞!小鹏汇天 “陆地航母”飞越陆家嘴
- 2024-12-23偷拍自拍 俄罗斯国防部称乌克兰无东说念主机伏击喀山
- 2024-09-10偷拍自拍 越南富寿省一大桥坍弛 多东说念主落水
相关资讯
- 户外 勾引 16万亿好意思元吊水漂,比2008年金融危急损失更大,足足跨越4倍之
- 自慰 女孩 【东说念主民需要这么的栽培家⑫】潘承洞:治学恒久不懈 治校追求超卓
- 姐妹花 比亚迪深陷供应商降价10%风云,特斯拉再捅一刀?
- 情侣 偷拍 卡牌潮玩风靡年青一代,感性破费倡议方正那时
- 偷拍自拍 麻将听牌张数的狡计面容,再也无须发怵错过和牌的契机了