Dynamic components

This is the 15th day of my participation in the August Text Challenge.More challenges in August

Dynamic components

What if we need to do v-if frequently on a page to determine what components need to be rendered

If there are too many conditions, the template logic can be cumbersome, and VUE provides dynamic components to simplify operations

Dynamic components use component components, implemented with a special attribute is

The passing and listening events on a dynamic component are exactly the same as on a normal component

<template>
  <div>
    <button
      v-for="tab in tabs"
      :key="tab"
      :class="{ active: activeTab === tab }"
      @click="changeTab(tab)"
    >
      {{ tab }}
    </button>

    <! The value of dynamic component is the component name that needs to be displayed (which is the registered component name) -->
    <component :is="activeTab" />
  </div>
</template>

<script>
import About from './components/About.vue'
import Home from './components/Home.vue'
import Category from './components/Category.vue'

export default {
  name: 'App'.components: {
    About,
    Home,
    Category
  },

  data: () = > ({
    tabs: [
      'Home'.'About'.'Category'].activeTab: 'Home'
  }),

  methods: {
    changeTab(v) {
      this.activeTab = v
    }
  }
}
</script>

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

keep-alive

By default, when we switch components, the old components are destroyed and re-created when we come back

However, there are situations in development where we want to keep the state of the component rather than destroy it

At this point we can use a built-in component: keep-alive

<keep-alive>
  <! When a component is switched, the old component will be cached.
  <component :is="activeTab" />
</keep-alive>
Copy the code

But when we do this, all components will be cached, and sometimes we only want some components to be cached

In this case, you can set an attribute to keep-alive

attribute The values instructions
include String or RegExp or Array Only components with matching names are cached

If multiple components are represented by string, they are separated by commas
exclude String or RegExp or Array Any component with a matching name will not be cached

If the value of exclude conflicts with that of include, exclude takes higher precedence

If multiple components are represented by string, they are separated by commas
max The number or string How many component instances can be cached, and once this number is reached,

Instances in the cache component that have not been accessed recently are destroyed

Note: It is important to note whether you use string or RegExp or Array

Instead of taking the name of the component, the value is taken from the name property in the component

<! -- Use commas between components when using strings -->
<keep-alive include="Home,Category">
   <component :is="activeTab" />
</keep-alive>
Copy the code
<! -- use regex -->
<keep-alive :include="/Home|Category/">
  <component :is="activeTab" />
</keep-alive>
Copy the code
<! -- Use array -->
<keep-alive :include="['Home', 'Category']">
  <component :is="activeTab" />
</keep-alive>
Copy the code

Asynchronous components

By default, during the process of building the entire component tree, webPack packs these component modules together at package time, since components are directly dependent on each other through modularity

At this point, as the project gets bigger and bigger, the size of the app.js file will get bigger and bigger, which will slow down the rendering speed of the first screen

So, for components that don’t need immediate use, we can separate them into smaller chunks of chunk.js

To do this, we are given a function in Vue :defineAsyncComponent

DefineAsyncComponent accepts two types of arguments:

Type 1: a factory function that returns a Promise object

<template>
  <div>
    <Home />
    <About />
  </div>
</template>

<script>
    import { defineAsyncComponent } from 'vue'
    // Asynchronously load components directly from script so that they can be registered in components
    // defineAsyncComponent returns the result we need to use
    const Home = defineAsyncComponent(() = > import('./components/Home.vue'))
    const About = defineAsyncComponent(() = > import('./components/About.vue'))

    export default {
      name: 'App'.components: {
        Home,
        About
      }
    }
</script>
Copy the code

Type 2: Accepts an object type and configures asynchronous functions

const Home = defineAsyncComponent({
  // The default component to display
  loader: () = > import('./components/Home.vue'),
  // The component is displayed when the component has not been loaded
  loadingComponent: Loader,
  // The component is displayed when the component load error occurs
  errorComponent: Error.// After 2s delay, loadingComponent is displayed
  delay: 2000.// In ms if the component has not been downloaded within the time specified in timeout
  // Whether an error is reported or not, it is considered a failure
  // The default is Infinity
  timeout: 0
})
Copy the code

In the real world, however, you might not need to configure as many attributes, so Vue provides a built-in component for that

Suspense is a built-in global component that has two slots

  • Default: Displays the content of default if it can be displayed
  • Fallback: If default cannot be displayed, the contents of the Fallback slot will be displayed
<suspense>
  <template #default>
     <About />
  </template>
  <! -- If the contents in the default slot cannot be displayed, the contents in the fallback slot cannot be displayed -->
  <template #fallback>
      <Home />
  </template>
</suspense>
Copy the code

$refs

In some cases, we can bind the element or component to a ref attribute if we want to retrieve the element object or subcomponent instance directly, but we do not recommend DOM manipulation directly in Vue development

$refs is an Object that stores all DOM elements and component instances registered with ref attributes

<! Register the corresponding component in refs
<About ref="about" />
Copy the code
/ / value
mounted() {
  console.log(this.$refs.title) // The native element gets the DOM object
  console.log(this.$refs.about) // The component gets the component instance object (proxy object)
  console.log(this.$refs.about.$el) // If you want to get the component's DOM object, you need to get its property $el
}
Copy the code

$parentand$root

attribute instructions
$parent The parent component element of the current component
$root The root component element generally refers to the App component

Note: the $children attribute has been removed from Vue3, so it is no longer usable

The component of v – model

We can use v-Model to do bidirectional binding in input, which now encapsulates a component that is used elsewhere, but also supports V-Model on components, similar to the.sync operator in VUe2

The parent component

<template>
  <div>
    <Home v-model="msg" />

    <! -- This is equivalent to -->
    <! -- So the child is actually passed modelValue, not MSG -->
    <Home :model-value="msg" @update:modelValue="msg = $event" />
    <! -- update:modelValue is the updated value in a special event subcomponent of the VUE that is passed directly as an event parameter -->
    
    <h2>{{ msg }}</h2>
  </div>
</template>

<script>
import Home from './components/Home.vue'

export default {
  name: 'App'.components: {
    Home
  },

  data() {
    return {
      msg: '123'}}}</script>
Copy the code

Child components

<template>
  <div>
    <input type="text" v-model="message">
  </div>
</template>

<script>
export default {
  name: 'Home'.props: {
    // The actual value passed in is modelValue, not MSG
    modelValue: String
  },

  emits: ['update:modelValue'].computed: {
    message: {
      get() {
        return this.modelValue
      },

      set(v) {
        this.$emit('update:modelValue', v)
      }
    }
  }
}
</script>
Copy the code

But in fact we might need multiple properties on a component that need to be bidirectionally bound,

At this point, v-Model cannot be used alone, and the property names passed cannot all be called ModelValues

So in practice, you can usually manually set the name of the props variable that you want to pass to the child component

The parent component

<template>
  <div>
    <! -- Use MSG instead of default modelValue -->
    <! V-model <Home V-model :foo="foo" V-model :bar="bar" /> -->
    <Home v-model:msg="msg" />

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

<script>
import Home from './components/Home.vue'

export default {
  name: 'App'.components: {
    Home
  },

  data() {
    return {
      msg: '123'}}}</script>
Copy the code

Child components

<template>
  <div>
    <input type="text" v-model="message">
  </div>
</template>

<script>
export default {
  name: 'Home'.props: {
    msg: String
  },

  emits: ['update:msg'].computed: {
    message: {
      get() {
        return this.msg
      },

      set(v) {
        this.$emit('update:msg', v)
      }
    }
  }
}
</script>
Copy the code

The life cycle

Each component may go through a series of processes from creation, mounting, updating, unmounting, and so on

At some point in the process, you might want to add some code logic of your own

Vue provides us with the component’s lifecycle functions for this purpose

Life cycle function

Lifecycle functions are hook functions that are called back at some point from within the Vue source code

By calling back to the lifecycle function, we can tell what stage the component is currently going through

Then we can write our own logical code in this lifecycle

The life cycle of the cache component

For cached components, we do not execute created or Mounted lifecycle functions on re-entry

But sometimes we do want to monitor when we re-enter a component and when we leave it

The lifecycle hook functions activated and deactivated can be used to listen

activated() {
  // This can play a similar role to created in caching components, called when the keep-alive cached component is activated
  // The created method executes with activated on the first load.
  // On the second entry, only the activated function is executed
  console.log('activated')},deactivated() {
  // This can play a similar role in the cache component to unmounted, when the keep-alive cache component is disabled
  // Deactivated is executed when the component is removed
  // Deactivated and unmounted are both executed when a component is destroyed.
  console.log('deactivated')}Copy the code

So in the cache component, we can use the activated and deactivated functions instead of the Created and unmouted functions