Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
preface
After a number of UNIAPP applets project development, I will review all my experience in pit combat summary, the following content is only for uniAPP development micro channel applets scene, in addition to uniAPP there are some small program development attention points, I hope this article can help you avoid pit. Dry goods (dry to thirst)
Uniapp profile
First, the official introduction. If you are familiar with UNIAPP, you can skip it.
Uni-app is a framework for developing all front-end applications using vue.js. Developers write a set of code that can be published to iOS, Android, Web (responsive), mini programs (wechat/Alipay/Baidu/Toutiao /QQ/ Kuaishou/Dingding/Taobao), Kuaiapp and many other platforms.
With UniApp we can use vue.js syntax to write applets. In short, we can develop applets by replacing the template template from HTML with WXML in normal vue.js development, so what’s the advantage of this?
- Reduce the technical learning pressure, if you know vUE you can directly start, if you don’t know VUE incidentally learn VUE, but also can enjoy the surrounding ecological benefits of VUE
- Syntax intersection with native applet syntax is more convenient, if you have ever developed a applet you will feel
this.setData()
δΈNative applet components
The trouble and fear of development - Uniapp can be packaged into small programs of various platforms and also into APP, as shown in the figure below on the official website.
4. The code prompt of the small program development tool is relatively slow, although it has made great progress compared to the last few years, but it still does not reach the level I want.
Uniapp development preparation
Ide Tool Installation
HBuilder website link
To do a good job, he must sharpen his tools. The first step in uniApp development is to install an official IDE called HbuilderX. This is the only IDE I recommend for uni-App development. It is very convenient and helps us to quickly generate page templates and component templates, visual page configuration, excellent code prompts, code completion capabilities, etc.
HbuilderX still has some disadvantages compared to vscode, and some of the plug-in ecology is not very robust. But developing uni-app is HbuilderX (official stuff, after all)
HbuilderX is easy to install, just download it from the official website. Once the download is complete we need to install some plug-ins. Open HbuilderX and select Tools -> Plug-in Installation from the top bar, as shown below
When you open it, you can see the currently installed plug-ins and some official plug-ins. I can’t remember which ones were not installed at the beginning due to the age, but below are the ones that must be installed, one is for git version management and one is for sass compilation.
We can also set our editor theme and character size, code indentation, etc., if you have other editor habits can be adjusted appropriately. I originally developed using vscode, so I switched to the jalen theme, and the actual page looks exactly like vscode one dark pro editor style and code color!
I think the above steps are necessary, comfortable and beautiful development environment can greatly enhance your interest in development!
Project directory structure analysis
New project
Once HbuilderX is installed and configured, we are ready to develop. First we need to create a project, we click on file -> New -> Project in the top left corner of ide, then we select UniApp project and template select default template
After the creation, we can see that a new file named after the project has been added to the file tree on the left, which is the project template that HBuilder has built in for us
The following is an introduction to the project framework given by UniApp. There are some folders that are not built into the template, so we need to manually create the following folders, such as the outermost components, to place some of our global generic components
β ββ ββindex β ββ ββ vue index page β ββ ββ vue index page β ββ ββ vue index page β ββ ββ vue index page β β β list. Vue list page β β the static storage application reference local static resource directory (such as images, video, etc.), note: can only be stored in the static resources β β uni_modules store [uni_module] (/ uni_modules) specification of the plugin. β ββ WxComponents β ββ app.vue β ββ wxComponents β ββmain.js β Vue ββmanifest.json, ββ pages.json, page-routing, navigation, tabs, etcCopy the code
In the process of development, ACCORDING to the development habit of VUE project, I created functional classification folders in Pages according to business functions. The most common one is to distinguish functional modules according to tabbar on the home page. Each folder stores all pages involved in this function. There is also a separate Components folder in each feature folder for the page-dependent components in that feature only folder.
A new page
When we need to create a new page, we can quickly create it through the built-in page template of HBuilder. Right click the current project in the left file tree, choose New page, enter the page name and select template to create the page. Generally, I choose the TEMPLATE of SCSS. When created, the page will be automatically registered with page.json.
Universal plug-in encapsulation
Since UniApp chooses to use vue.js as the development framework, we must make use of some excellent features in VUE, such as plugin. You can go to the official website to see the introduction of vUE plug-in.
Vue plugin official introduction link
By introducing plug-ins, we can greatly improve our development efficiency. Of course, if it is the first time to use UniApp for development, it may not be clear which functions are suitable to be encapsulated as plug-ins. Below, I will introduce some general plug-ins encapsulated in my actual development
We need to write a config file before encapsulation, so that we can quickly customize some colors and request paths, etc.
//congif.js
const config = {
baseUrl:'https://example.cn'.// The base path of the request
modalColor:'#5271FF'.// Popover color
}
module.exports = config
Copy the code
Pop-up plug-in
In applets, we use the official showModal or showToast API for some user interaction if we don’t have custom pop-ups and mimicry components. This very frequently used operation is a great way to wrap it up for quick invocation. The specific code is as follows
The plug-in code
const config = require('.. /config.js')
var message = {
toast(title, type = 'text') {
if (title.length > 15) {
console.error('Toast is more than 15 characters in length and the current length is' + title.length)
return
}
var icon = 'none'
if (type) {
switch (type) {
case 'text':
icon = 'none'
break
case 'suc':
icon = 'success'
break
case 'err':
icon = 'error'
break
}
}
uni.showToast({
title,
icon
})
},
confirm(title, confirmColor) {
return new Promise((res, rej) = > {
uni.showModal({
title,
cancelColor: '#b6b6b6'.confirmColor: confirmColor || config.modalColor,
success: (result) = > {
if (result.cancel) {
rej(result)
} else if (result.confirm) {
res(result)
}
}
})
})
},
async message(content, confrimText) {
return new Promise((res) = > {
uni.showModal({
title: 'tip',
content,
showCancel: false.confirmColor: config.modalColor,
success: (result) = > {
res(result)
}
})
})
}
}
module.exports = message
Copy the code
Sample call
this.message.toast('Answer deleted')
Copy the code
Request the plugin
Our common request library in VUE is AXIos, and almost every developer has a secondary wrapper around AXIOS to reduce the amount of code needed to call and do some global configuration. In UNI-app, we don’t need to introduce a third party request library. We directly use the official UNI. request(OBJECT) API to call the request. Of course, we also need to do a secondary encapsulation. The specific code is as follows
The plug-in code
//http.js
const config = require('.. /config.js')
const message = require('./message.js')
var http = {
post(path, params, contentType = 'form', otherUrl, ) {
return new Promise((resolve, reject) = > {
var url = (otherUrl || config.baseUrl) + path
if(! checkUrl(url)) { rej('Request failed')
}
uni.request({
method: 'POST',
url,
header: {
"Content-Type": contentType === 'json' ? "application/json" :
"application/x-www-form-urlencoded"
},
data: params,
success: (res) = > {
console.log('request: POST request' + config.baseUrl + path + 'success', res.data)
resolve(res.data)
},
fail: (err) = > {
message.toast('Request failed'.'err')
console.error('request: request' + config.baseUrl + path + 'failure', err)
reject('Request failed')}})})},put(path, params, contentType = 'form', otherUrl, ) {
return new Promise((resolve, reject) = > {
var url = (otherUrl || config.baseUrl) + path
if(! checkUrl(url)) { rej('Request failed')
}
uni.request({
method: 'PUT',
url,
header: {
"Content-Type": contentType === 'json' ? "application/json" :
"application/x-www-form-urlencoded"
},
data: params,
success: (res) = > {
console.log('request: PUT request' + config.baseUrl + path + 'success', res.data)
resolve(res.data)
},
fail: (err) = > {
message.toast('Request failed'.'err')
console.error('request: PUT request' + config.baseUrl + path + 'failure', err)
reject('Request failed')}})})},get(path, params, otherUrl) {
return new Promise((resolve, reject) = > {
var url = (otherUrl || config.baseUrl) + path
if(! checkUrl(url)) {return
}
uni.request({
url,
data: params,
success: (res) = > {
console.log('request: GET request' + config.baseUrl + path + 'success', res.data)
resolve(res.data)
},
fail: (err) = > {
message.toast('Request failed'.'err')
console.error('request: GET request' + config.baseUrl + path + 'failure', err)
reject(err)
}
})
})
},
delete(path, params, otherUrl) {
return new Promise((resolve, reject) = > {
var url = (otherUrl || config.baseUrl) + path
if(! checkUrl(url)) {return
}
uni.request({
url,
data: params,
method: "DELETE".success: (res) = > {
console.log('request: the DELETE request' + config.baseUrl + path + 'success', res.data)
resolve(res.data)
},
fail: (err) = > {
message.toast('Request failed'.'err')
console.error('request: the DELETE request' + config.baseUrl + path + 'failure', err)
reject(err)
}
})
})
},
async upload(path, fileArray, otherUrl) {
if (typeoffileArray ! = ='object') {
console.error('Request: argument error, please pass file array')
return
}
var url = (otherUrl || config.baseUrl) + path
if(! checkUrl(url)) {return
}
var arr = []
for (let i in fileArray) {
const res = await uni.uploadFile({
url: otherUrl || config.baseUrl + path,
filePath: fileArray[i],
name: 'file'
})
console.log(res)
if (res[0]) {
console.error('Request: Upload failed', res[0])
return
}
arr.push(JSON.parse(res[1].data).data)
}
return arr
},
}
function checkUrl(url) {
var urlReg = /^((ht|f)tps?) :\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])? $/;
if(! urlReg.test(url)) {console.error('Request: Request path error' + url)
return false
}
return true
}
module.exports = http
Copy the code
Sample call
async getAnswer() {
const res = await this.http.get('/applet/answerList', {
qId: this.question.id,
})
if (res.code === 200) {
return res.data
} else {
this.message.toast('Request failed')
return false}}Copy the code
As you can see in the code above, we introduced two dependency files config and message, which we’ll talk about later. In the HTTP object, there are five methods: POST, GET, Update, and delete, which correspond to restful API operations. There is also an upload method for uploading files. We don’t need to worry about cross-domain requests in applets. Our default request path is obtained from the config dependency file. At this time we can also use the first popover plug-in for a quick message prompt.
Memory card
We use vuex + vuex-persistedstate to store globalData and persist it. There are two ways to store globalData. We globalize data by adding the globalData value to app.vue, which we can use to save our applets version, for example.
export default {
globalData: {
version: '1.0.0'}}Copy the code
However, globalData data is not persistent and is reinitialized when we exit the applet and re-enter, so we have a global storage method called storage, which is similar to localStroge on the Web side. Through the official API to achieve the effect of local storage
In the small program is often not as complex as the web side of the data structure, although uniApp small program can also use VUex as a global data management library, but I still made a simplified version of their own use. This plugin was written a long time ago and is a very simple implementation. If you want to omit the setData operation, you can use proxy to hijack the stored value and store it locally.
The plug-in code
var store = {
_init(){
if(uni.getStorageSync('store') = =' '){
uni.setStorageSync('store', {})return
}
const data = uni.getStorageSync('store')
for(let i in data){
if(!this[i]){
this[i] = data[i]
}
}
},
setData(key,value){
if(key == '_init'||key=='setData') {console.error('Store: invalid key value',key)
return
}
this[key] = value
uni.setStorageSync('store'.this)
console.log(uni.getStorageSync('store'))}}module.exports = store
Copy the code
The sample used
this.store.setData('user', {name:'oil'}) / / assignment
console.log(this.store.user) / / read values
Copy the code
Form validation plug-in
Form validation is the use of a very lightweight open source form validation library JSValidate, you can directly click the link in the repository to see the source code, the following code is not put, talk about how to use. JSValidate gitee link
Sample call
// validate.js
const validate = {
userForm: {intro: '@ bio | the require'.college: '@ school | the require! Please choose your school '.nickname:'@ nickname | the require'}}module.exports = validate
Copy the code
Write a form validation method to the form and use a popover to indicate if the criteria are not met
//form.js validateForm() {const validate = require("./validate") const validator = new this.validator() var result = validator.check(validate.userForm, this.form, false) if (result ! == true) { this.message.message(result) return false } return true }Copy the code
Time processing plug-in
As for the time processing plug-in, I also used an open source lightweight JS library day.js in the project. Please refer to the official documents for specific usage methods. Day.js almost contains all operations related to time processing, such as time comparison and time conversion. Day.js official documentation link
Day. js has a function that is particularly commonly used, which is the function of relative time conversion. Relative time conversion is to convert a time string such as year month day hour minute second to several seconds ago, ten minutes ago, several months ago and so on. Using the following code, we use computed in vue for time string processing, pass a time string parameter to the computed method through a closure, and then return a Chinese relative time through the formNow method of day.js. Date is the plug-in I packaged and introduced.
The sample code
computed: {
relativeDate() {
return (date) = > {
return this.date(date).fromNow()
}
}
}
Copy the code
When we have many plug-ins (as shown below), our plug-ins may share some configuration, such as config.js above. Then we can write an entry file called index.js to import our plug-ins and install our plug-ins in main.js.
The sample code
// index.js
const http = require('./lib/http')
const message = require('./lib/message')
const router = require('./lib/router')
const validator = require('./lib/validator')
const date = require('./lib/date')
const store = require('./lib/store')
const to = require('./lib/to')
const oil = {
message,
http,
router,
validator,
date,
store,
to,
install(Vue) {
this.store._init()
for (let i in this) {
if (i == 'install') {
continue
}
Vue.prototype[i] = this[i]
}
delete this.install
}
}
export default oil
Copy the code
// main.js
import Vue from 'vue'
import oilUni from './oil-uni/index.js'
Vue.use(oilUni)
app.$mount()
Copy the code
We define an object called oil in our introductory file. In addition to the oil method, there is a special method called install. The purpose of install is to pass the Vue constructor to install as the first argument when we use vue.use (). We then tie all the methods to Vue’s prototype chain.
Once installed, we can access the wrapped plug-in simply by using this. + xx in the js of the page or component.
Common Component encapsulation
The purpose of plug-ins is to modularize our code so that common operations can be easily reused. Componentization helps us encapsulate and reuse a UI. Since the applet scenario is generally not very complex, there are not many very common components. Here are just some of the component libraries I use in my business and the components I encapsulate
Introduction of third-party component libraries
colorUI
The first one I recommend is colorUI, which I use on almost all applets. ColorUI is more of a style library than a component library. ColorUI making links
ColorUI encapsulates a lot of inline styles, so we don’t have to switch between template and style frequently, which greatly reduces our mental burden. An analogy can be made to tailwindCSS, but in HBuilderX, there are very robust colorUi-style code hints. It’s not just colorUI. HBuilderX gives you a complete code hint for your own styles or references. The following figure
ColorUI does not provide functional packaged components for us, but in its sample source code, most of the scenes can be directly copied and modified to use, such as picture uploading and form components. ColorUI sample page
The introduction of colorUI is also very simple, put the package of colorUI in the root directory of the project, and then reference it in the style of app. vue. ColorUI contains three files, one is main. CSS, which contains all the style codes of colorUI. Icon is the icon of colorUI, animation is the animation of colorUI, and the functions of all three packages are used by writing specified code in the inline class.
//App.vue
<style>
@import "colorui/main.css";
@import "colorui/icon.css";
@import "colorui/animation.css";
</style>
Copy the code
vant-weapp
Vant is probably the most useful component library for vue Ecosystem on mobile. It covers almost everything, and vant has a version of app-specific apps that do app-specific things. Official documentation of Vant Syndrome
But vant weapp is written in the native small the grammar of the program, and the vue uniapp grammar some discrepancy, so introduce need to do some special operation, the following said the vant weapp how to introduce.
- To do this, you need to download Vant retry P and add the Vant folder to the project root directory
wxcomponent
Folder, if not, create a new one.
- in
App.vue
To introduce a style file,
<style>
@import "/wxcomponents/vant/common/index.wxss";
</style>
Copy the code
- Imports are not imported directly into a page or component, but in the same way applets are used
pages.json
The following code is introduced in the specified pageusingComponents
Added to the configuration itemComponent name: Component path
Then you can use it directly on the page
{
"pages": [{"path": "pages/home/home"."style": {
"navigationBarTitleText": ""."enablePullDownRefresh": false."usingComponents": {
"van-progress": "/wxcomponents/vant/progress/index"}}}]}Copy the code
Note that the syntax in the official documents for Vant retry is mini-programs. You can do it yourself by adding vUE syntax
Rolling container component
After the introduction of the above two component libraries, we can find the corresponding components in most of the development scenarios, at most, a secondary encapsulation to adapt to the business.
Common Service Scenarios
The login page
In small programs, login often uses the fast authentication function of each platform, rather than entering the account password or mobile phone verification code on the Web. For example, wechat small programs can obtain user information by sending requests to the official API of wechat.
Obtaining User information
Therefore, when we design the page, we often only need a very simple button to obtain user information. Below, I will use the login function in a project to show you how UNIApp realizes wechat small program login to obtain user information
<template>
<button class="cu-btn bg-blue shadow-blur round lg" @click="login">Login immediately</button>
</template>
<script>
export default {
methods: {
async login() {
uni.showLoading({
mask: true.title: 'Logging in'
})
const res = await uni.getUserProfile({
desc: 'Used to store user data'
})
uni.hideLoading()
if (res[0]) {
this.message.toast('Fetch failed'.'text')
return
}
this.getUser(res[1].userInfo)
},
async getUser(userInfo) {
uni.showLoading({
mask: true.title: 'Logging in'
})
const loginRes = await uni.login()
if (loginRes[0]) {
uni.hideLoading()
this.message.toast('Fetch failed')
return
}
const res = await this.http.post('/applet/weChatLogin', {
code: loginRes[1].code
}, 'form')
uni.hideLoading()
if(! res.data) {this.router.push('/pages/form/userForm', {
userInfo,
handle: 'add'
})
return
}
this.store.setData('user', res.data)
},}
Copy the code
Let’s take a look at the code above. First we use the UNI.getUserProfile API to get the user’s basic information, such as avatar, nickname, locale, etc. Next we call uni.login to get the code value. The code value is used to pass to the back end to get the unique identifier OpenID from wechat to the user.
I pass the code code to the back end, which parses openID and checks whether the current user has user information in the database. If not, it is the first login. The first time we log in, we jump to the form page to complete personal information and obtain the user’s mobile phone number.
The specific code of the back end is not expanded in detail here, only the overall implementation process.
Obtain the user’s mobile phone number
The necessary condition to obtain the user number is to click the button label with open-type getPhoneNumber to trigger, and bind an event with getPhoneNumber. When clicked, wechat will pop up a box authorizing access to the phonenumber, which will trigger our getPhonenumber method.
In the getPhonenumber method, there are two properties including the property encryptedData and iv (initialization vector). These two parameters are passed to the back end for phonenumber parsing.
Also very, very important, if you are a local application, the user can express some reviews and articles, so let’s save the user’s head must have been effective, if we use the default avatar provided WeChat official link directly stored in the database, so when a user in head, after the original link will fail!
So what we need to do is use the UNI. DownloadFile API to download the user’s avatar as a local file, and upload the local file to the server, and the user’s avatar will always be valid!
The specific code is as follows, the business has been removed, only the core code.
<button class="cu-btn bg-blue shadow-blur round lg" open-type="getPhoneNumber"
@getphonenumber="getTel" @click="getCode">Sure to submit</button>
Copy the code
async uploadAvatar() {
// Upload the user profile picture
if (this.updateImg) {
var uploadRes = await this.http.upload('/applet/file/uploadFile'[this.form.avatarUrl])
}
else if (this.userInfo) {
var downloadRes = await uni.downloadFile({
url: this.userInfo.avatarUrl
})
if (downloadRes[0]) {
uni.hideLoading()
this.message.toast('Login failed')
return
}
var uploadRes = await this.http.upload('/applet/file/uploadFile', [downloadRes[1].tempFilePath])
}
else {
return
}
this.form.avatarUrl = uploadRes[0]},async getTel(e) {
// Obtain the user's mobile phone number at the first login
if(! e.detail.encryptedData || ! e.detail.iv) {this.message.toast('Login failed')
return
}
uni.showLoading({
mask: true.title: 'Logging in'
})
await this.uploadAvatar()
this.form.tags = this.tag.arr.map(item= > item.name).join(', ')
const res = await this.http.post('/applet/authorization', {
code: this.code,
iv: e.detail.iv,
encryptedData: e.detail.encryptedData,
userInfo: this.form
}, 'json')
uni.hideLoading()
},
Copy the code
List page
Let’s talk about a very, very common business scenario, which is the list page. The list page looks simple, but it can be very mysterious. Such as pull-down refresh, slide-up loading, prompt for no more content, keyword search, TAB bar matching, blank pages, reuse of list item components, and so on. Having a complete design from the start makes a big difference to development efficiency and overall code robustness!
I will use my actual development code examples to demonstrate the functionality of a list. Again, I removed the business code and left the core code!
<! Page code -->
<scroll-view
:scroll-y="true"
style="height: 100vh"
:refresher-enabled="true"
:refresher-triggered="list.flag"
@refresherrefresh="refresh"
@scrolltolower="getAnswer"
:enable-back-to-top="true"
:scroll-into-view="list.scrollId"
:scroll-with-animation="true"
>
<view style="position: relative" class="bg-white">
<view v-for="(item,index) in list.data" :key="index" >
<answer-item
:data="item"
></answer-item>
</view>
</view>
<view
class="cu-load bg-gray text-main loading"
style="height: 40px"
v-if=! "" list.nomore"
></view>
</scroll-view>
Copy the code
/ / js code
export default {
components: {
AnswerItem,
},
data() {
return {
list: {
data: [].flag: false.// Whether to display refresh
limit: 10.total: 0.nomore: false.// Whether to display to the end
empty: false.// Whether the display is null,
error: false.// If the request is incorrect,}}; },async onLoad(e) {
this.getQuestion()
await this.getAnswer()
async getAnswer(){},methods: {
async getAnswer() {
const listHandle = require(".. /.. /utils/js/listHandle")
const id = this.list.data.length ? this.list.data[this.list.data.length - 1].id : ' '
const res = await this.http.get('/applet/answerList', {
qId: this.question.id,
limit: this.list.limit,
userId: this.store.user ? this.store.user.id : ' ',
id
})
if (res.code === 200) {
const list = listHandle.add(res.data, this.list.data, this.list.limit)
Object.assign(this.list, list)
return res.data
} else {
this.list.error = true
this.message.toast('Request failed')
return false}},async refresh() {
// Refresh method
const listHandle = require(".. /.. /utils/js/listHandle")
this.list.flag = true
this.list.nomore = false
this.list.empty = false
this.list.error = false
this.list.loadNum = 0
const res = await this.http.get('/applet/answerList', {
qId: this.question.id,
limit: this.list.limit,
userId: this.store.user ? this.store.user.id : ' '.id: ' '
})
this.list.flag = false
if (res.code === 200) {
const list = listHandle.update(res.data, this.list.limit)
Object.assign(this.list, list)
} else {
this.list.err = true
this.message.toast('Request failed')}},}}Copy the code
// listhandle.js list item handling method
const listHandle = {
add(resData, listData, limit) {
var ret = {
nomore: false.empty: false.data: []}if (resData) {
if (resData.length < limit) {
// The number of pages is less than the number of pages
ret.nomore = true
}
ret.data = listData.concat(resData)
} else {
ret.data = listData
ret.nomore = true
if(! listData.length) {// No data has been returned and the current list is empty
ret.empty = true}}return ret
},
update(resData, limit) {
var ret = {
nomore: false.empty: false.data: []}if (resData) {
if (resData.length < limit) {
// The number of pages is less than the number of pages
ret.nomore = true
}
ret.data = resData
} else {
ret.nomore = true
// The request has returned no data and is displayed empty
ret.empty = true
}
return ret
}
}
module.exports = listHandle
Copy the code
Pay attention to the point
When loading on the phone, if you are sorting in reverse chronological order, traditional bottom web pager passes a page number and a single page number to the backend query. If users post new content as you scroll up, you’ll have duplicate items in your list.
For example: you take ten data initially, and when you load up to the bottom you pass a page=2 and a limit=10 to the back end, meaning all ten data as one page, I want to take the contents of the second page. But when a user adds a new item, the last item on your first page is pushed to the second page, and the first item you get is exactly the same as the last one you got!
To solve this problem, we simply do not pass values by page number when passing data to the back end. We pass the id of the last entry of the current data to the back end and ask the back end to take ten ids smaller than this value. At this point, no matter how many users insert new data, it will not affect your results. Of course, if your table id is increasing, you can also use the creation time of the data field. Corresponding to this functionality is the following line of code.
const id = this.list.data.length ? this.list.data[this.list.data.length - 1].id : ''
Cross-page method calls
In the development of uniApp applets, we may encounter a situation where I need to call the methods of the previous page on the current page. For example, I want to implement a search function. When I click on search details and enter a keyword, I want to return to the list page and trigger a search method, as shown below
Here’s how I did it
searchFunc(){
let pages = getCurrentPages()
let page = pages[pages.length - 2]
page.$vm.searchText = this.search.text
page.$vm.refresh()
this.router.back()
}
Copy the code
GetCurrentPages () is a global function that gets an instance of the current page stack, given as an array in stack order. The current page is the last item in the array, so the previous page is pages[pages.length-2]. Also remember to add the $VM attribute, because in UniApp our data and methods are mounted on this instance. We can use this example to access all the data and methods of the corresponding page!
Step on the pit carefully
The issues listed below are not only about UNI-App, but also about applets themselves
Scoll-view scroll-into-view cross-components
There is a scroll-into-view property on the scroll-view tag of the applet. The value of this property can be passed in as an ID, and when we change this value we will scroll to the container with the specified ID.
But if our scrollView is encapsulated in a component for use, we’re in slot
The scroll view cannot be pulled down to refresh
why
It should be that the drop-down position of the Scrollview element is determined when the element is rendered, but the height we give to the Scrollview changes the drop-down position, resulting in that the falads are not in place when the element is pulled down
The solution
Render the Scrollview element after the height variable of the scrollview is determined. The specific method is as follows
<scroll-view
scroll-y="true"
:style="'height:'+height"
v-if="height"
:refresher-enabled='true'
:refresher-triggered='list.flag'
@refresherrefresh='refresh'
@scrolltolower='loadMore'>
</scroll-view>
Copy the code
Scroll -view sticky style problem
Problem description
Scroll view is a label that is often used by small programs. Inside the scroll window, we might have a top TAB bar. If we don’t want to fix it to the top by calculating the height, we can use position:sticky with a boundary condition such as the top:0 property to achieve a sticky layout. When the container rolls, if our top TAB hits the top it doesn’t scroll anymore, it stays at the top.
But in a small program if you use the sticky attribute for a child element directly in the Scroll view element, the element you give sticky will expire at the bottom of the parent element, which will be very impressive if you have encountered it π.
The solution
In the scroll view element, add another layer of view element, and then put the child element with the sticky attribute into the view, you can achieve the effect of sticking in a certain position
Ios fixed font movement bug in input box
Problem description
I put a form in a scrollable container fixed in the middle of the page. It worked fine in android, but there was a bug on IOS. If the input box is out of focus without clicking any other position after input, the font inside the scroll window will also scroll with the following solution
// The original input box<input></input>
Copy the code
The solution
Using this method, not only does the layout style not change, but the bug of the font scrolling along with the fixed scrolling window is resolved
// The changed input field<textarea fixed="true" auto-height="true" ></textarea>
Copy the code
Real time error BUG
Problem description
When using the new Date().tolocaledateString () API in applets to retrieve the time, it is displayed as the current time in the development tool and as the time of another location in the real machine
Causes of bugs
The toLocaleDateString() method depends on the underlying operating system for formatting dates. For example, in the US, the month appears before the date (06/22/2018), while in India, the date appears before the month (22/06/2018).
The solution
Use the new Date() constructor to get the Date after Date concatenation
If no arguments are entered, the Date constructor creates a Date object based on the current time set by the system.
The difference between Date and toLocaleDateString() is that one fetches the time currently set by the system and the other formats the time by the underlying operating system
// The code is as follows
let date = new Date()
date = date.getFullYear() + '/' + (date.getMonth() + 1) + '/' + date.getDate()
date = date.split('/')
if (date[1] < 10) {
date[1] = '0' + date[1]}if (date[2] < 10) {
date[2] = '0' + date[2]
}
date = date.join(The '-')
Copy the code
conclusion
This article has been written on and off for two weeks. Although it is quite long, there is still a lot of content THAT I have not covered. Although I understand that output forces input, I still hope to get more positive feedback when I write my article! The likes are big drops and the updates are big drops fast.
I am oil Oyo, the new front end, welcome to pay attention to grow together!