vue3.0实战从0到1实战电商管理系统(第二天)

8,163 阅读8分钟

章节文章课程简介:

任何事情都需要时间的沉淀,技术也不例外,今天编写Vue3.0系列的章节文章,只是希望能够比别人更早的去尝鲜一些新的技术,毕竟Vue3.0已经Beta版本了,所以里正式版本也不远了,提前去学习和了解,我们就会比别人有更多的时间去充分理解Vue3.0的特性,只有当你真正理解一门技术的时候,才能够正确的判定它是否合适、是否应该运用到你当前的实际项目当中去。

  • 第一天:浅谈vue3.0、初始化项目之:Hello World Vue3.0
  • 第二天:Api实战之:vue-composition 我是api调用工程师
  • 第三天:vue3如何实现逻辑复用
  • 第四天:实战之:高解耦式mock api的设计与订单列表查询
  • 第五天:如何实现代码优化

今天是第二天:Api实战之:vue-composition 我是api调用工程师

学习任何框架之前,首先肯定要学习的是它的生命周期,Vue3.0的所有生命周期函数都是在setup函数中定义,具体包含生命周期机器定义如下:

import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onRenderTracked,
  onRenderTriggered,
} from "vue";
export default {
  setup() {
    console.log("setup");
    onRenderTracked(() => {
      console.log("onRenderTracked");
    });
    onRenderTriggered((event) => {
      console.log('onRenderTriggered')
    });
    onBeforeMount(() => {
      console.log("onBeforeMount");
    });
    onMounted(() => {
      console.log("onMounted");
    });
    onBeforeUpdate(() => {
      console.log("onBeforeUpdate");
    });
    onUpdated(() => {
      console.log("onUpdated");
    });
    onBeforeUnmount(() => {
      console.log("beforeDestroy");
    });
    onUnmounted(() => {
      console.log("onUnmounted");
    });
    onErrorCaptured(() => {
      console.log("onErrorCaptured");
    });
    return {
    };
  },
};

Vue3.0组件生命周期图

alt vue3.0

Vue3.0 vue-composition Api的使用

  • (1) setup() setup() 函数是 vue3 中统一的入口函数,所有生命周期函数定义都是需要定义在次函数下才生效,setup 函数中无法访问到 this,所有的组件参数都是通过,setup函数中包含props和context参数,props参数默认是响应式的

首先我们先创建一个组件如下:

export default {
  setup() {
      console.log("组件入口函数");
  }
}

components/user,vue

<template>
  <section>
    <h2>我是:{{ userName }}</h2>
  </section>
</template>
export default {
  props: {
  userName: String
 },
  setup(props,context) {
    // context.attrs
    // context.slots
    // context.parent
    // context.root
    // context.emit
    // context.refs
      console.log(`组件传递props${props.userName}`);
      console.log(`组件的上下文对象${context}`);
  },
};

然后在App.vue页面中使用它

src/App,vue

<template>
  <section>
    <h2>Hello World Vue3.0</h2>
    <com-user :userName="'虎克小哥哥'"/>
    <br/>
  </section>
</template>
import ComUser from "./components/user.vue"
export default {
  components:{
    ComUser
  },
  setup() {
    return {
    };
  },
};
  • (2) reactive() 函数接收一个普通对象,返回一个响应式的数据对象,支持Map、Set、WeakSet、WeakMap数据结构
<template>
  <section>
    <h2>Hello World Vue3.0</h2>
    <h3>我是:{{userInfo.userName}}</h3>
    <br/>
  </section>
</template>
import { reactive } from "vue";
export default {
  setup() {
    const userInfo=reactive({userName:"虎克小哥哥"});
    return {
      userInfo
    };
  },
};
  • (3) ref() 函数用来根据给定的值创建一个响应式的数据对象,ref() 函数调用的返回值是一个对象,这个对象上只包含一个 .value 属性。

    <template>
      <section>
        <h2>Hello World Vue3.0</h2>
        <h3>我叫虎克小哥哥,来自:{{city}}</h3>
        <button @click="getUserCity">你来自哪里?</button>
        <br/>
      </section>
    </template>
    
    import { ref } from "vue";
    export default {
      setup() {
        const city=ref("");
        const getUserCity=()=>{
          city.value="上海";
        }
        return {
          city
        };
      },
    };
    
    
    
    
    
  • (4) isRef() 用来判断某个值是否为 ref() 创建出来的对象。 isProxy、isReactive、isReadonly都大同小异

 <template>
   <section>
     <h2>Hello World Vue3.0</h2>
     <h3>{{Msg}}</h3>
     <button @click="getUserInfo">你来自哪里?</button>
     <br/>
   </section>
 </template>
import { isRef } from "vue";
export default {
  setup() {
    const userName=ref("虎克小哥哥");
    const city=ref("上海");
    const Msg=ref("");
    const getUserInfo=()=>{
      if(isRef(userName)){
        Msg.value=`我叫:${userName.value},來自${city.value}`
      }else{
        Msg.value=`我叫:${userName.value}`
      }
    }
    return {
      Msg,
      getUserInfo
    };
  },
};

  • (5) toRefs() 函数可以将 reactive() 创建出来的响应式对象,转换为普通的对象,就是可以將reactive多层对象类型的响应对象,转化为普通类型的响应数据
<template>
  <section>
    <h2>Hello World Vue3.0</h2>
    <h3>转换reactive类型数据{{userInfo.userName}}</h3>
    <h3>转换reactive类型数据{{code}}</h3>
    <br/>
  </section>
</template>
import { reactive,toRefs } from "vue";
export default {
  setup() {
    const data=reactive({
      userInfo:{
        userName:"虎克小哥哥"
      },
       code:200
    });
   }
    return {
       ...toRefs(data),
    };
  },
};
  • (6) computed() 计算属性 传入一个 function 函数,可以得到一个只读的计算属性 传入一个对象可以自定义get set函数 返回一个响的应式ref对象
<template>
  <section>
    <h2>Hello World Vue3.0</h2>
    请输入年龄:<input type="text" v-model="age">
    <br/><br/>
    我的年龄是:{{userMsg}}
    <br/>
  </section>
</template>
import { ref,computed } from "vue";
export default {
  setup() {
    const age = ref("");
    //传入函数的方式
    const userMsg = computed(() =>{
      return `我的年龄是:`+age.value
    })

    //传入对象自定义get set的形式
    const userMsg = computed({
    get(){
      return `我的年龄是:`+age.value
    },
    set(val){
      age.value=val;
    }
   })
  // 返回的userMsg是一个响应式的ref对象
   userMsg.value="";
    return {
      age,
      userMsg
    };
  },
};
  • (7) watch() 监听函数
<template>
  <section>
    <h2>Hello World Vue3.0</h2>
    请输入地址:<input type="text" v-model="city">
    请输入年龄:<input type="text" v-model="age">
     <button @click="stop">不想给你知道我的年龄</button>
    <br/>
  </section>
</template>
import { ref,watch } from "vue";
export default {
  setup() {
     const city=ref("上海");
        //定义方式1 内部的响应对象改变就触发监听,默认会触发深度监听,
        //初始化的时候会执行一次
        //返回一个监听实例函数
       const stop = watch(() => {
          console.log("我的年龄在增长:",age.value)
        },{
            lazy: false // 是否触发深度监听
       })
       //调用监听实例函数,可以停止监听
       //stop()

        //监听某个响应对象 
       const stop =  watch(
          () => age.value,
          (age, prevAge) => {
             console.log("age:",age,"prevAge",prevAge)
          }
        )
        //监听多个响应对象
        const stop = watch(
          [
          () => age.value, 
          () => city.value, 
          ],
          (
            [age, city], 
            [prevage, prevcity], 
          ) => {
            console.log("age:",age,"prevage",prevage)
            console.log("city:",city,"prevcity",prevcity)
          },
          {
            lazy: true // 是否触发深度监听
          }
      )
    return {
       stop
    };
  },
};
  • (8) provide & inject 共享普通数据,轻轻松松垮多级组件的数据传递(不限层级,可以说是优点也可以说是缺点,因为命名规则稍有不规范就会显得数据维护性降低bug满天飞,层级过深的时候也不是很直观) provide() 和 inject() 可以实现嵌套组件之间的数据传递。父级组件中使用 provide() 函数向下传递数据;子级组件中使用 inject() 获取上层传递过来的数据

1 (父组件传值子、孙子组件)

Achild.vue 孙子组件

 <template>
  <section>
   <div>孙子组件</div>
   <img style="width:50px;height:50px" :src="pic"/>
  </section>
</template>

<script>
import { inject } from 'vue'
export default {
  setup() {
    //A组件获取父组件传递过来的帅气头像数据
    const pic = inject('pic')
    return {pic}
  },
};
</script>

A.vue 子组件

<template>
<section>
 <div>子组件</div>
 <com-achild/>
</section>
</template>

<script>
import ComAchild from "./components/Achild.vue";
export default {
 components:{
  ComAchild,
},
};
</script>

App.vue 根组件

<template>
  <section>
   <com-a/>
  </section>
</template>

import ComA from "./components/A.vue";
import {provide,ref} from "vue";
const pic='https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1461286262,427682797&fm=26&gp=0.jpg'
export default {
   components:{
    ComA,
  },
  setup() {
    //父组件冒泡共享数据pic
    provide('pic',pic )
    //也支持传递响应式数据
    const pic = ref('pic');
    provide('pic',pic)
  },
};

  • (9) ref 组件实例获取

App.vue

<template>
  <section>
    <com-a ref="comRef"/>
  </section>
</template>
import { ref,onMounted } from "vue";
import ComA from "./components/A.vue";
export default {
 components:{
  ComA,
 },
  setup() {
     const comRef = ref(null);
    //需要在domx渲染类型的生命周期后使用
    onMounted(() => {
      //获取子组件实例,调用其内部函数
      console.log(comRef.value.getName())
    })
    return {
      comRef
    };
   },
};

子组件A.vue

<template>
<section>
  我是子组件
</section>
</template>

export default {
    setup(){
        //子组件中的函数 
        const getName=()=>{
            return "我是测试数据"
        }
        return{
            getName
        }
    }
};
  • (10) 高级反应性API customRef: 这个是真的香,创建一个可以控制其get set触发更新的引用对象,返回一个响应式的ref对象 markRaw:标记一个对象,使其永远不会转换为代理。返回对象本身

App.vue

<template>
  <section>
    轻轻松松实现防抖
    {{text}}
    <input v-model="text"/>
  </section>
</template>
import { customRef } from "vue";
//只需要返回一个响应Ref对象,可自定义其get set
const useDebounce=(value, delay = 10000)=>{//10000秒之后才会更新text的值
  return customRef((track, trigger) => {
    let timeout
    return {
      get() {
        track()//必须调用次函数才会触发更新
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()//必须调用次函数才会触发更新
        }, delay)
      }
    }
 })
}
export default {
  setup() {
    return {
      text:useDebounce()
    };
   },
};
- (11) 高级反应性API 

markRaw:标记一个对象,使其永远不会转换为代理。返回对象本身 shallowRef:创建一个引用来跟踪其自身的.value突变,但不会使其值具有反应性(意思就是)

App.vue

<template>
  <section></section>
</template>
import { markRaw } from "vue";
export default {
  setup() {
    const foo = markRaw({
     nested:true
    })
    const bar = reactive({
      nested: foo.nested
    })
    console.log(bar)
    console.log(foo)
   },
};

foo对象未被代理,最常见的运用场景就是大数据的列表页面,列表数据不会纯展示性质的,不会涉及到修改,也就没必要去深度代理了。其实和冻结对象差不多,明白其意思根据具体场景使用即可,跳过代理转换可以提高性能

alt vue3.0

第一天:浅谈vue3.0、初始化项目之:Hello World Vue3.0

第三天:vue3如何实现逻辑复用

🎨 原创不易,支持请点赞、转发