Vue3 セットアップとセットアップ構文シュガーの基本的な使用法

セットアップはいつ実行されますか

setup は、結合された api を記述するために使用されます。ライフサイクル フック機能の観点からは、beforeCreate を置き換えることと同等であり、作成される前に実行されます。

setup(props) {
  console.log("setup", props);
},
beforeCreate() {
  console.log("beforeCreate");
},
created() {
  console.log("created");
},

実行後は設定印刷結果が常に先頭になります。

セットアップ データとメソッドの使用方法

インスタンスにプロパティをマウントするには、セットアップ内のプロパティとメソッドを return で公開する必要があります。そうしないと、それらを使用する方法がありません。

<template>
  <div class="hello">
    <h1>{
   
   { msg }}</h1>
  </div>
</template>
setup(props) {
  let msg = "hello";
  return {
    msg,
  };
},

セットアップの中にこれはありますか?

これをセットアップで自分で印刷すると、返される結果は未定義です。セットアップは beforeCreate の前に 1 回実行されるため、これは未定義であり、これはセットアップ内に存在せず、これに関連するものはマウントできません。

setup(props) {
  console.log("setup", props);
  console.log("setup this", this);
},
beforeCreate() {
  console.log("beforeCreate");
},
created() {
  console.log("created");
},

セットアップ時のフック機能の使い方

Vue3 は vue2 と互換性のあるオプション形式の記述方法であるため、フック関数はオプション API と同等のセットアップと並行して存在できますが、vue2 と vue3 の構成が競合する場合、 vue3 のセットアップが優先されます。

export default{ 
    setup(){  
        console.log('setup'); 
    }, 
    mounted(){  
        console.log('mounted'); 
    }
}

vue3 の新しい setup() 関数は結合 API を記述するために使用されるため、このようなコードを記述することは推奨されません。したがって、フック関数を登録するには onXXX ファミリーの関数を使用する必要があります. 登録が成功した後、呼び出し時にコールバック関数が渡されます.  

import { onMounted } from "vue";
export default{ 
    setup(){  
        const a = 0  
        return{   a  }  
        onMounted(()=>{   
            console.log("执行"); 
        }) 
    }
}

これらの登録されたライフサイクル フック関数は、現在のコンポーネント インスタンスを見つけるためにグローバルな内部状態に依存しているため、セットアップ中に同期的にのみ使用できます。関数が現在のコンポーネントで呼び出されない場合はエラーがスローされます。

他のフック関数は同じです。必要に応じてインポートするだけです。

セットアップとフック機能の関係

セットアップがフック関数と並列化されている場合、セットアップはライフサイクル関連の関数を呼び出すことはできませんが、ライフサイクルはセットアップ関連のプロパティとメソッドを呼び出すことができます。

<template> 
    <button @click="log">点我</button>
</template><script>

export default{ 
    setup(){  
        const a = 0  return{   a  } 
    }, 
    methods:{  
        log(){   
            console.log( this.$options.setup() );//返回一个对象  
        } 
    }
}
</script>

this.$options.setup() は、セットアップのすべてのプロパティとメソッドを含む大きなオブジェクトを返します。

設定パラメータ

setup を使用する場合、**props と context の 2 つのパラメーターを受け取ります。**

小道具

最初のパラメーターは props で、これは親コンポーネントが値を子コンポーネントに渡すことを意味し、受信したプロパティはコンポーネント内で宣言されます. 子コンポーネントで受信されると、受信したデータはプロキシオブジェクトにパッケージ化され、実現できます.新しい小道具がインポートされると、自動的に更新されます。

export default{ 
    props: {  
        msg: String,  
        ans: String, 
    }, 
    setup(props,context){  
        console.log(props);//Proxy {msg: "着急找对象", ans: "你有对象吗?"} 
    },
}

props はレスポンシブであるため、ES6 の deconstruction を使用できないため、props のレスポンシブ性が失われます。

import { toRefs } from "vue"; 
export default{  
    props: {   
        msg: String,   
        ans: String,  
    },  
    setup(props,context){   
        console.log(props);   
        const { msg,ans } = toRefs(props)   
        console.log(msg.value); //着急找对象   console.log(ans.value); //你有对象吗?  
    }, 
}

コンポーネントを使用していると、オプションのパラメータに出くわすことがよくあります.特定の値を渡す必要がある場所と渡さない場所があります.

ans がオプションのパラメーターである場合、ans は props で渡されない場合があります。この場合、toRefs は ans の参照を作成せず、代わりに toRef を使用する必要があります。

import { toRef } from "vue";
setup(props,context){ 
    let ans  = toRef(props ,'ans')// 不存在时,创建一个ans 
    console.log(ans.value);
}

コンテクスト

context 属性、スロット、カスタム イベントの 3 つの部分を含むコンテキスト環境。

setup(props,context){ 
    const { attrs,slots,emit } = context // attrs 获取组件传递过来的属性值, // slots 组件内的插槽 // emit 自定义事件 子组件
}
  • attrs は非応答オブジェクトであり, 主にコンポーネントの外部から渡された no-props 属性を受け取ります. 一部のスタイル属性を渡すためによく使用されますが, props 構成で宣言されていない属性は; と同等です.親コンポーネントと子コンポーネントの間のプロセスで、親コンポーネントがthis.$attrsデータを送信します 受け渡し、サブコンポーネントが props で受信されない場合、attrs には表示されますが、vm には表示されません props で受信された場合、vm には表示されますが、vm には表示されません属性。

  • スロットはプロキシ オブジェクトです。ここで、slots.default() は配列を取得し、配列の長さはコンポーネントのスロットによって決定され、スロットの内容は配列内にあります。

  • emit: に相当する、カスタム イベントを配布する関数this.$emit

これはセットアップに存在しないため、前の this.$emit を置き換えるために emit が使用され、子が親に渡され、カスタム イベントがトリガーされるときに使用されます。

<template> 
    <div :style="attrs.style">  
        <slot></slot>    
        <slot name="hh"></slot>  
		<button @click="emit('getVal','传递值')">子向父传值</button>  
	</div> 
</template>

<script>
import { toRefs,toRef } from "vue";
export default{ 
    setup(props,context){  
        const { attrs,slots,emit } = context  // attrs 获取组件传递过来 style 属性     
        console.log('slots',slots.default());//插槽数组 
        console.log('插槽属性',slots.default()[1].props); //获取插槽的属性    
        return{  attrs,  emit   }  
    }, 
}
</script>

セットアップ機能の概要

  • 上記で説明したように、この関数は作成前に実行されます。

  • セットアップ内にこれはなく、これに関連するものはマウントできません。

  • セットアップ内のプロパティとメソッドは、return によって公開する必要があります。そうしないと、それらを使用する方法がありません。

  • セットアップ内部データは反応しません。

  • セットアップはライフサイクル関連の関数を呼び出すことはできませんが、ライフサイクル関数はセットアップで関数を呼び出すことができます。

注意点: (1) vue2 と vue3 の構成を混在させないようにしてください (2) 戻り値はもはや戻りオブジェクトではなくプロミスであり、テンプレートは属性を参照できないため、setup を非同期関数にすることはできません。戻りオブジェクト。(後で Promise インスタンスを返すこともできますが、Suspense と非同期コンポーネントの連携が必要です)

// 引入的不再是Vue构造函数了,引入的是一个名为createApp的工厂函数
import { createApp } from 'vue'
import App from './App.vue'

// 创建应用实例对象——app(类似于之前Vue2中的vm,但app比vm更“轻”)
const app = createApp(App)

// 挂载
app.mount('#app')

<スクリプトのセットアップ> シンタックス シュガー

<script setup>見返りに宣言する必要のない変数、関数、およびインポート導入されたコンテンツは<template/>

<script setup>
import { getToday } from './utils'
// 变量
const msg = 'hello'
// 函数
function log() {
    console.log(msg)
}
</script>

// 在 templete 中直接使用声明的变量、函数以及 import 引入的内容
<template>
    <div @click="log">{
   
   { msg }}</div>
	<p>{
   
   { getToday() }}</p>
</template>

標準コンポーネント <script> は setup 関数と return return を記述する必要があります

<script>
//import引入的内容
import { getToday } from './utils'  
export default{
 setup(){
    // 变量
    const msg = 'Hello!'
    // 函数
    function log() {
      console.log(msg)
    }
    //想在tempate里面使用需要在setup内return暴露出来
    return{
       msg,
       log,
       getToday 
    }
 }
}
</script>

<template>
  <div @click="log">{
   
   { msg }}</div>
   <p>{
   
   {getToday()}}</p>
</template>

<script setup> シンタックス シュガーのコードは、コンポーネントの setup() 関数のコンテンツ、および `<script setup>` ステートメントのトップ レベルのバインディング (変数、関数、およびによって導入されたコンテンツを含む) にコンパイルされます。宣言された変数、関数、およびインポート コンテンツを return で公開することなく、テンプレートで直接使用できます。<templet> で使用でき、export default{} を記述する必要はありません。 `<script setup>` を使用します。

<script setup> シンタックス シュガーのコードは、コンポーネントの setup() 関数のコンテンツにコンパイルされます。これは、コンポーネントが最初に導入されたときに一度だけ実行される通常の <script> とは異なり、コンポーネント インスタンスが作成されるたびに <script setup> 内のコードが実行されることを意味します。

<script>
  console.log('script');//多次实例组件,只触发一次
  export default {
      setup() {
          console.log('setupFn');//每次实例化组件都触发和script-setup标签一样
      }
  }
  </script>

setup()<script setup> タグは最終的に関数の内容にコンパイルされ、コンポーネントがインスタンス化されるたびに setup 関数が 1 回インスタンス化されます。scriptタグ内のsetup関数も同じで、コンポーネントをインスタンス化するたびにsetup関数を1回インスタンス化するのですが、scriptタグのsetupはexport default{}に書く必要があり、外側は一度だけ実行されます。それは最初に導入されます。

<script setup>インポートされたコンポーネントは自動的に登録されます

コンポーネントをインポートした後、「components:{}」を介してコンポーネントを登録する必要はありません。直接使用できます。

<script setup>
import MyComponent from './MyComponent.vue'
//components:{MyComponent}  不需要注册直接使用
</script>

<template>
  <MyComponent />
</template>

コンポーネントは文字列キーとして登録されるのではなく、変数として参照されるため、<script setup>で動的コンポーネントを使用する場合は、動的:isバインディングを使用する必要があります。

コンポーネント通信

props の代わりにand<script setup> API を使用し、で放出する必要がありますdefinePropsdefineEmits

`defineProps` と `defineEmits` には完全な型推論があり、`<script setup>` で直接利用できます (Nuggets を参照した後、記事のデモのほとんどがインポートを通じてこれら 2 つの API を導入していることに気付きました。これは明らかに公式ドキュメントです)書かれています)

props の代わりに defineProps は、親コンポーネントから渡されたデータを受け取ります (親コンポーネントはパラメーターを子コンポーネントに渡します)

親コンポーネント:

<template>
  <div>父组件</div>
  <Child :title="msg" />
</template>

<script setup>
import {ref} from 'vue'
import Child from './child.vue'
const msg = ref('父的值')  //自动返回,在template直接解套使用
</script>

サブアセンブリ:

  • <template/>親コンポーネントから渡された props を直接使用できます (props は省略できます)。

  • <script-setup>props.xxを介して親コンポーネントから渡された小道具を取得する必要があります

<template>
  <div>子组件</div>
  <div>父组件传递的值:{
   
   {title}}</div>
</template>

<script setup>
//import {defineProps} from 'vue'   不需要引入

//语法糖必须使用defineProps替代props
const  props = defineProps({
  title: {
    type: String
  }
});
//script-setup 需要通过props.xx获取父组件传递过来的props
console.log(props.title) //父的值
</script>

defineEmit は emit を置き換え、子コンポーネントはデータを親コンポーネントに渡します (子コンポーネントはデータを外部に公開します)。

サブコンポーネント コード:

<template>
  <div>子组件</div>
  <button @click="toEmits">子组件向外暴露数据</button>
</template>

<script setup>
import {ref} from 'vue'
const name = ref('我是子组件')
//1、暴露内部数据
const  emits = defineEmits(['childFn']);

const  toEmits = () => {
  //2、触发父组件中暴露的childFn方法并携带数据
  emits('childFn',name)
}
</script>

親コンポーネントのコード:

<template>
  <div>父组件</div>
  <Child  @childFn='childFn' />
  <p>接收子组件传递的数据{
   
   {childData}} </p>
</template>

<script setup>
import {ref} from 'vue'
import Child from './child.vue'
    
const childData = ref(null)    
const childFn=(e)=>{
    consloe.log('子组件触发了父组件childFn,并传递了参数e')
    childData=e.value
}    
</script>

<script setup>子コンポーネントのプロパティを親コンポーネントに積極的に公開する必要があります: defineExpose

<script setup>を使用するコンポーネントの場合、親コンポーネント$parentは ref または を介し​​て子コンポーネントの ref などの応答データを取得できず、defineExpose を介してアクティブに公開する必要があります。

サブコンポーネント コード:

<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)
//主动暴露组件属性
defineExpose({
  a,
  b
})
</script>

親コンポーネントのコード:

<template>
  <div>父组件</div>
  <Child  ref='childRef' />
  <button @click='getChildData'>通过ref获取子组件的属性 </button>
</template>

<script setup>
import {ref} from 'vue'
import Child from './child.vue'
const childRef= ref()  //注册响应数据  
const getChildData =()=>{
  //子组件接收暴露出来得值
  console.log(childRef.value.a) //1
  console.log(childRef.value.b) //2  响应式数据
}    
</script>

他の機能のシンタックス シュガー

`useSlots` と `useAttrs` (** めったに使用されません**。ほとんどの人は SFC モードで開発しているため、スロットは `<template/>` の `<slot/>` タグでレンダリングできます)

`script-setup` で `slots` と `attrs` を使用する必要がある場合は、代わりに `useSlots` と `useAttrs` を使用する必要があります。

紹介する必要があります: `import { useSlots ,useAttrs } form 'vue'`

`<template/>` の `$slots` と `$attrs` を介してアクセスする方が便利です (attrs は、親コンポーネント内の子コンポーネントに渡される非 props パラメータ/メソッドを取得するために使用され、attrs は使用されます親コンポーネントの非小道具を取得するには、小道具からサブコンポーネントに渡されるパラメーター/メソッド、属性は、親コンポーネントのサブコンポーネントに渡される非小道具パラメーター/メソッドを取得するために使用されます。スロットは、親コンポーネントのスロットによって渡される仮想 DOM オブジェクトを取得できます。であり、SFC モードでは役に立たないはずです。大きく、JSX/TSX でより多く使用されます)

親コンポーネント:

<template>
  <Child msg="非porps传值子组件用attrs接收" >
    <!-- 匿名插槽 -->
    <span >默认插槽</span>
    <!-- 具名插槽 -->
    <template #title>
      <h1>具名插槽</h1>
    </template>
    <!-- 作用域插槽 -->
    <template #footer="{ scope }">
      <footer>作用域插槽——姓名:{
   
   { scope.name }},年龄{
   
   { scope.age }}</footer>
    </template>
  </Child>
</template>

<script setup>
// 引入子组件
import Child from './child.vue'
</script>

サブアセンブリ:

<template>
  <!-- 匿名插槽 -->
  <slot />
  <!-- 具名插槽 -->
  <slot name="title" />
  <!-- 作用域插槽 -->
  <slot name="footer" :scope="state" />
  <!-- $attrs 用来获取父组件中非props的传递到子组件的参数 -->
  <p>{
   
   { attrs.msg == $attrs.msg }}</p>
  <!--true  没想到有啥作用... -->
  <p>{
   
   { slots == $slots }}</p>
</template>

  
<script setup>
import { useSlots, useAttrs, reactive, toRef } from 'vue'
const state = reactive({
  name: '张三',
  age: '18'
})

const slots = useSlots()
console.log(slots.default()); //获取到默认插槽的虚拟dom对象
console.log(slots.title());   //获取到具名title插槽的虚拟dom对象
// console.log(slots.footer()); //报错  不知道为啥有插槽作用域的无法获取
//useAttrs() 用来获取父组件传递的过来的属性数据的(也就是非 props 的属性值)。
const attrs = useAttrs()
</script>

セットアップでルーティングにアクセスする

ルーティング インスタンス コンポーネント情報へのアクセス: ルートとルーター

setup で this にアクセスできなくなり、 this.$router や this.$route に直接アクセスできなくなりました。(getCurrentInstance はこれを置き換えることができますが、お勧めしません)

推奨: this.$route と this.$router の代わりに、useRoute 関数と useRouter 関数を使用する

<script setup>
import { useRouter, useRoute } from 'vue-router'
    const route = useRoute()
    const router = useRouter()
    
    function pushWithQuery(query) {
      router.push({
        name: 'search',
        query: {
          ...route.query,
        },
      })
    }
<script/>

ナビゲーションガード

ルート インスタンス コンポーネントのナビゲーション ガードは引き続き使用できます

import router from './router'
router.beforeEach((to,from,next)=>{

})

組み合わせた api のナビゲーション ガードを使用することもできますonBeforeRouteLeave, onBeforeRouteUpdate

<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'

    // 与 beforeRouteLeave 相同,无法访问 `this`
    onBeforeRouteLeave((to, from) => {
      const answer = window.confirm(
        'Do you really want to leave? you have unsaved changes!'
      )
      // 取消导航并停留在同一页面上
      if (!answer) return false
    })

    const userData = ref()

    // 与 beforeRouteUpdate 相同,无法访问 `this`
    onBeforeRouteUpdate(async (to, from) => {
      //仅当 id 更改时才获取用户,例如仅 query 或 hash 值已更改
      if (to.params.id !== from.params.id) {
        userData.value = await fetchUser(to.params.id)
      }
    })
<script/>

複合 API ガードは、 によって<router-view>レンダリングされる。コンポーネント内ガードのように、ルーティング コンポーネントで直接使用する必要はありません。

通常のスクリプトで使用する

<script setup> は通常の <script> で使用できます。これらの場合、通常の <script> を使用できます。

  • プラグインによって有効化されたカスタム<script setup>オプションなど、宣言されたオプションでは使用できませんinheritAttrs

  • 名前付きエクスポートを宣言する

  • 副作用を実行するか、一度だけ実行する必要があるオブジェクトを作成します

<script>
    // 普通 <script>, 在模块范围下执行(只执行一次)
    runSideEffectOnce()
    
    // 声明额外的选项
    export default {
      inheritAttrs: false,
      customOptions: {}
    }
</script>

<script setup>
    // 在 setup() 作用域中执行 (对每个实例皆如此)
</script>

概要: setup のシンタックス シュガーは Vue3 を補完するものであり、Vue3 をより完全なものにします。

<script setup> は、単一ファイル コンポーネントで Composition API を使用するためのコンパイル時のシンタックス シュガーです。通常の <script> 構文よりも多くの利点があります

  • 定型文の内容を減らし、コードをより簡潔に
  • 純粋な Typescript を使用して小道具を宣言し、イベントをスローする機能
  • ランタイム パフォーマンスの向上 (そのテンプレートは、中間プロキシなしで、それと同じスコープでレンダー関数にコンパイルされます)
  • IDE 型推論パフォーマンスの向上 (言語サーバーがコードから型を抽出する作業が少なくなります)

おすすめ

転載: blog.csdn.net/qq_43641110/article/details/129981821