This article was first published on the WeChat public account: Big Move to the World, my WeChat: qq449245884, I will share with you the front-end industry trends, learning methods, etc. as soon as possible.
For more open source works, please see GitHub https://github.com/qq449245884/xiaozhi , including the complete test sites, materials and my series of articles for interviews with first-tier manufacturers.

With the release of Vue 3.2, a new composition tool is provided to us, called expose .

Have you ever created a component that needs to provide some methods and properties to the template, but you want those methods to be private to the component and not be called by the parent class?

If you are developing an open source component or library, you may want to keep some internal methods private. Before Vue 3.2 this was not easy to achieve because all the methods or data etc declared in the options API were public so templates could access it.

The same goes for the composition API. Everything we return from the setup method can be directly accessed by the parent class.

Combining APIs

Let's look at a practical example. Imagine we have a component that creates a counter that is updated every second.

MyCounter.vue

 <template>
    <p>Counter: {{ counter }}</p>

    <button @click="reset">Reset</button>
    <button @click="terminate">☠️</button>
</template>

<script>
import { ref } from 'vue'

export default {
  setup () {
    const counter = ref(0)

    const interval = setInterval(() => {
      counter.value++
    }, 1000)

    const reset = () => {
      counter.value = 0
    }

    const terminate = () => {
      clearInterval(interval)
    }

    return {
      counter,
      reset,
      terminate
    }
  }
}
</script>

From a composition standpoint, I want the parent component to be able to directly call the reset method when needed -- but I want to keep a reference to the terminate function and counter Only available for components.

If we instantiate this component into a parent class, say App.vue, and attach a ref reference to it, we can easily have the parent class call the reset method, because when we start from setup When returning it in setup , it was already exposed along with terminate .

App.vue

 <template>
  <MyCounter ref="counter" />

  <button @click="reset">Reset from parent</button>
  <button @click="terminate">Terminate from parent</button>
</template>

<script>
import MyCounter from '@/components/MyCounter.vue'

export default {
  name: 'App',
  components: {
    MyCounter
  },
  methods: {
    reset () {
      this.$refs.counter.reset()
    },
    terminate () {
      this.$refs.counter.terminate()
    }
  }
}
</script>

If you run this now, and click the reset or kill button, both work.

Let's be explicit about what we want to expose ( expose ) to the parent class so that only the reset function is available.

MyCounter.vue

 <script>
import { ref } from 'vue'

export default {
  setup (props, context) {
    const counter = ref(null)

    const interval = setInterval(() => {
      counter.value++
    }, 1000)

    const reset = () => {
      counter.value = 0
    }

    const terminate = () => {
      console.log(interval)
      clearInterval(interval)
    }

    context.expose({ reset })

    return {
      counter,
      reset,
      terminate
    }
  }
}
</script>

Here, we have added props and context parameters to the ---a2d34b52c86f07d1fd950ea378caaec1 setup function. We need to have context available because this is where the expose function is located. We can also use refactoring like this: { expose } .

Next, we use context.expose to declare an element object that we want to expose to the parent class that instantiates this component; in this example, we only intend to make the reset functionality available.

If we run the example again and click the "Terminate from parent" button, we'll get an error.

 Uncaught TypeError: this.$refs.counter.terminate is not a function

terminate The functionality is no longer available and our private API is now inaccessible.

Options API

Above we used ---3a7f880e6f49314ef26c918edade32c2 composition API in exponse , but this method can also be used in the options API. We can rewrite it as follows.

 //  MyCounter.vue


export default {
  created () { ... },
  data: () => ({ counter: null }),
  methods: {
    reset () { ... },
    terminate () { ... }
  },
  expose: ['reset']
}

Note that we've added a new Options API property expose that allows us to pass in an array where the string 'reset' is the name of the function we expose.

Combining API rendering capabilities

The way to create a powerful and flexible component is to harness the power of render functions. This is not new to Vue 3, but with the establishment of the composition API, we now have the flexibility to return the composition API h function directly from the setup method.

This creates a problem because in our setup function, the entire return statement is just the h method that contains the node the component is creating.

If at this point we choose to expose something to the parent class, we have the opposite problem to what we saw earlier. Nothing is exposed because nothing is returned except the DOM element.

Let's rewrite the MyCounter.vue component to use this method.

 <script>
// The template has been deleted
import { ref, h } from 'vue'

export default {
  setup (props, context) {
    const counter = ref(0)

    const interval = setInterval(() => {
      counter.value++
    }, 1000)

    const reset = () => {
      counter.value = 0
    }

    const terminate = () => {
      clearInterval(interval)
    }

    // context.expose({ reset })

    return () => h('div', [
      h('p', `Counter: ${counter.value}`),
      h('button', { onClick: reset }, 'Reset'),
      h('button', { onClick: terminate }, 'Terminate')
    ])
  }
}
</script>

Note that we imported h from Vue at the top, because we need it to create our DOM elements.

To illustrate the problem, the context.expose method is temporarily annotated.

The return statement now replicates the DOM structure from our previous <template> and if we run the example, we can click the reset and terminate buttons on the element correctly.

However, if we now click the "Reset from parent" button, we will encounter an error.

 Uncaught TypeError: this.$refs.counter.reset is not a function

reset method is no longer exposed because it was not returned by the setup function. To fix this, we need to cancel the call to context.expose to make it available again.

Summarize

The new expose method is very intuitive and easy to implement in our component. It clears up some very important compositional issues that in the past even required rewriting a complete component, so even if it's not an API you use every day, it's worth keeping in our folder for ashes.


The bugs that may exist after the code is deployed cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, I recommend a useful bug monitoring tool , Fundebug .

Author: Marina Mosti Translator: Front-end Xiaozhi Source: vuemastery

Original: https://www.vuemastery.com/blog/understanding-vue-3-expose/

comminicate

If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.

This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.


王大冶
68.1k 声望105k 粉丝