記事ディレクトリ
Vue 3.0
Vue がもたらすもの
2020 年 9 月 18 日、Vue.js バージョン 3.0 がリリースされました。
- パフォーマンスの向上
- バンドルサイズが 41% 削減
- 初期レンダリングが 55% 高速化、更新レンダリングが 133% 高速化
- メモリが 54% 削減
- ソースコードのアップグレード
- 応答性を実現するには、defineProperty の代わりに Proxy を使用します
- 仮想 DOM と Tree-Shaking の実装を書き直す
- TypeScript の採用
- 新機能
- 合成API(合成API)
- セットアップ構成
- リファレンスとリアクティブ
- 時計と時計効果
- 提供して注入する
- 新しいビルトイン
- 断片
- テレポート
- サスペンス
- その他の変更点
- 新しいライフサイクルフック
- データオプションは常に関数として宣言する必要があります
- v-on 修飾子としての keyCode サポートを削除
- 合成API(合成API)
1.Vue3.0プロジェクトを作成する
ノードのバージョンは 16 以上である必要があります
1. vue-cli を使用して作成します
公式ドキュメント: https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
または
2. vite を使用して作成する
公式ドキュメント: https: //v3.cn.vuejs.org/guide/installation.html#vite
viteの公式Webサイト: https: //vitejs.cn
- ヴァイトとは何ですか?—— 新世代のフロントエンド ビルド ツール
- 利点は次のとおりです。
- 開発環境ではパッケージング作業が不要で素早いコールドスタートが可能
- 軽量で高速なホットリロード (HMR) - より高速な部分リフレッシュ
- アプリケーション全体がコンパイルされるのを待つ必要のない、真のオンデマンド コンパイル
- 従来の建設とバイト建設の比較表
従来の建設モードでは、すべてのリソースをパッケージ化してからオンラインに移行します。
1. プロジェクトを作成する
または次のように:
2. エンジニアリング構造の分析
2.1、main.js
ファイル内
- Vue の導入方法が異なります。
- インスタンス オブジェクトを作成するにはさまざまな方法があります。
2.2.App.vue
ファイル内
ルートタグを許可しない
2. 共通構成 API
構成 API に変換: https://link.juejin.cn/?target=https%3A%2F%2Fv3.cn.vuejs.org%2Fguide%2Fcomposition-api-introduction.html
Vue2 では、構成アイテム スタイルの API であるオプション API を使用します。Vue インスタンスを作成し、その中にデータ、メソッド、ウォッチなどを書き込む必要がある構成オブジェクトを渡す必要があります。Vue3 は次のように提案します。新しいコンポジション API、結合 API、Vue インスタンスを直接作成する必要はありませんが、アプリを作成し、必要に応じて必要な API をインポートして使用します...
セクション 1 と 2 は最初に飛ばしても構いません。この章を読んだ後、この比較表を参照するとよいでしょう。
1. オプション API の問題
Vue2 で従来の (設定 API) を使用する場合、要件を追加または変更する場合は、それぞれOptions API
で変更する必要があります。data
methods
computed
2. 構成APIのメリット
Vue3 では、コードと関数 (組み合わせ) をよりエレガントに整理できます。関連する関数のコードをより整然とした方法でまとめて整理します。
合成API :https://p3-juejin.byreimg.com/tos-cn-i-k3u1fbpfcp/0f9d33731796417c9b8035990e4e52cd~tplv-k3u1fbpfcp-watermark.awebp
https://p3-juejin.byreimg.com/tos-cn-i- k3u1fbpfcp/dbee55cc74ba45e2b7883c78cf7aa691~tplv-k3u1fbpfcp-watermark.awebp
理解できなくてもパニックにならないでください。次の内容を学習した後、戻ってくると理解できるようになります〜
3. 共通の合成 API
①キックオフsetup
1. 理解: Vue3.0 の新しい設定項目、値は関数です。
2. セットアップは、すべての複合 API (組み合わせ API) の「パフォーマンスの段階」です。
3. コンポーネントで使用されるコンポーネント (データ、メソッドなど) をセットアップで構成する必要があります。
4. setup 関数の 2 つの戻り値:
- オブジェクトが返された場合、オブジェクト内のプロパティとメソッドをテンプレートで直接使用できます。(集中!)
- レンダリング関数を返す場合: レンダリング コンテンツをカスタマイズできます。(わかります) (あまり使われません)
<template>
<h1>博主的信息</h1>
<h2>姓名:{
{
name}}</h2>
<h2>年龄:{
{
age}}</h2>
<h2>性别:{
{
gender}}</h2>
<button @click="sayInfo">显示信息</button>
</template>
<script>
// import {
h} from 'vue'
export default {
name: "App",
//此处只是测试一下setup,暂时不考虑响应式的问题。
setup(){
// 数据
let name = "博客zhu虎康"
let age = 18
let gender = "男"
// 方法
function sayInfo(){
alert(`你好${
name},你太厉害了吧`)
}
return {
name,age, gender,sayInfo
}
// return ()=> h('h1','虎康yyds')
}
};
</script>
戻り値がレンダリング関数の場合
、テンプレートに記述したテンプレートは機能せず、ページは記述した h 関数のコンテンツでレンダリングされます。
5、注意点:
Vue2.x 構成と混合しないようにしてください
- セットアップのプロパティとメソッドには、Vue2.x 構成 (データ、メソッド、計算...) でアクセスできます。
- ただし、Vue2.x 構成 (データ、メソッド、計算...) にはセットアップでアクセスできません。
- 名前が重複している場合は、セットアップが優先されます。
setup を非同期関数にすることはできません。戻り値はオブジェクトではなく Promise になり、テンプレートは戻りオブジェクトのプロパティを参照できないからです。(後で Promise インスタンスを返すこともできますが、それには Suspense コンポーネントと非同期コンポーネントの連携が必要です)
上記のデータはレスポンシブデータではありません。変更するとページが更新されなくなります。レスポンシブデータはどのように定義すればよいですか?
②ref関数
RefImpl = 参照 + 実装
1. 機能: 応答データを定義します。
2. 文法:const xxx = ref(initValue)
- 応答データを含む参照オブジェクト (参照オブジェクト、略して ref オブジェクト)を作成します。
- Vue3 には、さまざまなデータ、変数—RefImpl; collection {]—プロキシに対するさまざまな応答があります。
- JS でのデータ操作:
xxx.value
- テンプレート内のデータを読み取ります: .value は必要ありません。直接:
<div>{ {xxx}}</div>
3. 備考:
- 受信データは、基本タイプまたはオブジェクトタイプです。
- データの基本的なタイプ: 応答性は、クラスのゲッターとセッターに依存して完了します (後でソース コードを参照するとわかります)。
- オブジェクト型データ: Vue3.0 の新しい関数 (リアクティブ関数) を内部的に「リクエスト」します。
<template>
<h1>博主的信息</h1>
<h2>姓名:{
{
name }}</h2>
<h2>年龄:{
{
age }}</h2>
<h2>职业: {
{
job.type }}</h2>
<h2>工资:{
{
job.salary }}</h2>
<button @click="sayInfo">显示信息</button>
<button @click="changeInfo">修改信息</button>
</template>
<script>
import {
ref } from "vue";
export default {
name: "App",
setup() {
// 数据
let name = ref("虎康");
let age = ref(18);
let job = ref({
type: "前端工程师",
salary: "30K",
});
// 方法
function sayInfo() {
alert(`你好${
name.value},你太厉害了吧,薪水${
job.value.salary}这么高`);
}
function changeInfo() {
name.value = "三十年后的虎康";
age.value = 48;
job.value.type = "工程师";
job.value.salary = "200K";
}
return {
name,
age,
job,
sayInfo,
changeInfo,
};
},
};
</script>
ソース コードを見ると、ref を呼び出すと RefImpl のインスタンス オブジェクトが返されることがわかりますが、RefImpl クラスにはデータの変更を検出するためのゲッターとセッターが存在します。
function ref(value) {
return createRef(value, false);
}
function createRef(rawValue, shallow) {
if (isRef(rawValue)) {
return rawValue;
}
return new RefImpl(rawValue, shallow);
}
class RefImpl {
constructor(value, _shallow) {
this._shallow = _shallow;
this.dep = undefined;
this.__v_isRef = true;
this._rawValue = _shallow ? value : toRaw(value);
this._value = _shallow ? value : convert(value);
}
get value() {
trackRefValue(this);
return this._value;
}
set value(newVal) {
newVal = this._shallow ? newVal : toRaw(newVal);
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal;
this._value = this._shallow ? newVal : convert(newVal);
triggerRefValue(this, newVal);
}
}
}
③反応機能
1. 機能:応答データのオブジェクト型を定義します(基本型には使用せず、ref 関数を使用します)
2. 構文:const 代理对象= reactive(源对象)
オブジェクト (または配列) を受け取り、プロキシ オブジェクト (Proxy のインスタンス オブジェクト、参照)を返します。プロキシ オブジェクトとして)
3. reactive によって定義されたレスポンシブ データは「深い」です。
4. ES6 ベースの内部プロキシ実装は、プロキシ オブジェクトを通じてソース オブジェクトの内部データを操作します。
<template>
<h1>博主的信息</h1>
<h2>姓名:{
{
yk.name }}</h2>
<h2>年龄:{
{
yk.age }}</h2>
<h2>职业: {
{
yk.job.type }}</h2>
<h2>工资:{
{
yk.job.salary }}</h2>
<h2>爱好:{
{
yk.hobby }}</h2>
<h3>测试数据:{
{
yk.job.a.b.c }}</h3>
<button @click="changeInfo">修改信息</button>
</template>
<script>
import {
reactive } from "vue";
export default {
name: "App",
setup() {
// 数据
let yk = reactive({
name: "虎康",
age: 18,
hobby: ["写博客", "学习", "看书"],
job: {
type: "前端工程师",
salary: "30K",
a: {
b: {
c: 666,
},
},
},
});
// 方法
function changeInfo() {
yk.name = "三十年后的虎康";
yk.age = 48;
yk.job.type = "工程师";
yk.job.salary = "200K";
yk.job.a.b.c = 888;
// 直接通过数组下标修改,可以触发响应式
yk.hobby[0] = "写小说";
}
return {
yk,
changeInfo,
};
},
};
</script>
④ Vue3.0におけるレスポンシブ原理
1. Vue2.xの応答性
1.1. 実装原理
-
オブジェクト タイプ:
Object.defineProperty()
オブジェクトの既存の属性値を読み取り、変更することによってインターセプト (データ ハイジャック) します。 -
配列タイプ: インターセプトは、配列を更新するための一連のメソッドをオーバーライドすることによって実現されます。(配列の変更メソッドはラップされています)。
Object.defineProperty(data, 'count', {
get () {
},
set () {
}
})
1.2. 問題がある
-
属性を追加または削除しても、インターフェイスは更新されません。
-
添字を使用して配列を直接変更すると、インターフェイスは自動的に更新されません。
-
解決
Vue.set、Vue.delete
またはvm.$set、vm.$delete
これらの API を使用します
Vue2 で応答性をシミュレートする
//源数据
let person = {
name:'张三',
age:18
}
//模拟Vue2中实现响应式
let p = {
}
Object.defineProperty(p,'name',{
configurable:true,
get(){
//有人读取name时调用
return person.name
},
set(value){
//有人修改name时调用
console.log('有人修改了name属性,我发现了,我要去更新界面!')
person.name = value
}
})
Object.defineProperty(p,'age',{
get(){
//有人读取age时调用
return person.age
},
set(value){
//有人修改age时调用
console.log('有人修改了age属性,我发现了,我要去更新界面!')
person.age = value
}
})
2. Vue3.0の応答性
上の例では、添字を使用して配列を変更できることがわかります。Vue3 で属性の追加と削除がうまく機能するかどうかをテストしてみましょう
<template>
<h1>博主的信息</h1>
<h2>姓名:{
{
yk.name }}</h2>
<h2 v-show="yk.age">年龄:{
{
yk.age }}</h2>
<h2 v-show="yk.gender">性别:{
{
yk.gender }}</h2>
<h2>职业: {
{
yk.job.type }}</h2>
<h2>工资:{
{
yk.job.salary }}</h2>
<h2>爱好:{
{
yk.hobby }}</h2>
<h3>测试数据:{
{
yk.job.a.b.c }}</h3>
<button @click="changeInfo">修改信息</button>
<button @click="addGender">增加性别</button>
<button @click="deleteAge">删除年龄</button>
</template>
<script>
import {
reactive } from "vue";
export default {
name: "App",
setup() {
// 数据
let yk = reactive({
name: "虎康",
age: 18,
hobby: ["写博客", "学习", "看书"],
job: {
type: "前端工程师",
salary: "30K",
a: {
b: {
c: 666,
},
},
},
});
// 方法
function changeInfo() {
yk.name = "三十年后的";
yk.age = 48;
yk.job.type = "工程师";
yk.job.salary = "200K";
yk.a.b.c = 888;
yk.hobby[0] = "写小说";
}
function addGender() {
yk.gender = "男";
}
function deleteAge() {
delete yk.age;
}
return {
yk,
changeInfo,
addGender,
deleteAge,
};
},
};
</script>
1. 実施原則
- プロキシ経由 (プロキシ): 属性値の読み取りと書き込み、属性の追加、属性の削除など、オブジェクト内の属性の変更をインターセプトします。
- Through Reflect (反射): ソース オブジェクトのプロパティを操作します。
- プロキシとリフレクトについては、MDN ドキュメントで説明されています。
プロキシとリフレクションについては、このブログ投稿を読んで
Vue3 での応答性をシミュレートできます。
let person = {
name:'YK',
age:18
}
const p = new Proxy(person,{
//有人读取p的某个属性时调用
get(target,propName){
console.log(`有人读取了p身上的${
propName}属性`)
// return target[propName]
return Reflect.get(target,propName)
},
//有人修改p的某个属性、或给p追加某个属性时调用
set(target,propName,value){
console.log(`有人修改了p身上的${
propName}属性,我要去更新界面了!`)
// target[propName] = value
return Reflect.set(target,propName,value)
},
//有人删除p的某个属性时调用
deleteProperty(target,propName){
console.log(`有人删除了p身上的${
propName}属性,我要去更新界面了!`)
// return delete target[propName]
return Reflect.deleteProperty(target,propName)
}
})
⑤ リアクティブ vs. リファレンス
定義データの観点からの比較
- ref は、以下を定義するために使用されます。 基本的な型データ。
- reactive は、オブジェクト (または配列) タイプのデータを定義するために使用されます。
- 備考: ref は、オブジェクト (または配列) 型のデータを定義するために使用することもできます。このデータは、内部でリアクティブを通じてプロキシ オブジェクトに自動的に変換されます。
原理的な観点からの比較
- ref は、クラス内のゲッターとセッターを通じて応答性 (データ ハイジャック) を実装します。
- reactive は、Proxy を使用して応答性 (データ ハイジャック) を実装し、Reflect を通じてソース オブジェクト内のデータを操作します。
使用の観点から見ると
- データを操作するにはref:.valueで定義されたデータが必要ですが、データ読み込み時にテンプレートに直接読み込む場合は.valueは必要ありません。
- reactive で定義されるデータ: 操作データと読み取りデータ: どちらも .value は必要ありません。
⑥セットアップ時の2つの注意点
1. セットアップ実行のタイミング
beforeCreate の前に 1 回実行されますが、これは未定義です。
2. パラメータの設定
setup(props,context)
次のように、セットアップによって受け取った 2 つのパラメーター (props、context) をコンソールに出力します。
props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
context:上下文对象
attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs。
slots: 收到的插槽内容, 相当于 this.$slots。
emit: 分发自定义事件的函数, 相当于 this.$emit。
3. テストしてみる
App コンポーネントと HelloWorld コンポーネント
1. 親コンポーネントは属性パラメータを子コンポーネントに渡します。
<template>
<h1>博主的信息</h1>
<HelloWorld msg="你好啊" school="ABC"></HelloWorld>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
name: "App",
components: {
HelloWorld },
};
</script>
<template>
<h2>姓名:{
{
yk.name }}</h2>
</template>
<script>
import {
reactive } from "@vue/reactivity";
export default {
name: "HelloWorld",
props: ['msg'], // 不写全会报警告
setup(props, context) {
let yk = reactive({
name: "YK",
});
console.log('props-----',props);
console.log()
console.log('context.attrs-----', context.attrs)
return {
yk };
},
};
</script>
2. カスタムイベント
<template>
<h1>博主的信息</h1>
<HelloWorld @hello="showHelloMsg"></HelloWorld>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
name: "App",
setup() {
function showHelloMsg(value) {
alert(`你好啊,你触发了hello事件,我收到的参数是:${
value}!`);
}
return {
showHelloMsg };
},
components: {
HelloWorld },
};
</script>
<template>
<h2>姓名:{
{
yk.name }}</h2>
<button @click="test">测试触发一下HelloWorld组件的Hello事件</button>
</template>
<script>
import {
reactive } from "@vue/reactivity";
export default {
name: "HelloWorld",
emits:["hello"], // 不写能执行,但是会报警告
setup(props, context) {
let yk = reactive({
name: "YK",
});
function test() {
context.emit("hello", "**子组件的信息**");
}
return {
yk,test };
},
};
</script>
放出オプションなしで受信した場合、警告が報告されます
スロット
デフォルトのスロット
<template>
<h1>博主的信息</h1>
<HelloWorld>
<span>YK,你好</span>
</HelloWorld>
</template>
<template>
<h2>姓名:{
{
yk.name }}</h2>
<slot></slot>
</template>
名前付きスロット
<template>
<h1>博主的信息</h1>
<HelloWorld>
<template v-slot:ykMsg>
<span>YK,你好</span>
</template>
</HelloWorld>
</template>
<template>
<h2>姓名:{
{
yk.name }}</h2>
<slot name="ykMsg"></slot>
</template>
⑦ 計算特性とモニタリング
1. 計算関数
Vue2.x
の設定機能とcomputed
一致しています。
言葉遣い
私
mport {
computed} from 'vue'
setup(){
...
//计算属性 —— 简写
let fullName = computed(()=>{
return person.firstName + '-' + person.lastName
})
//计算属性 —— 完整
let fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
}
2. 監視関数: watch (誰が監視されているか、(監視コールバック)、{監視設定})
- 完全な書き込み:
次のように、複数の構造を持つデータを直接定義します。ref 定義には .value が必要ですが、reactive は必要ありませんが、{deep:true} をオンにする必要があります
[一般的な使用例 3、モニター]
-
Vue2.x
の設定機能とwatch
一致しています。 -
2 つの小さな「穴」:
1. reactive:oldValueで定義されたレスポンシブデータを監視する場合、oldValueが正しく取得できず、強制的にディープ監視が有効になります(ディープ構成は無効)。
2. reactive で定義された応答データ内の特定の属性 (オブジェクトである必要があります) を監視する場合、深い設定が有効になります。 -
ケース 1: ref で定義された応答データを監視する
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{
immediate:true})
オブジェクトが ref で定義されている場合
watch(person.value,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
})
またはこれ
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{
deep: true})
- ケース 2: 複数の参照によって定義された応答データを監視し、それらを配列に配置して統合監視を行う
//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变化了',newValue,oldValue)
})
- ケース 3: reactive で定義されたレスポンシブ データを監視する[通常はケース 3 の開発を使用します]
ウォッチが reactive で定義された reactive データを監視している場合、oldValue を正しく取得できません。!
ウォッチが reactive で定義されたリアクティブ データを監視する場合、詳細な監視が強制的に有効になります。
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{
immediate:true,deep:false}) //此处的deep配置不再奏效
- 状況 4: reactive で定義された応答データ内の属性を監視する
//情况四:监视reactive定义的响应式数据对象中的某个属性
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{
immediate:true,deep:true})
- 状況 5: reactive で定義された応答データ内の特定の属性を監視し、それらを配列に配置して統合監視を行う
//情况五:监视reactive定义的响应式数据中的某些属性
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{
immediate:true,deep:true})
- 特別なケース
//特殊情况
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{
deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
ウォッチの 3 番目の属性
- flash:'pre' : デフォルトは pre で、dom 更新前に実行されます。
- flash:'post': dom 更新後に実行されます
- flash:'sync': dom update と同期して実行します。
時計のクリアコールバック
監視を停止します。監視を停止したい場合は、次の stop 関数を呼び出すことができます。watch
自体は関数です。つまり、関数を返します。
const stop = watch(num,
(newValue,oldValue)=>{
console.log(newValue,oldValue)
})
3.watchEffect関数
-
監視のルーチンは、監視の属性だけでなく、監視のコールバックも指定します。
-
watchEffect のルーチンは、どの属性を監視するか、どの属性を監視コールバックで使用するか、次にどの属性を監視するかを指定する必要はありません。
-
watchEffect は計算に少し似ています。
- ただし、computed は計算値(コールバック関数の戻り値)に注目するため、戻り値を記述する必要があります。
- また、watchEffect は処理 (コールバック関数の関数本体) に注目するため、戻り値を記述する必要がありません。
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(()=>{
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回调执行了')
})
⑧ライフサイクル
1. Vue2.x のライフサイクル フックは Vue3.0 でも引き続き使用できますが、そのうち 2 つのフックの名前が変更されました。
- beforeDestroy は beforeUnmount に名前変更されました
- destroy は名前を unmount に変更しました
ライフサイクル フックは、構成されたアイテムの形式で直接使用することも、可能な限り統一された API の組み合わせの形式で使用することもできます。一般的に、結合された API のフックは、構成アイテムのフックより前に実行されます。結合された API のフックの変更
2. Vue3.0 では、コンポジション API の形式でライフサイクル フックも提供しています。これは、次の Vue2.x のフックに対応します。
コンポジション API は、統一的に使用する必要がある API を導入し、setup() で呼び出します。
beforeCreate
===>setup()
created
=======>setup()
beforeMount
===>onBeforeMount
mounted
=======>onMounted
beforeUpdate
===>onBeforeUpdate
updated
=======>onUpdated
beforeUnmount
==>onBeforeUnmount
unmounted
=====>onUnmounted
⑨ カスタムフック機能(強調)
-
フックとは何ですか? —— 基本的には、セットアップ関数で使用されるComposition APIをカプセル化する関数です。
-
vue2.x の mixin に似ています。
-
カスタム フックの利点: コードの再利用により、セットアップのロジックがより明確になり、理解しやすくなります。
フックフォルダーを作成し、その中にファイルを作成します
/hooks/usePoint.js
import {
reactive, onMounted, onBeforeUnmount } from "vue";
export default function() {
//实现鼠标“打点”相关的数据
let point = reactive({
x: 0,
y: 0,
});
//实现鼠标“打点”相关的方法
function savePoint(event) {
point.x = event.pageX;
point.y = event.pageY;
console.log(event.pageX, event.pageY);
}
//实现鼠标“打点”相关的生命周期钩子
onMounted(() => {
window.addEventListener("click", savePoint);
});
onBeforeUnmount(() => {
window.removeEventListener("click", savePoint);
});
return point;
}
コンポーネントで使用される
<template>
<h2>我是HelloWorld组件</h2>
<h2>当前点击时鼠标的坐标为:x:{
{
point.x}},y:{
{
point.y}}</h2>
</template>
<script>
import usePoint from '../hooks/usePoint'
export default {
name:'HelloWorld',
setup(){
const point = usePoint()
return {
point}
}
}
</script>
⑩ toRef
1.機能:
値が別のオブジェクトのプロパティを指す ref オブジェクトを作成します。
2. 文法:
const name = toRef(person,'name')
3. アプリケーション:
外部使用のみを目的としてリアクティブ オブジェクトにプロパティを提供する場合。
4. 拡張:
toRefs
toRef
関数と一致していますが、複数の ref オブジェクトをバッチで作成できます。構文は次のとおりです。toRefs(person)
<template>
<h4>{
{
person}}</h4>
<h2>姓名:{
{
name}}</h2>
<h2>年龄:{
{
age}}</h2>
<h2>薪资:{
{
job.j1.salary}}K</h2>
<button @click="name+='~'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">涨薪</button>
</template>
<script>
import {
ref,reactive,toRef,toRefs} from 'vue'
export default {
name: 'Demo',
setup(){
//数据
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
// const name1 = person.name
// console.log('%%%',name1)
// const name2 = toRef(person,'name')
// console.log('####',name2)
const x = toRefs(person)
console.log('******',x)
return {
person,
// name:toRef(person,'name'),
// age:toRef(person,'age'),
// salary:toRef(person.job.j1,'salary'),
...toRefs(person)
}
}
}
</script>
5. その他の合成 API
1.shallowReactiveとshallowRef
-
ShallowReactive: オブジェクトの最も外側のプロパティの応答 (浅い応答) のみを処理します。
-
shallowRef: オブジェクトの応答ではなく、基本的なデータ型の応答のみを処理します。
- いつ使用しますか?
- オブジェクトデータがある場合、構造は比較的深いですが、外側の属性のみが変化します ===>shallowReactive。
- オブジェクト データがある場合、後続の関数はオブジェクト内のプロパティを変更しませんが、===> ShallowRef を置き換える新しいオブジェクトを生成します。
2. readonly とshallowReadonly
- readonly: リアクティブ データを読み取り専用 (ディープ読み取り専用) にします。
- shallowReadonly:レスポンシブデータを読み取り専用(浅い読み取り専用)にし、1層目のデータのみ変更可能、2層目以降のデータは変更可能とします。
- 適用シナリオ: データの変更が予想されない場合。
3. toRaw と markRaw
-
toRaw
- 機能:
reactive
ボットによって生成された応答オブジェクトを通常のオブジェクトに変換します。 - 使用シナリオ: 応答オブジェクトに対応する共通オブジェクトを読み取るために使用されます。この共通オブジェクトに対するすべての操作によってページが更新されることはありません。
- 機能:
-
マーク生
-
役割: オブジェクトが再び応答オブジェクトにならないように、オブジェクトにマークを付けます。
アプリケーションシナリオ:- 複雑なサードパーティ ライブラリなど、一部の値はレスポンシブに設定すべきではありません。
- リアクティブ変換をスキップすると、不変のデータ ソースを含む大きなリストをレンダリングする際のパフォーマンスが向上します。
-
4.カスタム参照
役割: 依存関係の追跡と更新トリガーを明示的に制御するカスタム ref を作成します。
手ぶれ補正効果を実現
<template>
<input type="text" v-model="keyWord" />
<h3>{
{
keyWord }}</h3>
</template>
<script>
import {
customRef } from "vue";
export default {
name: "App",
setup() {
//自定义一个ref——名为:myRef
function myRef(value, delay) {
let timer;
// track, trigger相符相成,在get、set中结合使用
return customRef((track, trigger) => {
return {
get() {
console.log(`有人从myRef这个容器中读取数据了,我把${
value}给他了`);
track(); // 通知Vue追踪value的变化(提前和get商量一下,让他认为这个value是有用的)
return value;
},
set(newValue) {
console.log(`有人把myRef这个容器中数据改为了:${
newValue}`);
clearTimeout(timer);
timer = setTimeout(() => {
value = newValue;
trigger(); // 通知Vue去重新解析模板
}, delay);
},
};
});
}
// let keyWord = ref('hello') //使用Vue提供的ref
let keyWord = myRef("hello", 500); //使用程序员自定义的ref
return {
keyWord };
},
};
</script>
5.provide
とinject
-
役割: 祖先コンポーネントと子孫コンポーネント間の通信を実現します。
-
ルーチン: 親コンポーネントには
provide
データを提供するオプションがあり、子孫コンポーネントにはinject
このデータの使用を開始するオプションがあります。 -
具体的には次のように書かれています。
-
親コンポーネント内:
setup(){ ...... let car = reactive({ name:'奔驰',price:'40万'}) provide('car',car) // 给自己的后代组件传递数据 ...... }
-
子孫コンポーネント内:
setup(props,context){ ...... const car = inject('car') // 拿到祖先的数据 return { car} ...... }
-
6. レスポンシブデータの判定
- isRef: 値が
ref
オブジェクトかどうかを確認します - isReactive: オブジェクトが
reactive
リアクティブ プロキシによって作成されたかどうかを確認します - isReadonly: オブジェクトが
readonly
読み取り専用プロキシによって作成されたかどうかを確認します。 - isProxy: オブジェクトが
reactive
orメソッドによってreadonly
作成されたプロキシであるかどうかを確認します。
コンポジション API の紹介もそろそろ終わりですが、この時点でアニメーションを見返してみると、Vue3 の香りがとても漂っていると感じます。
6. 新しいコンポーネント
1. フラグメント
Vue2 の場合: コンポーネントにはルート タグが必要です
Vue3 の場合: コンポーネントはルート タグがなくてもよく、内部的に複数のタグがフラグメント仮想要素に含まれます 利点:
タグ レベルを削減し、メモリ使用量を削減します
2. テレポート
テレポートとは何ですか? —— テレポートは、コンポーネントの HTML 構造を指定された場所に移動できるテクノロジーです。
<teleport to="移动位置">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
ポップアップ ウィンドウ コンポーネントを例に挙げます。
ネストされたボックスを作成し、最も内側のボックスにポップアップ ウィンドウを設定します。
アプリの親コンポーネント
<template>
<div class="app">
<h3>我是App组件</h3>
<Child />
</div>
</template>
<script>
import Child from "./components/Child";
export default {
name: "App",
components: {
Child },
};
</script>
<style>
.app {
background-color: gray;
padding: 10px;
}
</style>
子息子コンポーネント
<template>
<div class="child">
<h3>我是Child组件</h3>
<Son />
</div>
</template>
<script>
import Son from "./Son";
export default {
name: "Child",
components: {
Son },
};
</script>
<style>
.child {
background-color: skyblue;
padding: 10px;
}
</style>
息子孫コンポーネント
<template>
<div class="son">
<h3>我是Son组件</h3>
<Dialog />
</div>
</template>
<script>
import Dialog from "./Dialog.vue";
export default {
name: "Son",
components: {
Dialog },
};
</script>
<style>
.son {
position: relative;
background-color: orange;
padding: 10px;
}
</style>
ダイアログの対象となるダイアログ
<template>
<div>
<button @click="isShow = true">点我弹个窗</button>
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<h4>一些内容</h4>
<h4>一些内容</h4>
<h4>一些内容</h4>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</div>
</template>
<script>
import {
ref } from "vue";
export default {
name: "Dialog",
setup() {
let isShow = ref(false);
return {
isShow };
},
};
</script>
<style>
.mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.dialog {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
width: 300px;
height: 300px;
background-color: green;
}
</style>
意図的に最も内側のボックスに位置決めを追加しました。相対位置決めでは、位置決めのために外側のレイヤーで最も近い位置決めボックスが検索されるため、効果は次のようになります。このポップアップ ウィンドウが本文の下に表示されることを願っています。
Dialog コンポーネントにテレポート タグを追加します。
<template>
<div>
<button @click="isShow = true">点我弹个窗</button>
<teleport to="body">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<h4>一些内容</h4>
<h4>一些内容</h4>
<h4>一些内容</h4>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
</div>
</template>
それは良い
3. サスペンス
-
非同期コンポーネントの待機中に追加のコンテンツをレンダリングすることで、アプリケーションのユーザー エクスペリエンスが向上します。
-
使用手順:
- コンポーネントを非同期的にインポートする (動的インポート)
import { defineAsyncComponent} from 'vue' const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
Suspense
パッケージコンポーネントを使用してdefault
設定します。fallback
<template> <div class="app"> <h3>我是App组件</h3> <Suspense> <template v-slot:default> <Child/> </template> <template v-slot:fallback> <h3>加载中.....</h3> </template> </Suspense> </div> </template>
default
:コンポーネントが表示する内容です
fallback
:コンポーネントがフルロードされていない「スペアタイヤ」です
7. その他
1. グローバルAPIの移管
Vue 2.x には、多くのグローバル API と構成があります。
- 例: グローバル コンポーネントの登録、グローバル ディレクティブの登録など。
//注册全局组件
Vue.component('MyButton', {
data: () => ({
count: 0
}),
template: '<button @click="count++">Clicked {
{ count }} times.</button>'
})
//注册全局指令
Vue.directive('focus', {
inserted: el => el.focus()
}
これらの API は Vue3.0 で調整されました。
- グローバル API、つまり Vue.xxx をアプリケーション
(app)
インスタンスに調整します。
2. その他の変更点
① data オプションは常に関数として宣言する必要があります。
②遷移クラス名の変更
- Vue2.xの書き方
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-leave,
.v-enter-to {
opacity: 1;
}
- Vue3.xの書き方
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
③ v-on 修飾子として keyCode を削除し、config.keyCodes をサポートしなくなります
④ v-on.native 修飾子を削除します。
- 親コンポーネントのバインドイベント
<my-component
v-on:close="handleComponentEvent"
v-on:click="handleNativeClickEvent"
/>
- サブコンポーネントでカスタム イベントを宣言する
<script>
export default {
emits: ['close']
}
</script>
⑤フィルター(フィルター)を外す
フィルタ これは便利そうに見えますが、中括弧内の式が「単なる JavaScript」であるという前提を打ち破るカスタム構文が必要であり、学習コストだけでなく実装コストもかかります。フィルターをメソッド呼び出しまたは計算されたプロパティに置き換えることをお勧めします。
参考
Vue3 公式ドキュメントv3.cn.vuejs.org /
Vite 公式ドキュメントcn.vitejs.dev/
Vue-cli 公式ドキュメントcli.vuejs.org/zh/
Shang Silicon Valley Vue3 ビデオwww.bilibili.com/video/BV1Zy…