How to develop a global elastic layer component in uni-app? The following article will introduce to you through examples how to implement a global elastic layer component in uni-app. I hope it will be helpful to you!
The company has an app written using the uni-app framework. The elastic layer inside is basically implemented using the official uni.showModal API. , the performance on the device is the native elastic layer. At the customer's request, it needs to be replaced with the designed style, so we started to implement such a component.
According to the methods and methods often used by the elastic layer, the properties and methods it needs can be roughly listed:
alert/confirm
, etc. promise
, can use $api. xx().then
The first few items are easy to do, just define the fields in data
, and directly use the official wheeluni in the outer layer -popup
, so you need to write less logic for controlling pop-up (lazy), so that the general structure is written
// template部分 <uni-popup ref="popup" :maskClick="maskClick"> <view class="st-layer" :style="{ width: width }"> <view class="st-layer__content"> <!-- #ifndef APP-NVUE --> <text class="st-layer__icon" :class="option.iconClass || getIconClass()" v-if="option.type !== 'none' && option.showIcon"></text> <!-- #endif --> <view class="st-layer__msg" v-if="option.msg"> <text>{{ option.msg }}</text> </view> </view> <view class="st-layer__footer" :class="{'is-reverse-cofirmcancel' : isReverseConfirmCancel}" v-if="option.showConfirmButton || option.showCancelButton"> <view class="st-layer__footer__btn st-layer__footer__btn--confirm" @tap.stop="confirmClick" v-if="option.showConfirmButton"><text>确认</text></view> <view class="st-layer__footer__btn st-layer__footer__btn--cancel" @tap.stop="cancelClick" v-if="option.showCancelButton"><text>取消</text></view> </view> </view> </uni-popup>
Then the js part first simply implements some open and close methods
data() { return { option: {} } }, methods: { open(option) { let defaultOption = { showCancelButton: false, // 是否显示取消按钮 cancelButtonText: '取消', // 取消按钮文字 showConfirmButton: true, // 是否显示确认按钮 confirmButtonText: '取消', // 确认按钮文字 showIcon: true, // 是否显示图标 iconClass: null, // 图标class自定义 type: 'none', // 类型 confirm: null, // 点击确认后的逻辑 cancel: null, // 点击取消后的逻辑 msg: '' } this.option = Object.assign({}, defaultOption, option) this.$refs.popup.open() }, close() { this.$refs.popup.close() }, confirmClick() { const confirmHandler = this.option.confirm if (confirmHandler && typeof confirmHandler === 'function') { confirmHandler() } this.close() this.$emit('confirm') }, cancelClick() { const cancelHandler = this.option.cancel if (cancelHandler && typeof cancelHandler === 'function') { cancelHandler() } this.close() this.$emit('cancel') } }
Currently available on other pages
// test.vue 可以使用uni-app的 [easycom组件规范](https://uniapp.dcloud.io/component/README?id=easycom%e7%bb%84%e4%bb%b6%e8%a7%84%e8%8c%83),不用写import语句 <st-layer ref="stLayer"></st-layer> // js部分 this.$refs.stLayer.open({ msg: '测试', confirm: () => { console.log('点击了确认') }, cancel: () => { console.log('点击了取消') } })
Now the basic functions have been implemented, but someone wants to say that it is inconvenient to call like this. I want to call like this
open(msg).then(() => { console.log('点击了确认') }).catch(() => { console.log('点击了取消') })
How to implement it What about promise
? The simplest way is to let the open method return a promise
. How to enter the then
method when clicking confirm or cancel? See the following writing method
... open() { return new promise((reoslve, reject) => { ... this.option.confirm = this.option.confirm || function confirmResolve () { resolve() } this.option.cancel = this.option.cancel || function cancelReject () { reject() } }) } ...
If you want to encapsulate other separate methods, such as confirm
, you can Extended based on open:
confirm(msg, option = {}) { if (typeof msg === 'object') { option = msg } else { option.msg = msg } return this.open({ ...option, showCancelButton: true, type: 'confirm' }) } // 调用方式 this.$refs.stLayer.confirm('是否确认?').then().catch()
Such basic elastic layer components have been implemented. The following is the last stepGlobal use
To use the layer component written in the original vue project globally, it is usually injected into the page using the following method
import main from './main.vue' const LayerConstructor = vue.extend(main) const initInstance = () => { instance = new LayerConstructor({ el: document.createElement('div') }) instance.callback = defaultCallback document.getElementById('app').appendChild(instance.$el) }
It is directly pulled over and used, and the result is an error and prompt error: document is undefined
, then I remembered that uni-app
is very different from the ordinary vue project, which is introduced in its operating principle:
uni-app
The logical layer and the view layer are separated. When running on the non-H5 end, it is divided into two parts: the logical layer and the view layer. The logic layer is responsible for executing business logic, that is, running js code, and the view layer is responsible for page rendering. Although developers write js and css in a vue page, they are actually split during compilation. The logic layer runs in an independent jscore. It does not depend on the local webview, so on the one hand it has no browser compatibility issues and can run es6 code on Android 4.4. On the other hand, it cannot run window, Browser-specific js APIs such as document, navigator, and localstorage.
So this method of global registration is no longer available. So how to implement it in uni-app
?
Looking through the official forum, I found an implementation of loadervue-inset-loader
. The implementation principle is to obtain the sfc template content and insert custom content at the specified location (that is, components that require global ), the usage is as follows:
// 第一步 npm install vue-inset-loader --save-dev // 第二步 在vue.config.js(hbuilderx创建的项目没有的话新建一个)中注入loader module.export = { chainWebpack: config => { // 超级全局组件 config.module .rule('vue') .test(/\.vue$/) .use() .loader(path.resolve(__dirname, "./node_modules/vue-inset-loader")) .end() } } // 支持自定义pages.json文件路径 // options: { // pagesPath: path.resolve(__dirname,'./src/pages.json') // } // 第三步 pages.json配置文件中添加insetLoader "insetLoader": { "config":{ "confirm": "<BaseConfirm ref='confirm'></BaseConfirm>", "abc": "<BaseAbc ref='BaseAbc'></BaseAbc>" }, // 全局配置 "label":["confirm"], "rootEle":"div" }
config
(default: {}
)
Definition Key-value pair of label name and content
label
(default: []
)
Labels that need to be introduced globally, after packaging This tag will be introduced in all pages
rootEle
(default: "div"
)
The tag type of the root element, default The value is div and supports regular rules. For example, it matches any label ".*"
label
and rootEle
supports configuration in the style of a separate page and has a higher priority than the global one. After configuring
at this point, the component can be used globally. There is no need to write tags on each page to use it. You only need to call the API.
You can optimize it later based on usage. The level is limited, everyone’s advice is welcome.
Recommended: "uniapp tutorial"
The above is the detailed content of How to develop a global elastic layer component in uni-app (code example). For more information, please follow other related articles on the PHP Chinese website!