Starting with applets Base library version 1.6.3, applets support concise componentized programming. To view the version of the applets base library you are using, click the details on the right side of the Developer Tools:

The most basic components

The applets component, in fact, is a directory, the directory should contain four files:

  1. xxx.json
  2. xxx.wxml
  3. xxx.wxss
  4. xxx.js

Declare a component

First you need to make a custom component declaration in the JSON file (set the Component field to true to make this set of files custom components)

{
  "component": true
}Copy the code

Second, make a reference declaration in the JSON file of the page where the component is to be imported

{" usingComponents ": {/ / custom component name: component path, pay attention to is the relative path, cannot be an absolute path" component - tag - name ":" the path/to/the/custom/component "}}Copy the code

 

This way, you can use it on the main page.

Compared to vUE’s component introduction, the scheme of applets is more concise. Vue components need to be imported and registered in components, while applet components need to be registered in.json to be used in WXML.

Using slot.

Like vUE, applets have the concept of slot.

A single slot.

A

node can be provided in the component template to host the child nodes provided when the component references.

// In the main page, < addLike > is the component <addlike item="item" my_properties=" SSSSS "> <text> I am the text inserted by slot </text> </ addLike > / addLike component <view Class ="container"> <view>hello, here is the component </view> <view>hello, {{my_properties}}</view> <slot></slot> </view> // render <view class="container"> <view>hello, here is the component </view> <view>hello, {{my_properties}}</view> <text> I am slot inserted text </text> </view>Copy the code

More than one slot.

If you need to use multiple slots within a component, you need to declare enable in the component js:

Component({options: {multipleSlots: true // Enable multiple slot support in Component definition options}, Properties: {/*... */ }, methods: { /* ... * /}})Copy the code

Use:

< addLike item="item" my_properties=" SSSSS "> Specify slotname, <text slot="slot1"> </text> <text slot="slot2"> I am slot2 inserted text </text> </addlike> // child page <view Class ="container"> <view>hello, here is the component </view> <view>hello, {{my_properties}}</view> <slot name="slot1"></slot> <slot name="slot2"></slot> </view>Copy the code


Component constructor

As mentioned earlier, a component should contain js, WXML, WXSS, and JSON files. WXML is equivalent to HTML, WXSS is equivalent to CSS, so what should you put in JS?

Among the cases provided by wechat officials:

Component({behaviors: [], properties: {}, data: {}, // Private data that can be used for template rendering // Lifecycle functions, which can be functions, or a method name defined in the Methods section attached: function(){}, moved: function(){}, detached: function(){}, methods: { onMyButtonTap: function(){ }, _myPrivateMethod: function(){ }, _propertyChange: function(newVal, oldVal) { } } })Copy the code

It calls a Component constructor. The Component constructor can be used to define components, specifying their properties, data, methods, and so on when called. What can be put in the specific Component like this:

properties Object Map no This is analogous to the props of vue, through which the outside world passes data to the component. The external properties of a component are a mapping table of property names to property Settings, which can contain three fields,typeRepresents the property type,valueRepresents the initial value of the attribute,observerRepresents the response function when the property value is changed
data Object no Component internal data, andpropertiesTogether with template rendering of components. That is, this.data can be used to get both data and properties
methods Object no Component methods, including event response functions and arbitrary custom methods, for use of event response functions, seeComponent events
behaviors String Array no For code reuse mechanisms between components similar to mixins and traits, seebehaviors
created Function no The component lifecycle function, executed when the component instance enters the page node tree, cannot be called at this timesetData
attached Function no Component lifecycle function, executed when the component instance enters the page node tree
ready Function no Component lifecycle functions that are executed after the component layout is complete, at which point node information can be retrieved (usingSelectorQuery )
moved Function no Component lifecycle function, executed when the component instance is moved to another location in the node tree
detached Function no Component lifecycle function, executed when the component instance is removed from the page node tree
relations Object no For the definition of relationships between components, seeIntercomponent relationship
options Object Map no See other sections of the documentation for some component options

 

Components communicate with data

Componentization involves data communication, and vue, React, and Angular have different solutions for maintaining data between components. The solution for applets is much cleaner.

The main page passes data to the component

Properties is equivalent to props of vue and is the entry point to external data.

<a add_like="{{add_like}}"> </ A > // Component.js ({properties:{add_like:{type:Array, value:[], observer:function(){ } } } })Copy the code

Note: The data that is passed in, whether it is a simple data type or a reference type, is passed in as a value copy. Simple data types copy values directly, and reference types copy references, that is, modifying the properties of parameter objects inside a function affects the properties of objects outside the function.

If it is the props of Vue, the.sync function can be used to synchronize data. In the subroutine, a call to this.setData() will not affect the data in the parent component. Is there an easy way to modify the parent’s data within a child, or even a sibling? We’ll talk about that

 

Components export data to the main page

Similar to VUE, the main form of interaction between components is custom events.

The component fires custom events via this.triggerEvent(). The home page receives custom events on the component bind: Component_method =”main_page_mehod”.

The this.triggerEvent() method receives two objects, eventDetail and eventOptions, in addition to the custom event name.

Ontap () {// All data to be taken to the main page, Var eventDetail = {name:' SSSSSSSSS ', test:[1,2,3]} Var eventOption = {composed: true } this.triggerEvent('click_btn', eventDetail, // View views // view views // view views // view views CurrentTarget // target // type //...... // detail ha, all child component data is exposed by the detail property of this parameter}Copy the code

Data communication between components

Unlike Vue’s vuex solution, the communication between the components of the applets is simple and compact. You can use custom events to communicate just as the main page communicates with components, but an easier and more convenient way is to use relations provided by the applet.

Relations is a property in the Component constructor. Once the relations property of two components is related, they can capture each other and access each other and modify each other’s properties as if they were modifying their own.

Component({relations:{'./ path_to_B ': {// './ path_to_B 'is the relative path type of the other Component: 'child', // type Select two groups: Parent and child, ancestor and descendant linked:function(target){} function(target){} unlinked: function(target){} } }, })Copy the code

For example, there are two components that look like this:

<a> <b></b> </a>Copy the code

Their relationship is shown below:

 

Two components capture each other’s component instance using the this.getRelationNodes(‘./ path_to_A ‘) method. Now that you have an instance of the other component, you can access data on the other component and set data on the other component, but you cannot call methods on the other component.

 

Component({relations:{'./path_to_b': {type: 'Child ', linked:function(target){} // Target is an instance of component B, linkChanged: function(target){} function(target){} } }, methods:{ test () { var nodes = this.getRelationNodes('./path_to_b') var component_b = nodes[0];  SetData ({component_B.data.name :'ss'}) // Console. log(component_B.data.name) // Set the data of the parent component.setData ({component_B.data.name :'ss'}) // Component_b.setdata ({name:'ss'})}}}) Component({relations:{'./ path_to_A ': {relations:{'./path_to_a': {relations:{'. {// Attention! Both components must declare the relations property type:'parent'}}, data: {name: 'dudu'}})Copy the code

 

< COMPONent_sub1 > <component_sub_1> <component_sub1> <component_sub_1> <component_sub1> <component_sub_1

{ "usingComponents":{ "test_component_subb": ".. /.. /.. /components/test_component_sub2/test_component_sub2" } }Copy the code

2. Paths in relations, such as here:



Is the real relative path of each other’s components, not the logical path between components.

3. If relations is not associated, this.getRelationNodes will not get the other component

4. This component cannot get an instance of this component. This.getrelatonsNodes (‘./ path_to_self ‘) returns null

4. type 可以选择的 parent 、 child 、 ancestor 、 descendant 

 


Now that we can transfer data between two components, how do we transfer data between multiple components?

 

As shown in the figure above, component B of the same level and component C of the same level cannot be directly obtained between B and C. B can obtain A, and C can also obtain A, and A can directly obtain B and C. So, if you want to get the sibling element, you need to get the ancestor node first, and then get the sibling node through the ancestor node

I am in
The component bInside. I need to find it first
Ancestor component A“, and then use
Ancestor component AAn instance of
getRelationNodesMethod to obtain
Component cThe instance.

See yet? I’m afraid we’re going to be writing a lot of repetitive code again.

 

Fortunately, wechat applet also provides the behavior attribute, which is the equivalent of mixin and is an easy way to improve code reuse.

Ideas:

Suppose there are currently three components, component A, component B, and component C, where components B and C are siblings, and component A is a sibling of B and C. In order to reduce the repeatability of the code, we encapsulate the methods of obtaining the parent component and the methods of obtaining the sibling component in behavior methods. Methods can be easily called by any component that introduces this behavior.

Implementation:

Create a behavior file named relation_behavior.js, for example

Module.exports = Behavior({methods:{parent () {// Module.exports = Behavior({methods:{parent () {// module.exports = Behavior({methods:{parent () {// If the acestor component is null, ancesor var parentNode = this.getRelationNodes('.. /record_item/record_item') if (parentNode&&parentNode.length ! == 0) { return parentNode[0] } else { return this } }, _sibling(name) {var node = this._parent().getrelationNodes ('.. /${name}/${name}`) if (node &&node.length > 0) { return node[0] } } } })Copy the code

The behavior is then imported on components B and C, and methods are called to get instances of the parent and sibling components

// Var relation_behavior = require('./path_to_relation_behavior') Component({behaviors:[relation_behavior], Methods :{test () {let parent = this._parent() // access the data of the parent component d console.log(parent-data.name) // modify the data of the parent component parent.setData({ name: 'test1'}) // get sibling instance let sibling = this._sibling('c') // Access sibling data console.log(tsibling.data.name) // Modify sibling data Sibling. SetData ({name:"test"})}}}) var relation_behavior = require('./path_to_relation_behavior') Component({ behaviors:[relation_behavior], Methods :{test () {let parent = this._parent() // access the data of the parent component d console.log(parent-data.name) // modify the data of the parent component parent.setData({ name: 'test1'}) // get sibling instance let sibling = this._sibling('b') // Access sibling data console.log(tsibling.data.name) // modify sibling data sibling.setData({ name:"test" }) } } })Copy the code

 

 

It should also be noted that c and B are descendants of A from the perspective of the relations property.

However, the scope of component B and component C is the scope of the main page, and the property passed in is the property of the main page, thus ensuring the flexibility of the component data. Relations acts like an invisible chain connecting a bunch of components, which can access and modify each other’s data, but each component can obtain data independently from the outside world.

 

See so many theoretical things, or need a specific scenario to apply.

For example, we have a page for sharing the mood of a recorded picture. When the user clicks the “like” button, the “like” button of the recorded mood will turn red and the name of the person who liked it will appear in the column below.

 

Without componentization, it is likely that you will modify a like button, iterate through the data to update the data, and eventually all the record list states will be rendered again.

In the case of componentization, the “like” button is encapsulated as component B, and the “like” box below is encapsulated as component C. Each mood record is a component A

Here is the code implementation

/ / in the main page < view wx: for = "{{feed_item}}" > < a item = "{{item}}" > < b > < / b > < c > < / c > < / a > < view > / / var behavior_relation = in component a require('.. /.. /relation_behavior.js) // Behavior Component({behaviors:[behavior_relation], relations:{'.. /b/b':{type: 'descendant'}}}) var behavior_relation = require('.. /.. // Behavior Component({behaviors:[behavior_relation] relations:{'.. /a/a':{ type: 'ancestor' } }, data: { is_like: SetData ({is_like: is_like: is_like: is_like: is_like: is_like: is_like: This._sibling ('c').setData({likeStr: This._sibling('c').data. LikeStr + 'I'})}}) var behavior_relation = require('.. /.. /relation_behavior.js) // Behavior Component({behaviors:[behavior_relation], relations:{'.. / a/a ': {type:' ancestor '}}, data: {likeStr: 'XiaoHong, xiao Ming'}})Copy the code

This way, component B can modify the data in component C. At the same time, components B and C can maintain independent data communication with the main page through the properties and event system.