Vue3 New Features Built-in Component <Teleport>

Any portal - Teleport

The combined API for Vue3 and the Proxy-based Response Principle have been described in many articles, in addition to these more eye-catching updates.
Vue3 also added a built-in component: Teleport . The main purpose of this component is to move DOM elements within a template to other locations.

Why do we need Teleport

Teleport is a technology that can move our templates to locations other than Vue app in the DOM, which is a bit like the "any door" of the Dora A Dream

scene

Elements like modals,toast, etc. are in many cases easier to manage by completely stripping them off from the DOM of our Vue application

Reason

The reason is that if we are nested inside a component of a Vue, it can be difficult to handle the positioning, z-index, and style of the nested component

  • In addition, elements such as modals,toast, and so on need to use the value of the state (data or props) of the Vue component
  • This is where Teleport comes in. We can write template code in the logical location of the component, which means we can use the component's data or props. Then render it outside the scope of the Vue application

teleport (API)

  • to prop erty--> string type. Pro is required and must be a valid query selector or HTMLElement (if used in a browser environment). Specify the target element in which the content will be moved
<!-- Correct -->
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />
<!-- error -->
<teleport to="h1" />
<teleport to="some-string" />
  • Disabled property--> Boolean type. This optional property can be used for disabled functionality, which means that its slot contents will not move anywhere but will be rendered at the location you specified in the surrounding parent component.
<teleport to="#popup" :disabled="displayVideoInline">
  <video src="./my-movie.mp4">
</teleport>

Be careful:

This will move the actual DOM node instead of being destroyed and recreated, and it will keep any component instances active. All stateful HTML elements (that is, played videos) will remain in their state.

Teleport component uses

A common scenario is to create a component that contains full screen mode. In most cases, you want the logic of a modal box to exist in a component, but fast positioning of a modal box can be difficult with CSS, or you need to change the component combination.

Consider the following HTML structure:

<body>
  <div style="position: relative;">
    <h3>Tooltips with Vue 3 Teleport</h3>
    <div>
      <modal-button></modal-button>
    </div>
  </div>
</body>

Let's look at the modal-button component:

The component will have a button element to trigger the opening of the modal box, and a div element with class.modal, which will contain the contents of the modal box and a button for self-closing.

const app = Vue.createApp({});

app.component('modal-button', {
  template: `
    <button @click="modalOpen = true">
        Open full screen modal!
    </button>

    <div v-if="modalOpen" class="modal">
      <div>
        I'm a modal! 
        <button @click="modalOpen = false">
          Close
        </button>
      </div>
    </div>
  `,
  data() {
    return { 
      modalOpen: false
    }
  }
})

When using this component in the initial HTML structure, we can see that the modal box is rendered in a deeply nested div, and the position:absolute of the modal box is referenced by a relatively positioned div of the parent.

Teleport provides a clean way to control which parent node in the DOM renders HTML without resorting to the global state or splitting it into two components.

Let's modify modal-button to use <teleport> And tell Vue "Teleport this HTML to the body tag".

app.component('modal-button', {
  template: `
    <button @click="modalOpen = true">
        Open full screen modal! (With teleport!)
    </button>

    <teleport to="body">
      <div v-if="modalOpen" class="modal">
        <div>
          I'm a teleported modal! 
          (My parent is "body")
          <button @click="modalOpen = false">
            Close
          </button>
        </div>
      </div>
    </teleport>
  `,
  data() {
    return { 
      modalOpen: false
    }
  }
})

Therefore, once we click the button to open the modal box, Vue will correctly render the contents of the modal box as children of the body tag.

Use with Vue components

If <teleport>contains a Vue component, it will remain the logical child of the parent component:

const app = Vue.createApp({
  template: `
    <h1>Root instance</h1>
    <parent-component />
  `
})

app.component('parent-component', {
  template: `
    <h2>This is a parent component</h2>
    <teleport to="#endofbody">
      <child-component name="John" />
    </teleport>
  `
})

app.component('child-component', {
  props: ['name'],
  template: `
    <div>Hello, {{ name }}</div>
  `
})

In this case, even if child-component is rendered in different places, it will still be a child of parent-component and will receive name prop from it.

This also means that the injection from the parent component will work, and in Vue Devtools you will see the child component nested beneath the parent instead of where it will actually be moved.

Use multiple teleport s on the same target

A common use case scenario is a reusable component that may have multiple instances active at the same time. In this case, multiple components can mount their contents to the same target element. The order will be a simple append -- later mounts will follow earlier mounts in the target element.

<teleport to="#modals">
  <div>A</div>
</teleport>
<teleport to="#modals">
  <div>B</div>
</teleport>

<!-- result-->
<div id="modals">
  <div>A</div>
  <div>B</div>
</div>

Tags: Javascript Front-end Vue

Posted on Fri, 03 Dec 2021 12:04:56 -0500 by goldfiles