1. 程式人生 > 其它 >683 vue3的動態元件,keep-alive,快取元件的生命週期,非同步元件和Suspense,$refs,$parent和$root,生命週期,元件的v-model

683 vue3的動態元件,keep-alive,快取元件的生命週期,非同步元件和Suspense,$refs,$parent和$root,生命週期,元件的v-model

切換元件案例


v-if顯示不同的元件


動態元件的實現


動態元件的傳值


認識keep-alive


keep-alive屬性


快取元件的生命週期


App.vue

<template>
  <div>
    <button
      v-for="item in tabs"
      :key="item"
      @click="itemClick(item)"
      :class="{ active: currentTab === item }"
    >
      {{ item }}
    </button>

    <!-- 2.動態元件 -->
    <keep-alive include="home,about">
      <component
        :is="currentTab"
        name="coderwhy"
        :age="18"
        @pageClick="pageClick"
      >
      </component>
    </keep-alive>

    <!-- 1.v-if的判斷實現 -->
    <!-- <template v-if="currentTab === 'home'">
      <home></home>
    </template>
    <template v-else-if="currentTab === 'about'">
      <about></about>
    </template>
    <template v-else>
      <category></category>
    </template> -->
  </div>
</template>

<script>
  import Home from "./pages/Home.vue";
  import About from "./pages/About.vue";
  import Category from "./pages/Category.vue";

  export default {
    components: {
      Home,
      About,
      Category,
    },
    data() {
      return {
        tabs: ["home", "about", "category"],
        currentTab: "home",
      };
    },
    methods: {
      itemClick(item) {
        this.currentTab = item;
      },
      pageClick() {
        console.log("page內部發生了點選");
      },
    },
  };
</script>

<style scoped>
  .active {
    color: red;
  }
</style>

Home.vue

<template>
  <div @click="divClick">
    Home元件: {{name}} - {{age}}
  </div>
</template>

<script>
  export default {
    name: "home",  // home是字串
    props: {
      name: {
        type: String,
        default: ""
      },
      age: {
        type: Number,
        default: 0
      }
    },
    emits: ["pageClick"],
    methods: {
      divClick() {
        this.$emit("pageClick");
      }
    }
  }
</script>

<style scoped></style>

About.vue

<template>
  <div>
    <div>About元件</div>
    <button @click="counter++">{{ counter }}</button>
  </div>
</template>

<script>
  export default {
    name: "about",
    data() {
      return {
        counter: 0,
      };
    },
    created() {
      console.log("about created");
    },
    unmounted() {
      console.log("about unmounted");
    },
    activated() {
      console.log("about activated");
    },
    deactivated() {
      console.log("about deactivated");
    },
  };
</script>

<style scoped></style>

Category.vue

<template>
  <div>
    <div>Category元件</div>
    <button @click="counter++">{{ counter }}</button>
  </div>
</template>

<script>
  export default {
    name: "category",
    data() {
      return {
        counter: 0,
      };
    },
  };
</script>

<style scoped></style>

Webpack的程式碼分包


Vue中實現非同步元件


非同步元件的寫法二


非同步元件和Suspense


App.vue

<template>
  <div>
    App元件
    <home></home>

    <suspense>
      <template #default>
        <async-category></async-category>
      </template>
      <template #fallback>
        <loading></loading>
      </template>
    </suspense>
  </div>
</template>

<script>
  import { defineAsyncComponent } from "vue";

  import Home from "./Home.vue";
  import Loading from "./Loading.vue";

  // import AsyncCategory from './AsyncCategory.vue';
  const AsyncCategory = defineAsyncComponent(() =>
    import("./AsyncCategory.vue")
  );

  const AsyncCategory = defineAsyncComponent({
    loader: () => import("./AsyncCategory.vue"),
    loadingComponent: Loading,
    // errorComponent,
    // 在顯示loadingComponent元件之前, 等待多長時間
    delay: 2000,
    /**
     * err: 錯誤資訊,
     * retry: 函式, 呼叫retry嘗試重新載入
     * attempts: 記錄嘗試的次數
     */
    onError: function(err, retry, attempts) {},
  });

  export default {
    components: {
      Home,
      AsyncCategory,
      Loading,
    },
  };
</script>

<style scoped></style>

Home.vue

<template>
  <div>
    Home元件
  </div>
</template>

<script>
  export default {};
</script>

<style scoped></style>

Loading.vue

<template>
  <div>
    Loading
  </div>
</template>

<script>
  export default {};
</script>

<style scoped></style>

AsyncCategory.vue

<template>
  <div>
    <h2>{{ message }}</h2>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        message: "Hello Category",
      };
    },
  };
</script>

<style scoped></style>

$refs的使用


$parent和$root


App.vue

<template>
  <div>
    <!-- 繫結到一個元素上 -->
    <h2 ref="title">哈哈哈</h2>

    <!-- 繫結到一個元件例項上 -->
    <nav-bar ref="navBar"></nav-bar>

    <button @click="btnClick">獲取元素</button>
  </div>
</template>

<script>
  import NavBar from "./NavBar.vue";

  export default {
    components: {
      NavBar,
    },
    data() {
      return {
        names: ["abc", "cba"],
      };
    },
    methods: {
      btnClick() {
        console.log(this.$refs.title);

        console.log(this.$refs.navBar.message);
        this.$refs.navBar.sayHello();

        // $el
        console.log(this.$refs.navBar.$el);
      },
    },
  };
</script>

<style scoped></style>

<template>
  <div>
    <h2>NavBar</h2>
    <button @click="getParentAndRoot">獲取父元件和根元件</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        message: "我是NavBar中的message",
      };
    },
    methods: {
      sayHello() {
        console.log("Hello NavBar");
      },
      getParentAndRoot() {
        console.log(this.$parent);
        console.log(this.$root);
      },
    },
  };
</script>

<style scoped></style>

認識生命週期


生命週期的流程


App.vue

<template>
  <div>
    <button @click="isShow = !isShow">切換</button>
    <template v-if="isShow">
      <home></home>
    </template>
  </div>
</template>

<script>
  import Home from "./Home.vue";

  export default {
    components: {
      Home,
    },
    data() {
      return {
        isShow: true,
      };
    },
  };
</script>

<style scoped></style>

Home.vue

<template>
  <div>
    <h2 ref="title">{{ message }}</h2>
    <button @click="changeMessage">修改message</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        message: "Hello Home",
      };
    },
    methods: {
      changeMessage() {
        this.message = "你好啊, 哈哈";
      },
    },
    beforeCreate() {
      console.log("home beforeCreate");
    },
    created() {
      console.log("home created");
    },
    beforeMount() {
      console.log("home beforeMount");
    },
    mounted() {
      console.log("home mounted");
    },
    beforeUnmount() {
      console.log("home beforeUnmount");
    },
    unmounted() {
      console.log("home unmounted");
    },
    beforeUpdate() {
      console.log(this.$refs.title.innerHTML);
      console.log("home beforeUpdate");
    },
    updated() {
      console.log(this.$refs.title.innerHTML);
      console.log("home updated");
    },
  };
</script>

<style scoped></style>