component
If we put all the processing logic on a page together, it would become very complex to process, and not conducive to subsequent management and extension
However, if we break a page into small function blocks, each function block completes its own part of the independent function, then the whole page management and maintenance becomes very easy
-
We split a complete page into many components
-
Each component is used to implement a functional block of the page
-
Each component can be subdivided
The custom component consists of json WXML WXSS JS files.
The structure of a component in an applet is exactly the same as the structure of a page
It’s just that when the Component field in json is set to true,
This is a component, not a page
Json file for the component
{
"component": true.// Indicate that this is a component
"usingComponents": {} // Other components can also be used inside components
}
Copy the code
Using the component
<myCpn />
Copy the code
{
// All components that are used need to be registered here
"usingComponents": {
// Component name: component path
"myCpn": "/components/my-cpn/my-cpn"}}Copy the code
Attention to details:
- Because WXML node label names can only be lowercase letters, hyphens, and underscores, custom component label names can only contain these characters
- Custom components can also refer to custom components in a manner similar to how pages refer to custom components (using the usingComponents field)
- The name of the root directory where custom components and pages reside cannot be prefixed with wx-; otherwise, an error message will be reported
- If you declare a component in app.json’s usingComponents, that component is a global component
style
By default, class styles within a component and class styles outside of a component have a separate effect,
The default component style and page style do not conflict
If you need to have the same style between the component and the page interact
In the Component object, you can pass in an Options property with a styleIsolation property.
StyleIsolation has three values:
value | instructions |
---|---|
isolated | Default values The styles between components and pages do not affect each other |
apply-shared | The style of the page can affect the component, but the style of the component cannot affect the page If the component internal style and the page style conflict, the component internal style overrides the page style |
shared | Component styles and page styles can influence each other |
Component({
options: {
styleIsolation: 'apply-shared'}})Copy the code
You cannot use id selectors, attribute selectors, or label selectors within a component. You can only use class selectors
You can use class selectors, ID selectors, attribute selectors, and tag selectors in a page
By default, if a label selector is used externally (similar to view {… }) will affect the internal style of the component
But class selectors, ID selectors, and attribute selectors have no effect on the internal styles of components
Therefore, it is recommended to use the class selector for style Settings in applets
The page
In many cases, the content presented within a component (data, styles, tags) is not written down within the component and can be determined by the consumer
properties
For the most part, components are only responsible for layout and styling, and the content is determined by the objects that use them
We often need to pass data externally to our components for presentation
At this point we can use the properties property
Properties Supported types; String, Number, Boolean, Object, Array, null(unrestricted type)
The parent component
<myCpn name="klaus" />
<myCpn />
Copy the code
Child components
<view class="title">{{ name }}</view>
Copy the code
Component({
properties: {
name: String}})Copy the code
The above is a simplification. In practical development, the more common way to write is as follows:
Component({
properties: {
name: {
type: String.// Customize the default value to override the original default value
value: 'defaule name'.// The watch option for the property
// Deep listening is enabled by default
// The immediate option defaults to true
// The first oldValue is automatically initialized according to the type (e.g., string is empty and value is 0).
If the type of the props passed is different from that of the props needed, the type conversion is performed as much as possible
If the conversion succeeds, the converted value is used. If the conversion fails, the default value is used
observer(newName, oldName) {
console.log(newName, oldName)
}
}
}
})
Copy the code
Component({
properties: {
foo: {
// If multiple types of props can be used, use type and optionalTypes together
// type Mandatory -- This parameter is used to set the default initial value for multiple types. For example, if this parameter is not set, the default initial value is 0
type: Number.// Optional other types -- value is of the type array
optionalTypes: [String.Boolean]}}})Copy the code
externalClasses
Sometimes we don’t want styles to be fixed within a component, but externally
That is, you pass a style name to the child, and the style is defined in the parent component
The parent component
<! The title attribute is defined in externalClasses in the child component, so the comforter component will think of it as the value of the class style attribute that the parent component passed in ----.
<myCpn title="red" foo="Klaus" />
Copy the code
.red {
color: red;
}
Copy the code
Child components
<! -- The style is used in the child component -- note: the style name used here is title not red (★★★) -->
<view class="title">{{ name }}</view>
Copy the code
Component({
data: {
name: 'Klaus'
},
// Receive the style passed in by the parent - the value is of type array
externalClasses: ['title']})Copy the code
Custom events
The parent component
<view>{{ counter }}</view>
<! -- Listen for custom events -->
<cpn bindincrement="increment" />
Copy the code
Page({
data: {
counter: 0
},
increment() {
this.setData({
counter: this.data.counter + 1})}})Copy the code
Child components
<button size="mini" bindtap="increment">increment</button>
Copy the code
Component({
// Component methods need to be defined in the methods option
methods: {
increment() {
// Use triggerEvent to trigger custom events
// Parameter 1 -- Custom event name
// Argument 2 - the argument to be passed ---- is like an object
// parameter 3 ---- configuration object ---- is not usually used - pass an empty object
this.triggerEvent('increment', {}, {})}}})Copy the code
Phase case
To achieve a simple TAB switch components
The parent component
<tabs
users="{{ users }}"
bind:changeTab="changeTab"
/>
<text>{{ user }}</text>
Copy the code
Page({
data: {
users: ['Klaus'.'Alex'.'Steven'],
user: 'Klaus'
},
changeTab(e) {
this.setData({
user: e.detail.user
})
}
})
Copy the code
Child components
<view class="users">
<! -- You can dynamically bind the corresponding style in class -->
<text
wx:for="{{ users }}"
wx:key="user"
wx:for-item="user"
class="user {{ user === activeUser ? 'active' : ''}}"
bindtap="changeActiveTab"
data-user="{{ user }}"
>
{{ user }}
</text>
</view>
Copy the code
Component({
properties: {
users: {
type: Array.value: []}},data: {
activeUser: 'Klaus'
},
methods: {
changeActiveTab(e) {
const user = e.currentTarget.dataset.user
this.setData({
activeUser: user
})
this.triggerEvent('changeTab', {
user
})
}
}
})
Copy the code
selectComponent
You can select the component used in the current page or component from the page or component
The arguments are id or class selectors
<tabs id="cpn" />
Copy the code
Page({
onReady() {
console.log(this.selectComponent('#cpn'))}})Copy the code
slot
Component slots:
- Component slots are also designed to make the components we package more extensible
- Let the user decide what some of the content inside the component actually shows
A single slot
The parent component
<cpn>
<slider value="60" />
</cpn>
Copy the code
Child components
<view>start</view>
<! Unable to set component default value in applet -->
<! If there are multiple default slots in the Vue, only the first default slot will be valid, and the following default slots will be invalid.
<slot />
<view>end</view>
Copy the code
Multiple slots
The parent component
<cpn>
<view slot="left">left</view>
<view slot="center">center</view>
<view slot="right">right</view>
</cpn>
Copy the code
Child components
<slot name="left" />
<slot name="center" />
<slot name="right" />
Copy the code
Component({
options: {
// Multiple slots can only be used if this option is enabled in child components
multipleSlots: true}})Copy the code
Component
Component({
// Options for receiving props
properties: {},
// Options for defining data inside the component
data: {},
// External style passed in
externalClasses: [].// The method inside the component
methods: {},
// Watch option - can listen for state changes in data/properties
// But the observer method in this option takes only newValue
/ / not oldValue
observers: {},
// Configuration options within the component
For example multipleSlots and styleIsolation
options: {
multipleSlots: true
},
// The page life cycle
pageLifetimes: {
show() {
console.log('Page is displayed')},hide() {
console.log('Page hidden')},resize() {
console.log('Page size has changed')}},// The component lifecycle function
lifetimes: {
created() {
console.log('Component created')},attached() {
console.log('Component added to page')},ready() {
console.log('Component rendered complete')},moved() {
console.log('Component has moved')},detached() {
console.log('Component removed')}}})Copy the code
System apis
Network request
By default, the interface API domain address requested by the applet must be the domain name configured in the applet background
During local debugging, you can temporarily disable domain name verification
wx.request
wx.request({
url: 'https://httpbin.org/get'.// Request parameters - For GET requests, parameters can be written in the data option or after the URL request domain name
data: {
name: 'Klaus'.age: 23
},
// Successful callback
success(res) {
console.log(res.data.args)
}
})
Copy the code
wx.request({
url: 'https://httpbin.org/post'.// Request mode -- the default value is GET
method: 'POST'.// The parameters of the POST request must be placed in the data option
data: {
name: 'Klaus'.age: 23
},
success(res) {
console.log(res.data.json)
}
})
Copy the code
In applets, there may be multiple places to send network requests,
Therefore, we need to encapsulate network requests so that network requests throughout the project call their own encapsulated interfaces
In order to achieve the decoupling of the request and API, if the later need to modify, directly modify the encapsulated API request method
encapsulation
import { BASE_URL } from './consts'
class Api {
request(path, method, params) {
return new Promise((resolve, reject) = > {
wx.request({
url: BASE_URL + path,
method: method || 'get'.data: params || {},
success: resolve,
fail: reject
})
})
}
get(path, query) {
return this.request(path, 'get', query)
}
post(path, params) {
return this.request(path, 'post', params)
}
}
export default new Api()
Copy the code
test
// Import files must use relative paths, not absolute paths
import api from '.. /lib/api'
export function fetchTopMv(offset = 0, limit = 10) {
return api.get('/top/mv', {
offset,
limit
})
}
Copy the code
Popup window
showToast
wx.showToast({
title: 'toast'.icon: 'loading'.duration: 3000.// The duration for which toast appears. The default value is 1500
mask: true // When a toast appears, it is not allowed to interact with elements below the toast layer
})
Copy the code
showModal
wx.showModal({
title: 'title'.content: 'content'.success(res) {
// There are attributes in the res object
// 1. cancel -- The user exits the popover when the value is true
// 2. confirm - the user confirms the popup when the value is true
console.log(res)
}
})
Copy the code
showLoading
ShowLoding and showToast whose icon property is Loading have the same display effect
The only difference is that shoToast automatically shuts down after a certain amount of time
When showLoading is disabled, you need to manually invoke the hideLoading method
wx.showLoading({
title: 'loading... ',})// You need to manually call the hideLoading method to close the loading popup
setTimeout(() = > wx.hideLoading({}), 3000)
Copy the code
showActionSheet
wx.showActionSheet({
itemList: ['photos'.'gallery'].success(res) {
// there is a tapIndex attribute in res whose index value corresponds to the element in the index position of the itemList
console.log(res)
}
})
Copy the code
share
Sharing is an important way of spreading small programs. There are two ways of sharing in small programs:
- Click the menu button in the upper right corner and then click Forward
Page({
// onShareAppMessage is the equivalent of the Page and lifecycle functions
onShareAppMessage() {
// Returns a custom configuration item
return {
title: 'sharing'.// Share is displayed on the home page by default
// The path property can determine the shared applet and click enter to enter the specific page
path: '/pages/about/about.js'}}})Copy the code
OnShareAppMessage can be set to the following values:
- Click a button, direct forward
<! OnShareAppMessage is automatically called when a button component's open-type property is set to share.
<button open-type="share">share</button>
Copy the code
The login
// The constants are separated into separate locations for later maintenance and modification
const TOKEN = 'token'
App({
// Define token as a global variable
globalData: {
token: ' '
},
// Applets are recommended for login in the onLaunch method
onLaunch: function () {
// 1. Fetch the token from the buffer first
const token = wx.getStorage(TOKEN)
// 2. Check whether the token has a value
if(token && token.length ! = =0) { // The token already exists. Verify whether the token expires
this.check_token(token) // Verify that the token expires
} else { // Login without token
this.login()
}
},
check_token(token) {
wx.request({
// The backend server
url: 'http://www.example.com/auth'.method: 'post'.header: {
token
},
success: (res) = > {
if(! res.data.errCode) {// After obtaining the token, store the token in globalData
this.globalData.token = token;
} else {
// Token expired. Log in again
this.login()
}
},
fail: function(err) {
console.log(err)
}
})
},
login() {
wx.login({
// The code obtained from the wechat server is valid for only 5 minutes
success: (res) = > {
// 1. Obtain code
const code = res.code;
// 2. Send the code to our server
wx.request({
url: 'http://www.example.com/login'.method: 'post'.data: {
code
},
success: (res) = > {
// 1. Retrieve the token
const token = res.data.token;
// 2. Save the token in globalData
this.globalData.token = token;
// 3. Local storage
// The storage of an applet can be viewed and modified in the storage TAB of the applet debugger
wx.setStorage(TOKEN, token)
}
})
}
})
}
})
Copy the code
Page jump
navigator
<! The url parameter in navigator must be an absolute path, not a relative path.
<navigator url="/pages/profile/profile" open-type="switchTab">jump</navigator>
Copy the code
Open-type Optional value
value | instructions |
---|---|
navigate | The default is to keep the original page, and the new page is inserted as a push, but cannot be skipped to the Tabbar page This operation is a push operation, so a back button appears on the navigation bar |
redirectTo | Jump to a new page without saving the original page, but not to the Tabbar page The back button does not appear on the navigation bar |
switchTab | Jump to the tabBar page and close all other non-Tabbar pages Multiple tabbars are switched through the bottom TAB bar, so there is no back button in the navigation bar |
reLaunch | Close all pages before opening a page within the app The back button does not appear on the navigation bar |
navigateBack | Close the current page and return to the previous page or multi-level page |
<! If the value of delta is greater than the length in the history stack, all pages on the stack will be displayed except the one at the bottom of the stack.
<navigator open-type="navigateBack" delta="2">The fallback</navigator>
Copy the code
Pass parameters when the page jumps
- Home -> Details page —- page jump — use the query field in the URL
- Details page -> home page — page back — inside the details page to get the home page object, directly modify the data
Page jump
<! Select * from 'query' to 'route';
<navigator url="/pages/categories/categories? name=Klaus&age=23">jump</navigator>
Copy the code
Page({
// If the page jumps to the page with a query parameter
// The corresponding query argument is then converted to an object and passed in as an argument to the onLoad method
onLoad(options) {
console.log(options)
}
})
Copy the code
The page back
The page can be rolled back using a button or the back key on the navigation bar
That is, there are a lot of page back, so if the small program needs to pass in the corresponding parameters when the page back
The corresponding logic can be implemented in the onUnload method
Page({
onUnload() {
The getCurrentPages method retrieves all active pages - that is, pages in the history stack
const pages = getCurrentPages()
// Pass data to the previous page
// pages. Length is the number of active pages, and the index of the array starts at 0
// The index of the last page in pages is page.length-1
// So the index of the last page in pages is pages.length-2
const page = pages[pages.length - 2]
page.setData({
msg: {
name: 'Klaus'.age: 23}})}})Copy the code
Through THE WX API
Each naviagtor hop in the applet corresponds to the corresponding wxAPI
wx.navigateTo({
url: '/pages/about/about? name=Klaus&age=23'
})
Copy the code
// If the configuration object is not passed, then the default value of the delta property is 1, which means that the page is reverted to the previous page
wx.navigateBack({
// The value of delta is set the same as that of navigator when open-type is naviagorBack
delta: 2
})
Copy the code
home.js
Page({
handleTap() {
wx.navigateTo({
url: '/pages/categories/categories? name=Klaus&age=23'.events: {
// Set the event listener
getMsg(v) {
console.log(v)
}
}
})
}
})
Copy the code
categories.js
Page({
onLoad(options) {
// Get the parameters passed in
console.log(options)
// Get the corresponding event bus
const eventChannel = this.getOpenerEventChannel()
// Go through the event bus to the source page (in this case, the home page)
// Trigger the events registered in events to return data
eventChannel.emit('getMsg', {
msg: 'Hello World'})}})Copy the code