Vue3 構成 - API とセットアップのライフサイクル

1. セットアップの簡単な説明

Setup は、Composition API のエントリ関数であり、最初に使用される関数でもあります。セットアップは初期化中に 1 回だけ実行され、すべての複合 API 関数がここで使用されます。Comboposition API のコード構成は非常に柔軟で、すべてのコードをセットアップで直接記述することができます (簡単に言うと、vue2 のデータ、メソッド、および計算がすべて省略され、すべてのデータ メソッドが vue2 で記述されることを意味します)。セットアップ
ここに画像の説明を挿入します

セットアップが実行されるとき、コンポーネント オブジェクトはまだ作成されておらず、コンポーネント インスタンス オブジェクトはまだ利用可能ではないと推測できます。現時点では、これは未定義であり、data/computed/methods/props を通じてアクセスすることはできません。これ。

1. setup函数执行于beforeCreate和created之前,也就是说setup函数里面无法使用data和methods方法中的数据
2. setup 有2个参数
    props 的父组件传递过来的参数
    ctx 上下文对象
        ctx.attrs
        ctx.slots
        ctx.parent
        ctx.root
        ctx.emit
        ctx.refs
3.在 setup() 函数中无法访问到 this
4. 在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用

2.セットアップタグ単一ファイルコンポーネント

シングル ファイル コンポーネント (SFC) でコンポジション API を使用するためのコンパイル時の構文糖です。普通と比べて

  • 定型文が減り、コードがすっきりします。
  • 純粋な TypeScript を使用して props を宣言し、イベントをスローする機能。
  • 実行時のパフォーマンスの向上 (そのテンプレートは、中間プロキシなしで、同じスコープ内のレンダリング関数にコンパイルされます)。
  • IDE の型推論パフォーマンスの向上 (言語サーバーがコードから型を抽出する作業が少なくなります)

基本的な文法

<script setup name="Dict">
	1. name 表示组件的名称
	2. setup 放在script 上时,声明 变量,函数声明,以及 import 引入的内容,都能在模板中直接使用,不用rerun 
	3. 访问props 使用defineProps
 	const props = defineProps({
    
    
	    //子组件接收父组件传递过来的值
	    info:{
    
    
	        type: Object
	    }
	})
	4. ctx.emit 触发事件=》defineEmits(['selected']) // defineEmits子组件向父组件事件传递值
	5. ctx.expose 暴露公共 函数 =》defineExpose({
    
    函数名称});
	6. useSlots 和 useAttrs:与 setupContext.slots 和 setupContext.attrs 等价的值
	import {
    
     useSlots, useAttrs } from 'vue'
	const slots = useSlots()
	const attrs = useAttrs()
	7. 状态驱动的动态 CSS【(<style> 中的 v-bind)】
	const theme = {
    
    
  		color: 'red'
	}
	<style scoped>
		p {
    
    
		  color: v-bind('theme.color');
		}
	</style>
	8. 更新dom后操作nextTick(()=>{
    
     //执行代码})
	9. a
</script>

動的コンポーネント

 动态组件:由于组件被引用为变量而不是作为字符串键来注册的,在 <script setup> 中要使用动态组件的时候,就应该使用动态的 :is 来绑定:
	<template>
 		 <component :is="Foo" />
  		<component :is="someCondition ? Foo : Bar" />
	</template>
	<script setup>
import Foo from './Foo.vue'
import Bar from './Bar.vue'
</script>

再帰的なコンポーネント

単一ファイルのコンポーネントは、そのファイル名を使用して単独で参照できます。たとえば、FooBar.vue という名前のコンポーネントは、テンプレート内でそれ自体を参照できます。
この方法でインポートされたコンポーネントはインポートよりも優先度が低いことに注意してください。名前付きインポートがコンポーネントの推論名と競合する場合は、インポート エイリアスを使用できます:
import { FooBar as FooBarChild } from './components'

名前空間コンポーネント

<Foo.Bar> などのドット付きコンポーネント タグを使用して、オブジェクト プロパティ内にネストされたコンポーネントを参照できます。これは、単一のファイルから複数のコンポーネントをインポートする必要がある場合に便利です。

<script setup>
import * as Form from './form-components'
</script>

<template>
  <Form.Input>
    <Form.Label>label</Form.Label>
  </Form.Input>
</template>

カスタムディレクティブを使用する

グローバルに登録されたカスタム ディレクティブは期待どおりに機能し、ローカルに登録されたディレクティブは、上記のコンポーネントと同様にテンプレートで直接使用できます。

ただし、注意すべき制限があります。ローカル カスタム ディレクティブは、テンプレート内で直接使用できるように、vNameOfDirective の形式で名前を付ける必要があります。

<script setup>
const vMyDirective = {
    
    
  beforeMount: (el) => {
    
    
    // 在元素上做些操作
  }
}
</script>
<template>
  <h1 v-my-directive>This is a Heading</h1>
</template>
或是
<script setup>
  // 导入的指令同样能够工作,并且能够通过重命名来使其符合命名规范
  import {
    
     myDirective as vMyDirective } from './MyDirective.js'
</script>

トップレベルの待機

<script setup> 中可以使用顶层 await。结果代码会被编译成 async setup()<script setup>
const post = await fetch(`/api/post/1`).then(r => r.json())
</script>
注意:
async setup() 必须与 Suspense 组合使用,Suspense 目前还是处于实验阶段的特性。我们打算在将来的某个发布版本中开发完成并提供文档 - 如果你现在感兴趣,可以参照 tests 看它是如何工作的

vue3 のバージョンは 3.2 からサポートされており、より簡潔になっていますので、ご使用の際はバージョンにご注意ください。定義された変数とメソッドは返す必要がなく、テンプレートで使用できます。

3.合成API

コンポーネント ロジックをより柔軟に「組み合わせる」ことを可能にする、低侵入型の機能的な API のセット
Comboposition API は React Hooks からインスピレーションを受けており、ミックスインよりも強力です。コード ロジックの再利用性が向上し、テンプレートからの独立性が達成されると同時に、関数型プログラミングによりコードがより圧縮可能になります。

コンポーザブル API とは何ですか?

ここに画像の説明を挿入します
オブジェクトベース API (vue2) の問題

  1. 再利用には向きません
  2. 潜在的な名前の競合
  3. コンテキストが失われた
  4. 限定されたタイプのサポート
  5. 組み合わせた API によって提供される機能をAPI タイプごとに整理する
  6. 再利用が非常に簡単 (ネイティブ JS 関数)
  7. 柔軟に組み合わせ可能(ライフサイクルフックは複数回使用可能)
  8. より優れたコンテキストサポートを提供する
  9. typeScipt 型のサポートの向上
    5. 関数/ロジックごとに整理

レスポンシブデータ

Vue2.x 版では data() でデータを定義するだけでレスポンシブデータにできましたが、Vue3.0 では reactive 関数や ref を使ってレスポンシブデータを作成する必要があります。

1. 简单数据类型(String、Number, bool 等)推荐使⽤ref
引入 import {
    
    ref} from 'vue'
使用: let num = ref(1)
获取/修改值:num.value
2. 复杂数据类型(Array、Object)推荐使⽤reactive
 import {
    
    reactive} from 'vue'
 let arr = reactive({
    
    age:1}) 传⼊⼀个对象,vue会封装成Proxy对象,使⽤⾥⾯的⽅法实现响应式数据
 直接修改数据: arr.age = 12

注:応答性の高いデータを作成する必要がない場合は、変数を直接宣言するだけです。たとえば、インターフェースから取得したデータ、

参考文献の紹介

ref と reactive の概要、ref の使用をお勧めします

ここに画像の説明を挿入します

ref が自動的にアンパックされる場合、.value を使用する必要はありません。

ここに画像の説明を挿入します

unref - Ref の逆の操作

ref が渡された場合はその値が返され、それ以外の場合は
ここに画像の説明を挿入します
変更されずに返されます。この 2 つは一緒に使用できます。MaybeRef
は ref および unref とうまく連携できます。

ref を関数パラメータとして受け入れる

ここに画像の説明を挿入します

レスポンシブデータの判定

isRef: 値が ref オブジェクトであるかどうかを確認します。
isReactive: オブジェクトが reactive によって作成されたリアクティブ プロキシであるかどう
かを確認します。 isReadonly: オブジェクトが readonly によって作成された読み取り専用プロキシであるかどうかを確認します。
isProxy: オブジェクトが reactive または readonly によって作成されたかどうかを確認します。メソッド 作成されたプロキシ

computed() 計算されたプロパティ

computed() は計算されたプロパティの作成に使用され、戻り値は ref() インスタンスです。

computed は読み取り専用の計算プロパティを作成します

関数を computed() に渡すことで、読み取り専用の計算プロパティを取得できます。

const count = ref(1)

// 创建一个计算属性,使其值比 count 大 1
const bigCount = computed(() => count.value + 1)

console.log(bigCount.value) // 输出 2
bigCount.value++ // error 不可写

computed は読み取りおよび書き込み可能な計算プロパティを作成します

onst count = ref(1)

// 创建一个 computed 计算属性,传入一个对象
const bigCount = computed({
    
    
    // 取值函数
    get: () => (count.value + 1),
    // 赋值函数
    set: val => {
    
    
      count.value = val - 1
    }
})

// 给计算属性赋值的操作,会触发 set 函数
bigCount.value = 9
// 触发 set 函数后,count 的值会被更新
console.log(count.value) // 8

読み取り専用()

リアクティブ オブジェクト、通常のオブジェクト、または参照を渡し、読み取り専用オブジェクト プロキシを返します。このプロキシは深く、オブジェクト内のデータも読み取り専用です。

const state = reactive({
    
     count: 0 })

const copy = readonly(state)

watchEffect(() => {
    
    
  // 依赖追踪
  console.log(copy.count)
})

// state 上的修改会触发 copy 上的侦听
state.count++

// 这里只读属性不能被修改
copy.count++ // warning!

watchEffect()

watchEffect() は、渡された関数を即座に実行し、その依存関係をリアクティブにリッスンし、依存関係が変更されたときに関数を再実行します。

基本的な使い方

const count = ref(0)

// 初次直接执行,打印出 0
watchEffect(() => console.log(count.value))

setTimeout(() => {
    
    
  // 被侦听的数据发生变化,触发函数打印出 1
  count.value++
}, 1000)

聞くのをやめる

watchEffect() を使用すると関数が返され、返された関数が実行されるとリスニングが停止します。

const stop = watchEffect(() => {
    
    
  /* ... */
})

// 停止侦听
stop()

時計()

Composition-API の Watch は Vue2.x と同じです。Watch はデータをリッスンし、そのリッスン コールバックを実行する必要があります。デフォルトでは、最初のレンダリングは実行されません。

watch と watchEffect の違い

  • 初期レンダリングが実行されないことを確認する
  • より具体的に見て聞く
  • watch はデータ変更をリッスンする前後の値にアクセスできます

watch は単一のデータソースをリッスンします

リッスンされるデータは、リアクティブ (戻り値を持つゲッター関数) によって作成された応答データであることも、参照であることもあります。

1 つのウォッチが 3 つの属性を受け取ります
  • パラメータ 1: 応答オブジェクト (リアクティブ オブジェクトなど)
  • パラメータ 2: オブジェクトの内部プロパティの変更に関するコールバック関数。old と new の 2 つの仮パラメータを持ちます。
  • パラメータ 3: 監視属性制御。deep は詳細な監視を意味し、immediate はページが起動されるとすぐに監視を開始することを意味します。
<script setup >
let message = reactive({
    
    
    name: 'helloworld'
})
watch(message, (newVal, oldVal) => {
    
    
    console.log(newVal);
    console.log(oldVal);
}, {
    
    
    deep: true,
    immediate: true
})
</script>

watch は複数のデータソースをリッスンします

複数のデータ ソースをリッスンする場合、監視するパラメーターを配列の形式で指定します。リスニング オブジェクトに複数のプロパティがある場合、パラメーター 1 をアロー関数の形式で記述して、必要なプロパティの名前を指定できます。監視する; そうでない場合 監視すると、すべてが監視されます。

 const loginForm = reactive({
    
    
    username: '',
    password: '',
  });
  const num = ref(0);
  // loginForm的每个值变化或num变化都会触发watch
  watch([loginForm, num], (val) => {
    
    
    console.log(val); // val[0]的数据是loginForm的数据,val[1]是num的数据
  });
  // loginForm.username值变化或num变化都会触发watch
    watch([() => loginForm.username, num], (val) => {
    
    
    console.log(val); // val[0]的是loginForm.username数据,val[1]是num的数据
  });

4. 構成 API 依存ツール

 1. toRef():当我们在模板中渲染数据时,不希望由前缀的时候可以使用组合-toRef()
 toRef()是函数,转换响应式对象中某个属性为单独响应式数据,并且值是关联的
 	//  数据响应式:
    const obj = reactive({
    
    
      msg: 'hello',
      info: 'hi'
    })
    const msg = toRef(obj, 'msg')
    const info = toRef(obj, 'info')
    const hClick = () => {
    
    
      msg.value = 'nihao'
      info.value= 'hihi'
    }
  可以直接访问: msg, info
2. toRefs():toRefs函数可以定义转换响应式中所有属性为 响应式数据,通常用于结构reactive定义的对象,转换响应式对象中所有属性(也可以是一部分)为单独响应式数据,对象成为普通对象,并且值是关联的
const {
    
     msg, info } = toRefs(obj);

5. ライフサイクル

ライフサイクル関数は次のとおりです: onBeforeMount、onMounted、onBeforeUpdate、onUpdated、onBeforeUnmount、onUnmounted、onErrorCaptured、onRenderTracked、onRenderTriggered、onActivated、onDeactivated。
vue2 とは異なり、vue3 は vue2 のライフサイクルの名前に基づいて on を追加します

script>
import {
    
    
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onRenderTracked,
  onRenderTriggered,
} from "vue";
export default {
    
    
  components: {
    
    },
  data() {
    
    
    return {
    
    };
  },
  setup() {
    
    
    // setup里面存着两个生命周期创建前创建
    // beforeCreate
    // created
    onBeforeMount(() => {
    
    
      console.log("onBefore   ====>  vue2.0 x beforemount");
    });
    onMounted(() => {
    
    
      console.log("onMounted  ====>  vue2.0 x mount");
    });
    onBeforeUpdate(() => {
    
    
      console.log("onBeforeUpdate  ====>  vue2.0 x beforeUpdate");
    });
    onUpdated(() => {
    
    
      console.log("onUpdated  ====>  vue2.0 x update");
    });
    onBeforeUnmount(() => {
    
    
      //在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。
      console.log("onBeforeUnmount ====>  vue2.0 x beforeDestroy");
    });
    onUnmounted(() => {
    
    
      //卸载组件实例后调用,调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。
      console.log("onUnmounted ====>  vue2.0 x destroyed");
    });
    // 新增两个生命周期函数
    //每次渲染后重新收集响应式依赖
    onRenderTracked(({
    
     key, target, type }) => {
    
    
      // 跟踪虚拟DOM重新渲染时调用,钩子接收debugger event作为参数,此事件告诉你哪个操作跟踪了组件以及该操作的目标对象和键。
      // type:set/get操作
      // key:追踪的键
      // target:重新渲染后的键
      console.log("onRenderTracked");
    });
    //每次触发页面重新渲染时自动执行
    onRenderTriggered(({
    
     key, target, type }) => {
    
    
      //当虚拟DOM重新渲染被触发时调用,和renderTracked类似,接收debugger event作为参数,
      // 此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键
      console.log("onRenderTriggered");
    });
    return {
    
    };
  },
};
</script>

セットアップでのライフ サイクルの実行と外部ライフ サイクル関数を比較すると、最初に setUp でライフ サイクル関数を指定し、次に外部ライフ サイクル関数を実行します。

親子コンポーネントのライフサイクル

親コンポーネント:

<template>
<div class="container">
 父组件-->{
    
    {
    
    msg}}
 //子组件
<ChildItem :msg="msg" :msg1="msg1"></ChildItem>
</div>
</template>


<script lang="ts">
import {
    
     defineComponent,ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated } from 'vue'
import ChildItem from './components/base/Child.vue'
export default defineComponent({
    
    
  name: 'App',
  components: {
    
    
    ChildItem

  },
  beforeCreate () {
    
    
    console.log('父beforeCreate')
  },
  created () {
    
    
    console.log('父created')
  },
  setup () {
    
    
    console.log('父setup')
    onBeforeMount(() => {
    
    
      console.log('父onBeforeMount')
    })
    onMounted(() => {
    
    
    //更新数据
    setTimeout(() => {
    
    
        msg.value = 'hello,1s后修改msg'
        console.log('msg 被修改')
      }, 1000)
      console.log('父onMounted')
    })
    onBeforeUpdate(() => {
    
    
      console.log('父onBeforeUpdate')
    })
    onUpdated(() => {
    
    
      console.log('父onUpdated')
    })
  }
})
</script>

Child.vue

<template>
  <div>子组件-->{
    
    {
    
    msg}}</div>

</template>

<script lang="ts">
import {
    
     defineComponent, onBeforeMount, onMounted, onBeforeUpdate, onUpdated } from 'vue'

export default defineComponent({
    
    
  name: 'ChildItem',
  props: {
    
    
    msg: {
    
    
      type: String,
      required: true
    }
  },
  beforeCreate () {
    
    
    console.log('子beforeCreate')
  },
  created () {
    
    
    console.log('子created')
  },
  setup (props, {
    
     attrs, slots, emit }) {
    
    
    console.log('子setup')
    onBeforeMount(() => {
    
    
      console.log('子onBeforeMount')
    })
    onMounted(() => {
    
    
      console.log('子onMounted')
    })
    onBeforeUpdate(() => {
    
    
      console.log('子onBeforeUpdate')
    })
    onUpdated(() => {
    
    
      console.log('子onUpdated')
    })
  }

})
</script>

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/gao_xu_520/article/details/125559272