As we all know, the small program is not a single page application, each of its pages is an independent WebView, and because there is no rendering ability can span multiple pages, so there is no way to achieve global can span multiple pages of components.
But the crowd has the wisdom, so we trouble point, each page manually introduced components, anyway, we can finally achieve, is a hole filled. There are a variety of specific implementation schemes, each with its own strengths. Both the rendering experience and the coding call experience are so different that it is difficult to detail.
This article describes a good implementation, using uni-App as an example (native, as well as other frameworks), to implement the global component step by step.
Before we begin, let’s take a quick look at the page stack of the applet.
- Each page is a separate WebView
- The bottom Tab page is fixed, once opened it is created once and never destroyed, and when switched back to the page it is placed again at the top of the page stack
- Other non-tab pages will be created once when opened and placed at the top of the page stack; When opening a new page, the new page is placed at the top, the old page is pressed under; When you return to the previous page, the current page is destroyed and the previous page is replaced at the top of the page stack
Implementing global components that span multiple pages is complicated because of the page stack and the independence and isolation of each page.
In theory, there is no way to truly implement a global component that covers all pages. But we can simulate it, and the difference is that we can simulate a global component that has a good experience.
First, let’s set a few goals:
- Write less code
- Keep it simple and easy to use
- Support for multiple components
Encapsulate a component container
Encapsulate a component container by introducing multiple components into the container so that we can only introduce the component container once on the Page, which is equivalent to introducing all global components.
To reduce implementation and usage complexity, the component container is simply a component container. In addition, we also encapsulate simple component registration functions here.
<! -- leaf.vue -->
<template>
<view>
<image-edit />
<notification />
<alert />
</view>
</template>
<script>
/ / global API
uni.$leaf = {
$register(vm, name) { // Register the component
if(! uni.$leaf[name]) {// Register the component API according to name
uni.$leaf[name] = (data) = > {
// For "ease of use", return Promise
return Promise((resolve, reject) = > {
const pages = getCurrentPages()
let vm = pages[pages.length - 1]
// #ifdef MP-WEIXIN
vm = vm.$vm
// #endif
uni.$emit('leaf/' + name, {
$route: vm.$route, // It is used to distinguish the current page stack
data,
resolve,
reject,
})
})
}
}
// Encapsulate events to simplify custom components
const handler = (e) = > {
if(e.$route ! == vm.$route || e.$stop) {return
}
// Only the page at the top of the stack can get events,
// This ensures that no matter which page or subcomponent of the page is making the API call,
// can be immediately displayed in front of the user
e.$stop = true
// Invoke event listening on the component
vm.leafHandler(e)
}
uni.$on('leaf/' + name, handler)
vm.$on('hook:beforeDestroy'.() = > {
uni.$off('leaf/' + name, handler)
})
},
}
import ImageEdit from './image-edit'
import notification from './notification'
import alert from './alert'
export default {
components: {
ImageEdit,
notification,
alert,
},
}
</script>
Copy the code
We can import the component container directly into the Page.
<! -- index.vue -->
<template>
<view>
<leaf />
</view>
</template>
<script>
import leaf from '@/components/leaf'
export default {
components: {
leaf,
},
}
</script>
Copy the code
Define components
When defining a component, you need to register it and provide an event listener function to handle API calls. We try to keep it simple.
<! -- alert.vue -->
<template>
<uni-popup ref="popup">
<view>{{content}}</view>
<button @click="confirm">determine</button>
<button @click="cancel">cancel</button>
</uni-popup>
</template>
<script>
export default {
data() {
return {
content: ' ',}},created() {
// Register the component
uni.$leaf.$register(this.'alert')},methods: {
leafHandler(e) {
const { data } = e
this.content = data.content
this.$e = e // Cache events
this.$refs.popup.open()
},
confirm() {
this.$refs.popup.close()
// Ahhh, we can use promises to manage component state and do whatever we want,
// The implementation of this API is humanized.
this.$e.resolve()
},
cancel() {
this.$refs.popup.close()
this.$e.reject()
},
},
}
</script>
Copy the code
3.
We can now use global components simply, conveniently, and humanely. The reason why Promise is used in front of the package is to humanize the use here, simple and easy to use is pleasant.
<! -- index.vue -->
<template>
<view>
<button @click="testAlert">Test the pop-up box</button>
<leaf />
</view>
</template>
<script>
import leaf from '@/components/leaf'
export default {
components: {
leaf,
},
methods: {
async testAlert() {
try {
// Simply test the effect with minimal code
await uni.$leaf.alert({ content: 'Do you think this plan is ok? '})}catch (error) {
uni.showToast({ title: 'Any suggestions? '},},}</script>
Copy the code
conclusion
The goals defined above should, perhaps, probably, be achieved.
Keep an eye on
The next article introduces an easy-to-use, user-friendly implementation of applets that only obtain user authorization when needed. This is a very common, very reasonable need to improve the user experience, but it is generally not easy to implement, and the actual handwriting practice is somewhat unpleasant. Then wait for a good solution to implement, please pay attention to ha.