[WeChat Mini Program] Custom Components

 

Create WeChat applet components

Create a component in the applet:

1. Create a [components] directory in the project root directory to store custom components

2. Enter the components directory and create a component directory for the component

3. Right-click the component directory and select [Create Components]

4. After pressing Enter, 4 files corresponding to the component will be automatically generated, with the suffixes .js, .json, .wxml and .wxss

 

1. Global components and local components

 

Partial page reference component:

The way to reference components in the [.json] configuration file of the page is called "local reference".

The sample code is as follows:

{
  "usingComponents": {
    "test1": "/components/test1/test1"
  }
}

  

Global reference components:

Configure component information in [app.json]

"usingComponents": {
  "test1": "/components/test1/test1"
}

  

Use components:

<!-- The global component can be used in any page, and the local component can only be used in the imported page -->
<test1></test1>

  

Difference between component and page

On the surface, components and pages are composed of four files: .js, json, .wxml, and .WXSS.

However, the js of components and pages is significantly different from the .json file:

● component json A declaration is required in the file"component": true Attributes
● component js The file called is Component()function
● The event handler function of the component needs to be defined to methods in node

 

Second, the style isolation problem between components:

1. Component style isolation

By default, the style of the custom component only takes effect on the current component and will not affect the UI structure outside the component

● components A The styles of the components do not affect the C style
● components A The style will not affect the style of the applet page
● The style of the applet page does not affect the components A and C style

benefit:

① Prevent external styles from affecting styles inside components

② Prevent the style of the component from destroying the style of the outside world

2. Notes on component style isolation

● app.wxss Global styles in have no effect on components

● only class The selector will have a style isolation effect,
    id selectors, attribute selectors, tag selectors are not affected by style isolation

Recommendation: It is recommended to use class selectors in components and pages that reference components, do not use id, attribute, tag selectors!

 

 

3. Modify the style isolation options of the component

By default, the style isolation feature of custom components can prevent the problem of interference between styles inside and outside the component.

But sometimes, we want to be able to control the style inside the component from the outside,

At this point, you can modify the style isolation options of the component through stylelsolation,

The usage is as follows:

// components/test1/test1.js
Component({
  options: {
    styleIsolation: 'isolated'
  }
})

// components/test1/test1.json
{
  "component": true,
  "usingComponents": {},
  "styleIsolation": "isolated"
}

  

Fourth, the optional value of stylelsolation

isolated
  Indicates that style isolation is enabled, inside and outside of custom components, using class The specified styles will not affect each other

apply-shared
  presentation page WXSs styles will affect custom components, but custom components wxSS The styles specified in will not affect the page
shared   presentation page WxSs styles will affect custom components,   custom component Wxss The styles specified in also affect the page and other settings apply-shared or shared custom component of

  

3. Data property and Method method

Set the same as the page

/**
 * the initial data of the component
 */
data: {
  count: 0
},

The method is stored in a separate object

  /**
   * Component's method list
   * Write custom methods and event handlers here
   * Custom methods are recommended to be marked with an underscore prefix
   * Such as:
   *  addCount() // event execution method
   *  _showCount() // custom method
   */
  methods: {
    addCount() {
      this.setData({ count: this.data.count + 1})
      this._showCount()
    },
    _showCount() {
      wx.showToast({ 
        icon: 'none',
        title: `count value: ${this.data.count}`
      })
    }
  }

 

4. Properties property

  /**
   * Component's property list
   * Used to receive properties passed in from external pages or other components
   */
  properties: {
    // The same way as vue
    max: { 
      type: Number,
      value: 10 // Defaults
    }
    /**
     * Simplified writing, no default value is set
     * max: Number 
     */
  },

  

Values ​​can be set when components are used

<test1 max="{{5}}"/>

  

Use property data

When it is equal to the max value, it cannot continue to stack

addCount() {
  if (this.data.count === this.properties.max) return
  this.setData({ count: this.data.count + 1})
  this._showCount()
},

  

Five, the difference between data and properties

In the components of the applet, the properties attribute and data data are used in the same way, they are both readable and writable, except:

● data Prefer to store private data of components

● properties More inclined to store data passed to the component from the outside world

Both addresses are the same:

this.data === this.properties // true

Assign a value to the properties property

// Reassign the data of properties
this.setData({ max: this.properties.max + 1 })

  

6. Data Listener

The listener function is not supported by the page

/**
 * Component's data listener
 */
observers: {
  // Multiple attributes can be monitored at the same time. The parameter input corresponds to the number of attributes, indicating the updated value of the attribute
  'attr1, attr2': function(newValue1, newValue2) {
    // todo ...
  }
},

 

Demonstration case:

Component HTML code:

<!--components/test2/test2.wxml-->
<text>components/test2/test2.wxml</text>

<view>
  {{n1}} + {{n2}} = {{sum}}
</view>
<button size="mini" type="primary" bindtap="addN1">n1 Increase</button>
<button size="mini" type="primary" bindtap="addN2">n2 Increase</button>

Component JS code:

// components/test2/test2.js
Component({
  /**
   * Component's data listener
   */
  observers: {
    'n1, n2': function(n1Value, n2Value) {
      this.setData({ sum: n1Value + n2Value })
    }
  },
  /**
   * Component's property list
   */
  properties: { },

  /**
   * the initial data of the component
   */
  data: { n1: 0, n2: 0, sum: 0 },

  /**
   * Component's method list
   */
  methods: {
    addN1() { this.setData({ n1: this.data.n1 + 1 }) },
    addN2() { this.setData({ n2: this.data.n2 + 1 }) }
  }
}) 

 

Demonstration case 2:

An RGB color case, HTML code

<!--components/rgbView/rgbView.wxml-->
<text>components/rgbView/rgbView.wxml</text>

<view class="colorBox" style="background-color: rgb({{fullColor}});">
  Color value:{{fullColor}}
</view>
<button size="mini" bindtap="changeR" >R</button> |
<button size="mini" bindtap="changeG" >G</button> |
<button size="mini" bindtap="changeB" >B</button>
<view>
  {{rgb.r}}, {{rgb.g}}, {{rgb.b}}
</view>

  

JS code:

// components/rgbView/rgbView.js
Component({
  observers: {
    // listen, then reassign
    'rgb.**': function(newRgb) {
      this.setData({ 
        fullColor: `${newRgb.r}, ${newRgb.g}, ${newRgb.b}`
      })
    }
  },

  /**
   * Component's property list
   */
  properties: { },

  /**
   * the initial data of the component
   */
  data: {
    rgb: { r: 0, g: 0, b: 0 },
    fullColor: '0, 0, 0'
  },

  /**
   * Component's method list
   */
  methods: {
    changeR() {
      let rValue = this.data.rgb.r + 5 
      rValue = rValue > 255 ? 255 : rValue
      this.setData({ 'rgb.r': rValue })
    },
    changeG() {
      let gValue = this.data.rgb.g + 5 
      gValue = gValue > 255 ? 255 : gValue
      this.setData({ 'rgb.g': gValue })
    },
    changeB() {
      let bValue = this.data.rgb.b + 5 
      bValue = bValue > 255 ? 255 : bValue
      this.setData({ 'rgb.b': bValue })
    }
  }
})

RGB Display Board Style:

/* components/rgbView/rgbView.wxss */
.colorBox {
  line-height: 200rpx;
  font-size: 24rpx;
  color: white;
  text-shadow: 0rpx 0rpx 2rpx black;
  text-align: center;
}

  

Seven, pure data fields

1. What is a pure data field

Concept: Pure data fields refer to those data fields that are not used for interface rendering.
Application scenarios: For example, in some cases, the fields in some data will not be displayed on the interface, nor will they be passed to other components, only in the current
Used inside the component. Data fields with this feature are suitable to be set as plain data fields.

Benefit: Pure data fields help improve the performance of page updates.

2. Rules of use

In the options node of the Component constructor, specify pureDataPattern as a regular expression,

Fields whose field names conform to this regular expression will become pure data fields. The sample code is as follows:

// components/rgbView/rgbView.js
Component({
  options: {
    // Customize regular rules to match pure data fields, demonstrated as the property of the first character underscore
    pureDataPattern: /^_/
  }
}

Change the rgb attribute name of the previous JS code to _rgb and use it:

// components/rgbView/rgbView.js
Component({
  options: {
    // Customize regular rules to match pure data fields, demonstrated as the property of the first character underscore
    pureDataPattern: /^_/
  },
  observers: {
    // listen, then reassign
    '_rgb.**': function(newRgb) {
      this.setData({ 
        fullColor: `${newRgb.r}, ${newRgb.g}, ${newRgb.b}`
      })
    }
  },

  /**
   * Component's property list
   */
  properties: { },

  /**
   * the initial data of the component
   */
  data: {
    _rgb: { r: 0, g: 0, b: 0 },
    fullColor: '0, 0, 0'
  },

  /**
   * Component's method list
   */
  methods: {
    changeR() {
      let rValue = this.data._rgb.r + 5 
      rValue = rValue > 255 ? 255 : rValue
      this.setData({ '_rgb.r': rValue })
    },
    changeG() {
      let gValue = this.data._rgb.g + 5 
      gValue = gValue > 255 ? 255 : gValue
      this.setData({ '_rgb.g': gValue })
    },
    changeB() {
      let bValue = this.data._rgb.b + 5 
      bValue = bValue > 255 ? 255 : bValue
      this.setData({ '_rgb.b': bValue })
    }
  }
})

  

Eight, the life cycle function of the component

All hook functions

// components/rgbView/rgbView.js
Component({
  lifetimes: {
    // Execute after creation
    created() {},
    // The component instance and the page are executed after the dom binding is completed, which is equivalent to the mounted of vue
    attached() {},
    // The view rendering of the component and the page is completed
    ready() {},
    // Executed after the component has been updated (the component instance is moved to a new location in the node tree)
    moved() {},
    // Fired when a component is removed from the page's dom tree
    detached() {},
    // Component triggers abnormally
    error() {}
  }
})

The main three functions

2. The main life cycle functions of components
In the applet component, there are three most important life cycle functions, namely created, attached, and detached. their respective characteristics
as follows:

① When the component instance is just created,
  created Lifecycle functions will be triggered ● Can't call at this time setData ● Usually in this lifecycle function, it should only be used for this Add some custom attribute fields ② After the component is fully initialized,
  After entering the page node tree, attached Lifecycle functions will be triggered
  at this time, this.data has been initialized ● This life cycle is very useful, and most of the initialization work can be carried out at this time.( For example, send a request to get the initial data)
③ After the component leaves the page node tree, detached Lifecycle functions will be triggered ● When exiting a page, it will trigger each custom component in the page detached life cycle function ● This is a good time to do some clean-up work

  

Nine, the life cycle function of the page to which it belongs

1. What is the life cycle of the page where the component is located
Sometimes, the behavior of custom components depends on changes in the state of the page, in which case the life cycle of the page where the component is located needs to be used.

// components/rgbView/rgbView.js
Component({
  pageLifetimes: {
    // Executed when the referenced page is displayed
    show() {},
    // Executed when the referenced page is hidden
    hide() {},
    // Executed when the referenced page is changed in size, the size can be obtained
    resize(size) {},
  }
})

 

Demo case, write a random color generation method in the color component:

  /**
   * Component's method list
   */
  methods: {
    /**
     * Generate random colors
     */
    _randomColor() {
      this.setData({
        _rgb: {
          r: Math.floor(Math.random() * 256),
          g: Math.floor(Math.random() * 256),
          b: Math.floor(Math.random() * 256)
        }
      })
    },
  }

  

Called at the cycle time of page rendering and display:

  pageLifetimes: {
    // Executed when the referenced page is displayed
    show() {
      // Fired when the referenced page is displayed
      this._randomColor()
    }
  }

  

10. Slot component slot

single slot

write a component

<!--components/test4/test4.wxml-->
<text>components/test4/test4.wxml</text>

<view>
  <view>This is the internal structure of the component</view>
  <slot></slot>
</view>

Use components:

<test4>
  <text>This is the part that embeds the component slot</text>
</test4>

  

multiple slots

<view>
  <view>This is the internal structure of the component 1</view>
  <slot name="before"></slot>
  <view>This is the internal structure of the component 2</view>
  <slot name="after"></slot>
  <view>This is the internal structure of the component 3</view>
</view>

The new version of WeChat needs to add JS configuration items:

There is no demonstration of the dark horse tutorial, indicating that it can be directly configured in the old version

// components/test4/test4.js
Component({
  options: {
    // Enable multi-slot support
    multipleSlots: true,
  }
}

When using, you need to specify the name:

<test4>
  <text slot="before">This is part 1 of the insert component slot</text>
  <text slot="after">This is part 2 of the embedded component slot</text>
</test4>

  

11. Communication problems between components

1. 3 ways of communication between parent and child components

①property binding
    ●It is used to set data from the parent component to the specified property of the child component, which can only be set JSON compatible data

②event binding
    ● Used for child components to pass data to parent components, arbitrary data can be passed

③Get component instance
    ● The parent component can also pass this.selectComponent()Get the child component instance object
    ● This allows direct access to arbitrary data and methods of subcomponents

  

1. The parent component (page) passes data to the child component:

<father counter="{{val1}}" />
<view> father components counter value: {{val1}}</view>  

Father component connection parameters:

// components/father/father.js
Component({
  /**
   * Component's property list
   */
  properties: {
    counter: {
      type: Number
    }
  }
})

 

Second, the child component passes data to the parent component

3. Event binding
Event binding is used to implement child-to-parent transfer of values, and any type of data can be passed. The use steps are as follows:

① in the parent component js , define a function,This function will be passed to the child component in the form of a custom event

② in the parent component wxml , pass the function reference defined in step 1 to the child component in the form of a custom event

③ in subcomponents js , by calling this.triggerEvent(custom event name',{/*parameter object*/ }) ,send data to parent component

④ in the parent component js in, through e.detail Get the data passed by the child component

  

1. The Father component first adds events and displays

<!--components/father/father.wxml-->
<text>components/father/father.wxml</text>

<view>exhibit Father components counter value:{{counter}}</view>
<button bindtap="addCounter">+1</button>

JS code to configure events and pass values ​​using event triggers:

  /**
   * Component's method list
   */
  methods: {
    addCounter() {
      this.setData({ counter: this.properties.counter + 1}) 
      // Synchronize the parent component
      this.triggerEvent('sync', { value: this.properties.counter})
    }
  }

When a page uses a component, bind the corresponding receiving method:

<father counter="{{val1}}" bind:sync="syncCounter" />
<view> father components counter value: {{val1}}</view>

Method writing:

  syncCounter(event) {
    // Receive parameters sent from child components
    this.setData({ val1: event.detail.value })
  },

  

3. Directly obtain the component instance to implement the call

You can call this.selectComponent("id or class selector") in the parent component to get the instance object of the child component,

This allows direct access to arbitrary data and methods of subcomponents.

When calling, you need to pass in a selector, such as this.selectComponent(".my-component").

<father 
  counter="{{val1}}" 
  bind:sync="syncCounter"
  class="cf"
  id="componentFather" />
<view> father components counter value: {{val1}}</view>
<button bindtap="getComponentFather"> test</button>

JS code:

The current version can't get the method of the component, the data attribute can be obtained

  /**
   * Get the component instance directly
   */
  getComponentFather() {
    // or id selector this.selectComponent('#componentFather')
    // or class selector this.selectComponent('.cf')
    const father = this.selectComponent('.cf')
    console.log(father)
    console.log(father.data.counter)
    // Can't get the component method?  Clear the cache, refresh the page and try again
    father.addCounter()
  },

 

12. behaviors

1. What are behaviors
behaviors are small programs used to implement code sharing features between components, similar to "mixins" in Vue.js

2. How behaviors work
Each behavior can contain a set of properties, data, lifecycle functions and methods.

When a component references it, its properties, data, and methods are incorporated into the component.

Each component can reference multiple behaviors, and behaviors can also reference other behaviors.

 

3. Create behavior

Call the Behavior(Object object) method to create a shared behavior instance object for all components to use:

// /behaviors/bhvirs1.js
module.exports = Behavior({
  // Attributes
  properties: {},
  // data
  data: { msg: 'Hello Behaviors!'},
  // method
  methods: {
    
  }
})

  

4. Import and use behavior

In the component, use the require() method to import the required behavior,

After mounting, you can access the data or methods in the behavior,

The sample code is as follows:

// components/father/father.js
const b1 = require('../../behaviors/bhvirs1')

Component({
  behaviors: [b1],
})

  

Components can display values ​​from Behaviors

<view>exhibit Behvior data {{msg}}</view>

  

All corresponding set properties:

 

Conflict problem, see the official document description

https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html

  

 

Posted by neo_phyte on Wed, 04 May 2022 19:07:57 +0300