9

" Combination API " is a new grammar extended by vue3. The grammar explained in the previous basic course is called " option API ". Both APIs are supported in vue3.

What is solved?

JS logic in the option API " combination API " can be further split. It is possible to data/computed/watch/ " into a separate declaration period (It can also be a separate file). Generally, the function after splitting is named "useXxx".
image.png

Split actual demand

Analyzing the shopping cart module in the figure below, I plan to into 2 parts (function) : one is used to obtain the shopping cart product data and the total price, and the other is used to calculate the discount coupon and calculate the total price after the discount The sub-tables are functions: " useGetCart " and " useCoupon ".
1.gif

setup structure

You must be very puzzled about disassembling the machine into two functions. The old "Option API" does not have the " methods look at the code format of the "Combination API", a new field." setup ", he is the logo attribute of "combination API", is a function , whose return value can be recognized and rendered by the template, similar to "data".

Pay special attention to the return values ​​of the two functions. They return data ( similar to data ) and functions ( similar to methods ). The actual function contains independent "watch/computed/life cycle hooks" The contents of "data" and "methods" of a vue component are grouped, which is why it is called "combined API".

<template>
  <article v-if="cart.length > 0">
    <ul>
      <li v-for="item in cart" :key="item.name">
        {{ item.name }} : {{ item.price }}元
        <input v-model="item.count" type="number" style="width: 48px" />
      </li>
    </ul>
    <h5 style="margin-left: 100px">原价:{{ totalPrice }}元</h5>
    <h5 style="margin-left: 100px; color: #f10">总价:{{ realTotalPrice }}元</h5>
    <button @click="createOrder">支付</button>
  </article>
</template>

<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
  name: 'Cart',

    setup(){
    // 购物车详情和总价
      const [cart,totalPrice,createOrder] = useGetCart();
    
    // 优惠后的价格
    const realTotalPrice = useCoupon();
    
    // 返回模板识别的数据,和data定义的数据一样
    return {cart,totalPrice,realTotalPrice,createOrder};
  }
});
</script>

Internal realization of "useXxx" function

This "use" as a function name prefix is ​​a naming convention, there is no limit to the actual name. "watch/computed/lifecycle hook" in each function, they all appear in the form of a function.

import {computed} from 'vue';
/**
 * 获取购物车详情
 */
function useGetCart() {
  //  购物车详情(reactive)
  const cart = reactive<{ name: string; count: number; price: number }[]>([]);

  // 模拟异步请求
  setTimeout(() => {
    cart.push(
      { name: "苹果", count: 10, price: 10 },
      { name: "香蕉", count: 20, price: 20 }
    );
  }, 1000);

  // 总价格(computed)
  const totalPrice = computed(() => {
    return cart.reduce((total, item) => item.count * item.price + total, 0);
  });

  return [cart, totalPrice] as const;
}

There is a new function " ref ", which is used to "define response data". Next we will talk about what "ref" is.

Note

  1. "as const" array type is represented assertion Ganso, if you forget the content of ts part, before later learning knowledge, can review under ts .
  2. There is only the "on" prefix in front of the hook name of the life cycle, such as mounted => onMounted

    Define response data (reactive/ref)

    "Response data" is the data that changes in value can drive dom to change. The data we data " is the response data. But if we want to define data setup data" "Function , replaced by " reactive/ref " function :

    reactive

    Define response data, input can only be object type , and return the response version of the input object.

    <template>
     <h1>{{count}}</h1>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    export default defineComponent({
     setup(){
     return reactive({count:99});
      }
    });
    </script>

    image.png
    The actual this case can not "reactive" , as a result, but if the "count" data is modified, it will not automatically change the interface, always show "99."

    ref

    The same is to define the response data. The difference from "reactive" is that the format of the return value response data is different, and the data returned by ref needs to be accessed with ".value".

    const n = ref(110);
    console.log(n);

    image.png
    You can see that the return value is in the value field. This is done because the monitoring of data changes in js only supports "reference data types". For string and number types, if you need to monitor, you need to construct an object, so here ref needs to construct one variable: {value 110} of

    The choice of reactive and ref

    Important : If the data to be monitored is reference data (object) then use reactive, if it is (number/boolean/string) and other primitive data types, use ref.

    Encapsulation function (useXxx)

    Now we look back at the implementation of 2 functions.

    useGetCart

    Return the product information and total price in the shopping cart, the total price uses the "calculated attribute" function (computed), and we encapsulate the "generate order" function, because it needs the shopping cart product information as a parameter, so we do both As a group.

    import {computed} from 'vue';
    /**
     * 获取购物车详情
     */
    function useGetCart() {
      //  购物车详情(reactive)
      const cart = reactive<{ name: string; count: number; price: number }[]>([]);
    
      // 模拟异步请求
      setTimeout(() => {
     cart.push(
       { name: "苹果", count: 10, price: 10 },
       { name: "香蕉", count: 20, price: 20 }
     );
      }, 1000);
    
      // 总价格(computed)
      const totalPrice = computed(() => {
     return cart.reduce((total, item) => item.count * item.price + total, 0);
      });
      
      
      // 生成订单(methods)
      function createOrder(){
       // 模拟生成订单
     setTimeout(()=>{
         console.log(`成功购买${cart.length}件商品`);
     },1000)
      }
    
      return [cart, totalPrice,createOrder] as const;
    }

    useCoupon

    Get the discount amount, and return to calculate the discount amount. Use watch to monitor the "total price", recalculate the "post discount total price" when it changes, and use "onMounted" to control the timing of the data request trigger (this example has no practical meaning, This is only to show the usage of "onMounted").

    import {watch,onMounted} from 'vue';
    /**
     * 获取优惠劵
     */
    function useCoupon(totalPrice: Ref<number>) {
      const realTotalPrice = ref(0);
      // 此处实际可以不用onMouted,
      // 仅仅为了演示用法
      onMounted(() => {
     // 模拟异步请求
     setTimeout(() => {
       const coupon = 9;
       watch(
         totalPrice,
         (value) => {
           realTotalPrice.value = value - coupon;
         },
         { immediate: true }
       );
     }, 1000);
      });
    
      return realTotalPrice;
    }

    "watch" is a function, and its second parameter is an object. There is a field "immediate" which means the callback is executed after initialization, and "deep" means the deep monitoring data (object).

Complete source code

https://github.com/any86/vue3-start/blob/master/src/views/Setup.vue

WeChat group

Thank you for reading. If you have any questions, you can add me to WeChat. I will pull you into the WeChat group (due to Tencent’s 100-member limit on WeChat groups, group members must be pulled in after more than 100 people)

To be continued

latest developments, please pay attention to my language bird

www.yuque.com_russell-qqjgt_rfbdgd(iPhone X).png


铁皮饭盒
5k 声望1.2k 粉丝

喜欢写程序: [链接]