Vue 3-ComponentAPI(コンビネーションAPI-共通部分)


Composition API
解決:従来のoption api(オプション)構成方法でコンポーネントを書くときの問題は、ビジネスの複雑さがますます高くなるにつれて、コード量が増加し続けます.関連業務のコードはoptionの構成に従って特定の領域に書く必要があるため、後続のメンテナンスが非常に複雑であり、コードの多重性が高くない.
いくつかの関数があります.
		setup
		ref
		reactive
		watchEffect
		computed
		toRefs
		     hooks
		...

setup:
  • すべての組合せAPI関数はここで使用され、初期化時にのみ
  • が実行される.
  • 関数オブジェクトを返す場合、オブジェクト内の属性またはメソッドは、html
  • を直接使用することができる.
    実行タイミング:
    beforeCreateの前に実行(一度だけ実行)する場合、コンポーネントオブジェクトはまだ作成されていません.すなわち、thisはundefinedであり、thisによってdata/computed/methods/propsにアクセスすることはできません.すべてのcomposition API関連コールバック関数でもできません.
    パラメータ:
  • setup(props, context)/setup(props, {attrs, slots, emit})
  • props:props構成宣言および受信したすべての属性を含むオブジェクト
  • .
  • attrs:props構成で宣言されていない属性を含むオブジェクト.this.$に相当します.attrs
  • slots:this.$に相当するすべての入力スロットの内容を含むオブジェクトslots
  • emit:this.$に相当するカスタムイベントを配布するための関数emit

  • 戻り値:
  • は一般的にhtmlテンプレートにデータを提供するオブジェクトを返します.
  • 戻りオブジェクトの属性はdata関数戻りオブジェクトの属性と結合してコンポーネントオブジェクトの属性となる.
  • オブジェクトに戻るメソッドはmethodsのメソッドと成功したコンポーネントオブジェクトをマージするメソッドであり、重複名があればsetupが優先される.

  • 注意:
  • 『できるだけ混ぜて使わないで!』-methodsではsetupが提供する属性とメソッドにアクセスできますが、setupメソッドではdataとmethodsにアクセスできません(thisオブジェクトはありません).
  • setupはasync関数ではありません.戻り値はreturnのオブジェクトではなくpromiseなので、テンプレートにはreturnオブジェクトの属性データが見えません.
  • 以下のコードは@vue/cli 4.5.10
  • に基づく
  • 部分TS(Typescript学習)構文
  • // App.vue
    <template>
        <h2>App     </h2>
        <h4>{
         {
         msg}}</h4>
        <hr>
       
        <Child :msg=msg @XXX="XXX"/>     <!-- msg2='  ' -->
        <button @click="updateMsg">up-</button>
        <button @click="msg += '======'">up=</button>
    </template>
    <script lang="ts">
    import {
          defineComponent,ref, reactive } from 'vue';
    import Child from './components/Child.vue'
      export default defineComponent({
         
          name: 'App',
          components: {
         
              Child
          },
          setup() {
         
              const msg = ref('what are you doing?')
              function updateMsg() {
         
                  msg.value+='-------'
              }
              function XXX(txt: string) {
         
                  msg.value+=txt
              }
            return{
         
                msg,
                updateMsg,
                XXX
            }
          }
      })
    </script>
    
    // Child.vue
    <template>
      <h3>Child   </h3>
      <h5>{
         {
         msg}}</h5>
      <h5>count:{
         {
         count}}</h5>
      <button @click="emitXX">    emit</button>
    </template>
    
    <script>
    import {
         defineComponent} from 'vue'
    export default defineComponent({
         
     name: 'Child',
     data() {
         
         return{
         
             count: 10
         }
     },
     props: ['msg'],
     beforeCreate() {
         
         console.log('beforeCreate ...');
     },
     inheritAttrs: false,		//          (  vue warn)
     setup(props, context) {
         
         console.log('props:', props);console.log('props.msg:', props.msg);
         console.log('context:', context);
        //  console.log('context.attrs:', context.attrs.msg2);
         console.log('setup ...   this:', this);
         const showMsg1 = ()=>{
         
             console.log('setup  showMsg1 ...');
         }
         //            
         function emitXX() {
         
             context.emit('XXX','1234') //   msg        
         }
         return{
         
             showMsg1,
             emitXX
         }
     },
     //             
        mounted() {
         
            console.log('mounted ...   this:',this);
        },
    // 
        methods: {
         
            showMsg2() {
         
                console.log('methods  showMsg2 ...');
            }
        }
    })
    </script>
    

    refとreactive
    ref:基本タイプの応答データを定義します.応答式データを含む参照オブジェクトを返し、操作データを使用する.valueプロパティ、テンプレートには必要ありません.value
    reactive:複数のデータの応答式を定義する.
  • const proxy=reactive(obj):通常オブジェクトobjを受信し、その通常オブジェクトobjの応答型エージェントオブジェクトを返す.
  • 応答変換は「深層」です.オブジェクト内部のネストされたすべての属性に影響します.
  • 内部のES 6に基づくProxy実装は、プロキシオブジェクトによって操作するソースオブジェクトの内部データが応答式である.
  • // App.vue
    <template>
        <div>hello Vue3!</div>
        <!-- <button @click="add">
            Count is: {
         {
          count }}
        </button> -->
        <button @click="updateuser">
            updateuser
        </button>
        <h2>name:{
         {
         user.name}}</h2>
        <h2>age:{
         {
         user.age}}</h2>
        <h2>hsb:{
         {
         user.hsb}}</h2>
    </template>
    <script lang="ts">
    //   api  
    import {
          defineComponent,ref, reactive } from 'vue';
    export default defineComponent({
         
      name: 'App',
      //              
      // vue2:
    //   data(){
         
    //       return {
         
    //           count: 0
    //       }
    //   },
    //   methods: {
         
    //       add (){
         
    //         this.count++;
    //       }
    //   }
      // vue3:
      setup(){
           //      API       ,           
        //   let number = 10    //            (      :     ,        )
        const number = ref(10)  // ref      
        // console.log(number);
          function add() {
         
              number.value ++
          }
          
    
        /**
         *   :           
            const proxy = reactive(obj):         obj         obj         
                  “   ”:              
                 ES6   Proxy   ,                     
         */
        const obj ={
         
            name: 'y',
            age: 24,
            hsb: {
         
                name: 'z',
                age: 24,
                car: ['  ','BWM','   ']
            }
        }
        //              ,        ,    proxy    ,     obj  
          const user = reactive(obj)
          // user     ,obj     
          console.log(user);
          const updateuser = ()=>{
         
              user.name+='--'
              user.age-=1
              user.hsb.name+='---'
              user.hsb.car[0]='  '
          }
    
          return {
           // setup        ,          ,          
              number,
              add2:add,
              user,
              updateuser
          }
      }
      
    });
    </script>
    
    

    refとreactiveの詳細:
  • refは、基本タイプのデータを処理するために用いる、reactiveは、オブジェクト(再帰的深度応答式)
  • を処理するために用いる.
  • オブジェクト/配列にrefを入れると、内部で自動的にオブジェクト/配列がreactiveのプロキシオブジェクト
  • に変換されます.
  • ref内部:value属性にgetter/setterを追加することによってデータのハイジャック
  • を実現する.
  • reactive内部:Proxyを用いる対象内部の全てのデータのハイジャックを実現し、Reflectにより対象内部データ
  • を操作する.
  • refのデータ操作:jsで行う.value、テンプレートに不要(内部解析テンプレートの場合.valueが自動的に追加されます)
  • <template>
        <h2>ref _ reactive   </h2>
        <h3>m1:{
         {
         m1}}</h3>
        <h3>m2:{
         {
         m2}}</h3>
        <h3>m3:{
         {
         m3}}</h3>
        <hr>
        <button @click="update">upda</button>
    </template>
    <script lang="ts">
    import {
          defineComponent,ref, reactive } from 'vue';
      export default defineComponent({
         
          name: 'App',
          setup() {
         
              const m1 = ref('abc')
              const m2 = reactive({
         
                  name: 'xiaox',
                  wife: {
         
                      name: 'hah'
                  }
              })
              
              const m3 = ref({
         
                  name: 'aa',
                  wife: {
         
                      name: 'bb'
                  }
              })
              console.log('m3',m3);	// ref        /     reactive     
              const update = () =>{
         
                  m1.value += '111111'
                  m2.wife.name += '222222'
                  m3.value.name += '333333'
              }
              return{
         
                  m1,
                  m2,
                  m3,
                  update
              }
          }
      })
    </script>
    
    

    vue 2とvue 3の応答式を比較する
    vue 2の応答式:オブジェクト:definePropertyによってオブジェクトの既存の属性値の読み取りと変更をハイジャック(監視/ブロック)する配列:配列更新配列の一連の更新要素を書き換える方法によって要素修正のハイジャックを実現する.
    Object.defineProperty(data, 'count', {
         
        get () {
         }, 
        set () {
         }
    })
    

    Vue 3の応答式:Proxy(プロキシ):dataの任意の属性に対する任意(13種類)の操作をブロックし、属性値の読み書き、属性の追加、属性の削除などを含む...Reflect(反射):被プロキシオブジェクトの対応する属性を動的に特定する操作.
    <script>
        const user = {
         
            name: '  ',
            age: 19,
            wife: {
         
                name: '  ',
                age: 18,
            }
        }
        const proxyUser = new Proxy(user, {
         
                get(target, prop) {
         
                    console.log('get ..');
                    return Reflect.get(target, prop)
                },
                set(target, prop, val) {
         
                    console.log('set ..');
                    return Reflect.set(target, prop, val)
                },
                deleteProperty(target, prop) {
         
                    console.log('delete ..');
                    return Reflect.deleteProperty(target, prop)
                }
            })
            //                 
        console.log(proxyUser.name);
        //   
        proxyUser.name = '  2'
        console.log(user.name);
        //   
        proxyUser.gender = ' '
        console.log(user);
        //   
        delete proxyUser.age
        console.log(user);
        //     
        proxyUser.wife.name = '  2'
        console.log(user);
    </script>
    

    vue 2応答欠陥:
  • オブジェクトが直接追加した属性または既存の属性を削除する場合、インタフェースは自動的に
  • を更新しません.
  • は直接下付きで要素を置換したりlengthを更新したりして、インタフェースはarr[1]={}
  • を自動的に更新しません.
    計算プロパティと監視
    computed関数watch関数watchEffect関数
    <template>
        <h2>       </h2>
        <fieldset>
            <legend>    </legend><input type="text" placeholder="     " v-model="user.lastName"><br><input type="text" placeholder="     " v-model="user.firstName"><br>
        </fieldset>
        <fieldset>
            <legend>         </legend>
            fullName1:<input type="text" placeholder="    " v-model="fullName1"><br>
            fullName2: <input type="text" placeholder="    " v-model="fullName2"><br>
            fullName3:<input type="text" placeholder="    " v-model="fullName3"><br>
        </fieldset>
        
    </template>
    <script lang="ts">
    import {
          defineComponent,computed, watch, watchEffect, ref, reactive } from 'vue';
      export default defineComponent({
         
          name: 'App',
          setup() {
         
              const user = reactive({
         
                  //   
                  lastName: ' ',
                  //   
                  firstName: '  '
              })
              //              
              // vue3:   computed          ,  get
              const fullName1 = computed(()=>{
           //    ref   
                  console.log('fullName1 get...');
                  return `${
           user.lastName}_${
           user.firstName}`
              })
              //  computed      ,  get   set
              const fullName2 = computed({
         
                  get() {
         
                    //   console.log('fullName2 get...');
                      return `${
           user.lastName}_${
           user.firstName}`
                  },
                  set(val: string) {
         
                      console.log('fullName2 set...');
                      const name = val.split('_')
                      user.lastName = name[0]
                      user.firstName = name[1]
                  }
              })
             //   :  
              const fullName3 = ref('')
              watch(user, ({
         lastName, firstName})=>{
         
                fullName3.value = lastName + '_' + firstName
              }, {
         immediate: true, deep: true}) //         watch,                
            //   watchEffect(()=>{ //        
            //       fullName3.value = user.lastName + '_' + user.firstName
            //   })
    
              watch(fullName3, ()=>{
         
                const name = fullName3.value.split('_')
                user.lastName = name[0]
                user.firstName = name[1]
              }, {
         immediate: true, deep: true})
            //   watchEffect(()=>{
         
            //       const name = fullName3.value.split('_')
            //       user.lastName = name[0]
            //       user.firstName = name[1]
            //   })
    
              // watch        :
                // 1,       :
                watch([user, fullName3], ()=>{
         
                    console.log('       ...');
                })
                // 2,        :
                watch([()=>user.lastName, ()=>user.firstName], ()=>{
         
                    console.log('      ...');
                })
              return {
         
                  user,
                  fullName1,
                  fullName2,
                  fullName3
              }
          }
      })
      
      
    </script>
    
    

    ライフサイクルフック関数
    vue 2とvue 3の比較:
    beforeCreate->setup()created->setup()beforeMount->onBeforeMounted->onMounted beforeUpdate->onBeforeUpdate->onUpdate->onUpdated beforeDestroy->onBeforeUnmounted destroyed->onUnmounted
    カスタムhoos関数
    hooks関数とは,classを用いずに状態データを管理し,論理的思考を抽出する多重機能関数である.
    // useMousePosition.ts
    //            
    import {
          ref, onMounted, onBeforeUnmount } from 'vue'
    
    export default function () {
         
        const x = ref(-1)
        const y = ref(-1)
        const clickCB = (event: MouseEvent) => {
         
            x.value = event.pageX
            y.value = event.pageY
        }
        //          ,       API
        onMounted(() => {
         
            window.addEventListener('click', clickCB)
        })
        //               API
        onBeforeUnmount(() => {
         
            window.removeEventListener('click', clickCB)
        })
        return{
         
            x,
            y
        }
    }
    
    // useRequest.ts
    //     
    import axios from 'axios';
    import {
          ref } from "vue";
    //   ajax   
    //   TS               
    export default function <T>(url: string) {
         
        const loading = ref(true)
        const data = ref<T | null>(null)
        const errMsg = ref('')
        //    
        axios.get(url).then(res=>{
         
            loading.value = false
            data.value = res.data
        }).catch(err=>{
         
            loading.value = false
            errMsg.value = err.message || '    '
        })
        return{
         
            loading,    //     
            data,       //     
            errMsg      //     
        }
    }
    

    次のように呼び出されます.
    // App.vue
    <template>
        <h2>   hook  </h2>
        <h4>    class                          </h4>
        <h3>x: {
         {
         x}}、y: {
         {
         y}}</h3>
        <hr>
        <h3 v-if="loading">     ...</h3>
        <h3 v-else-if="errMsg">    : {
         {
         errMsg}}</h3>
        <ul v-else>
            <li>id: {
         {
         data.id}}</li>
            <li>address: {
         {
         data.address}}</li>
            <li>distance: {
         {
         data.distance}}</li>
        </ul>
        <hr>
        <!--      -->
        <ul v-for="item in data" :key="item.id">
            <li>id: {
         {
         item.id}}</li>
            <li>title: {
         {
         item.title}}</li>
            <li>price: {
         {
         item.price}}</li>
        </ul>
    </template>
    <script lang="ts">
    //              
    interface AddressData{
         
        id: number;
        address: string;
        distance: string;
    }
    interface ProductsData{
         
        id: string;
        title: string;
        price: number;
    }
    import {
          defineComponent, watch } from 'vue'
    import useMousePosition from './hooks/useMousePosition'
    import useRequest from './hooks/useRequest'
      export default defineComponent({
         
          name: 'App',
          
          setup(){
         
              //            
              const {
         x, y} = useMousePosition()
              
              //     
            //   const {loading, data, errMsg} = useRequest('/data/address.json')  //         
              const {
         loading, data, errMsg} = useRequest<ProductsData[]>('/data/products.json') //         
    
              //   
              watch(data, ()=>{
         
                  if (data.value) {
         
                      console.log(data.value.length);
                  }
              })
              return {
         
                  x,
                  y,
                  loading,
                  data,
                  errMsg
              }
          }
      })
      
      
    </script>
    
    

    toRefs
    応答型オブジェクトを通常オブジェクトに変換します.この通常オブジェクトの各propertyはrefオブジェクトです.
    <template>
      <h2>toRefs    </h2>
      <h4>               ,         property     ref  </h4>
      <h3>name: {
         {
         state.name}}</h3>
      <h3>age: {
         {
         state.age}}</h3>
    
      <h3>name: {
         {
         name}}</h3>
      <h3>age: {
         {
         age}}</h3>
      <hr>
    </template>
    
    <script lang="ts">
    import {
         defineComponent, reactive, toRefs, ref} from 'vue'
    export default defineComponent({
         
     name: 'App',
     setup(){
         
         const state = reactive({
         
            name: '  ',
            age: 20
        })
        // const state2 = toRefs(state)
        // console.log('state: ', state);
        // console.log('state2: ', state2);
        const {
         name, age} = toRefs(state)
    
        //             
        setInterval(() => {
         
            state.name += "1"
            state.age += 1
            // state2.name.value += "2"
            // state2.age.value += 2
            // name += '3'  // error
            // age += 3     // error
        }, 1500);
    
        return{
         
            state,
            // ...state,    //                
            // ...state2,
            name,
            age
        }
     }
    })
    </script>