Из версии базовой библиотеки апплета1.6.3Изначально апплет поддерживает простое компонентное программирование. Чтобы просмотреть версию базовой библиотеки Mini Program, которую вы используете, вы можете щелкнуть сведения в правой части инструментов разработчика, чтобы просмотреть:
самые основные компоненты
Компонент апплета на самом деле представляет собой каталог, который должен содержать 4 файла:
- xxx.json
- xxx.wxml
- xxx.wxss
- xxx.js
объявить компонент
Сначала вам нужноjson
Сделайте объявления пользовательских компонентов в файле (будетcomponent
поле установлено наtrue
Этот набор файлов можно установить как пользовательские компоненты)
{
"component": true
}
Во-вторых, в json-файле страницы, которую нужно ввести в компонент, сделайте объявление ссылки
{
"usingComponents": {
//自定义的组件名称 : 组件路径,注意是相对路径,不能是绝对路径
"component-tag-name": "path/to/the/custom/component"
}
}
Таким образом, его можно использовать на главной странице.
По сравнению с введением компонентов Vue решение апплета более лаконичное. Внедрение компонентов vue необходимо одновременно импортировать и регистрировать в компонентах, в то время как компоненты апплета необходимо зарегистрировать только в .json и можно использовать в wxml.
использовать слот
Как и vue, апплет также имеет концепцию слота.
один слот
Шаблон компонента может предоставить<slot>
Узел, который используется для переноса дочерних узлов, предоставляемых при ссылке на компонент.
// 主页面内,<addlike>是组件
<addlike item="item" my_properties="sssss">
<text>我是被slot插入的文本</text>
</addlike>
// addlike 组件
<view class="container">
<view>hello, 这里是组件</view>
<view>hello, {{my_properties}}</view>
<slot></slot>
</view>
// 渲染后
<view class="container">
<view>hello, 这里是组件</view>
<view>hello, {{my_properties}}</view>
<text>我是被slot插入的文本</text>
</view>
несколько слотов
Если вам нужно использовать несколько слотов в компоненте, вам нужно объявить и включить его в компоненте js:
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
properties: { /* ... */ },
methods: { /* ... */ }
})
использовать:
// 主页面
<addlike item="item" my_properties="sssss">
// 在普通的元素上加入 slot 属性,指定slotname, 就可以变成子元素的slot了
<text slot="slot1">我是被slot1插入的文本</text>
<text slot="slot2">我是被slot2插入的文本</text>
</addlike>
// 子页面
<view class="container">
<view>hello, 这里是组件</view>
<view>hello, {{my_properties}}</view>
<slot name="slot1"></slot>
<slot name="slot2"></slot>
</view>
Конструктор компонентов
Как мы только что сказали, компонент должен включать четыре файла: js, wxml, wxss и json. wxml эквивалентен HTML, а wxss эквивалентен css, так что же нужно писать на js?
В случае, предоставленном официальным лицом WeChat:
Component({
behaviors: [],
properties: {
},
data: {}, // 私有数据,可用于模版渲染
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function(){},
moved: function(){},
detached: function(){},
methods: {
onMyButtonTap: function(){
},
_myPrivateMethod: function(){
},
_propertyChange: function(newVal, oldVal) {
}
}
})
Он вызывает конструктор компонента. Конструктор компонента можно использовать для определения компонентов.При вызове конструктора компонента можно указатьсвойства, данные, методыЖдать. Что можно поместить в конкретный компонент, как показано ниже:
properties | Object Map | нет | Эквивалентно реквизиту Vue, через это свойство внешний мир передает данные в компонент. Внешним свойством компонента является таблица сопоставления имени свойства с настройкой свойства.Настройка свойства может содержать три поля.type Указывает тип атрибута,value Указывает начальное значение свойства,observer Представляет функцию ответа при изменении значения свойства. |
data | Object | нет | внутренние данные компонента иproperties Используются вместе для шаблонного рендеринга компонентов. То есть данные и свойства могут быть получены одновременно через this.data. |
methods | Object | нет | Методы компонентов, включая функции ответа на событие и любые пользовательские методы, для использования функций ответа на событие см.события компонентов |
behaviors | String Array | нет | Механизм повторного использования кода между компонентами, аналогичный миксинам и трейтам, см.behaviors |
created | Function | нет | Функция жизненного цикла компонента, выполняемая, когда экземпляр компонента входит в дерево узлов страницы, обратите внимание, что ее нельзя вызвать в это время.setData
|
attached | Function | нет | Функция жизненного цикла компонента, выполняемая, когда экземпляр компонента входит в дерево узлов страницы. |
ready | Function | нет | Функция жизненного цикла компонента, которая выполняется после завершения компоновки компонента, и в это время может быть получена информация об узле (используяSelectorQuery) |
moved | Function | нет | Функции жизненного цикла компонента, выполняемые при перемещении экземпляра компонента в другое место в дереве узлов. |
detached | Function | нет | Функции жизненного цикла компонента, выполняемые при удалении экземпляра компонента из дерева узлов страницы. |
relations | Object | нет | Определенные отношения между компонентами, см.отношения между компонентами |
options | Object Map | нет | Некоторые параметры компонента, см. описания в других разделах документации. |
Компоненты и передача данных
Компонентизация неизбежно включает в себя передачу данных.Чтобы решить проблему обслуживания данных между компонентами, у vue, react и angular есть разные решения. Небольшое программное решение намного проще.
Главная страница передает данные компоненту
Свойства эквивалентны свойствам Vue, которые являются точками входа для входящих внешних данных.
// 主页面使用组件
<a add_like="{{add_like}}">
</a>
// 组件a.js 内
Component({
properties:{
add_like:{
type:Array,
value:[],
observer:function(){
}
}
}
})
Примечание. Входящие данные, независимо от того, являются ли они простым типом данных или ссылочным типом,копия значенияТакой же(Отличие от описания в красной книге сокровищ состоит в том, что параметры функции js передаются как копирование значений, смысл в красной книге сокровищ таков: простые типы данных копируют значения напрямую, а ссылочные типы копируют ссылки, то есть изменяют свойства объекта параметра внутри функции, влияет на свойства объектов вне функции).
Если это реквизит Vue, его можно синхронизировать через .sync, а в подкомпоненте апплета вызов this.setData() для изменения данных в родительском компоненте не повлияет на данные в родительском компоненте, то есть дочернем. изменение свойства компонента, похоже, не имеет ничего общего с родительским компонентом. Итак, если вы измените данные родительского компонента в дочернем компоненте или даже измените данные в родственном компоненте, есть ли простой способ? Он будет упомянут ниже
Компонент исходящих данных на главную страницу
Как и в Vue, основной формой взаимодействия между компонентами являются пользовательские события.
компоненты проходят this.triggerEvent()
Запустите пользовательское событие, главная страница находится на компонентеbind:component_method="main_page_mehod"
для получения пользовательских событий.
в,this.triggerEvent()
Помимо получения имени пользовательского события, метод также получает два объекта:eventDetail
а такжеeventOptions
.
// 子组件触发自定义事件
ontap () {
// 所有要带到主页面的数据,都装在eventDetail里面
var eventDetail = {
name:'sssssssss',
test:[1,2,3]
}
// 触发事件的选项 bubbles是否冒泡,composed是否可穿越组件边界,capturePhase 是否有捕获阶段
var eventOption = {
composed: true
}
this.triggerEvent('click_btn', eventDetail, eventOption)
}
// 主页面里面
main_page_ontap (eventDetail) {
console.log(eventDetail)
// eventDetail
// changedTouches
// currentTarget
// target
// type
// ……
// detail 哈哈,所有的子组件的数据,都通过该参数的detail属性暴露出来
}
обмен данными между компонентами
В отличие от решения vuex, предложенного vue, связь между компонентами апплета проста и компактна. Вы можете использовать пользовательские события для связи так же, как главная страница взаимодействует с компонентами.Конечно, более простой и удобный способ — использовать отношения, предоставляемые апплетом.
отношения — это свойство в конструкторе компонентов.Пока свойства отношений двух компонентов связаны, они могут захватывать друг друга, получать доступ друг к другу и изменять свойства друг друга, точно так же, как изменять свои собственные свойства.
Component({
relations:{
'./path_to_b': { // './path_to_b'是对方组件的相对路径
type: 'child', // type可选择两组:parent和child、ancestor和descendant
linked:function(target){ } // 钩子函数,在组件linked时候被调用 target是组件的实例,
linkChanged: function(target){}
unlinked: function(target){}
}
},
})
Например, есть два компонента, как показано в коде:
// 组件a slot 包含了组件b
<a>
<b></b>
</a>
Связь между ними показана на следующем рисунке:
Два компонента захватывают экземпляр другого компонента с помощью метода this.getRelationNodes('./path_to_a'). Теперь, когда экземпляр противоположного компонента получен, вы можете получить доступ к данным противоположного компонента, а также можете установить данные противоположного компонента, но вы не можете вызвать метод противоположного компонента.
// 在a 组件中
Component({
relations:{
'./path_to_b': {
type: 'child',
linked:function(target){ } // target是组件b的实例,
linkChanged: function(target){}
unlinked: function(target){}
}
},
methods:{
test () {
var nodes = this.getRelationNodes('./path_to_b')
var component_b = nodes[0];
// 获取到b组件的数据
console.log(component_b.data.name)
// 设置父组件的数据
// 这样的设置是无效的
this.setData({
component_b.data.name:'ss'
})
// 需要调用对方组件的setData()方法来设置
component_b.setData({
name:'ss'
})
}
}
})
// 在b 组件里面
Component({
relations:{
'./path_to_a': { //注意!必须双方组件都声明relations属性
type:'parent'
}
},
data: {
name: 'dudu'
}
})
Примечание: 1. При использовании компонентов на главной странице у вас не может быть номеров, таких как
{
"usingComponents":{
"test_component_subb": "../../../components/test_component_sub2/test_component_sub2"
}
}
2. Путь в отношениях, например здесь:
Быть
Это реальный относительный путь противоположного компонента, а не логический путь между компонентами.
3. Если отношения не связаны, то this.getRelationNodes не может получить другой компонент
4. Этот компонент не может получить экземпляр этого компонента, использование this.getRelatonsNodes('./path_to_self ') вернет null
4. тип можно выбратьparent
,child
,ancestor
,descendant
Теперь, когда мы можем передавать данные между двумя компонентами, как передать данные между несколькими компонентами?
Как показано на рисунке выше, компонент b одного уровня и компонент c одного уровня не могут быть получены напрямую между b и c. b может получить a, c также может получить a, а a может напрямую получить b и c. . Следовательно, если вы хотите получить родственный элемент, вам нужно сначала получить узел-предок, а затем получить узел-брат через узел-предок.
я здесь组件b
Внутри мне нужно сначала найти祖先组件a
экземпляр, затем используйте祖先组件a
случайgetRelationNodes
способ получить组件c
пример. Быть
ты это видел? Боюсь, нам снова придется писать много повторяющегося кода.
К счастью, апплет WeChat также предоставляет атрибут поведения, эквивалентный примеси, который прост для понимания и позволяет улучшить повторное использование кода.
Идеи:
Предположим, что в настоящее время имеется три компонента: компонент a, компонент b и компонент c, где компонент b и компонент c являются одноуровневыми компонентами, а компонент a является одноуровневым компонентом b и c. Чтобы уменьшить дублирование кода, мы инкапсулируем метод получения родительского компонента и метод получения родственного компонента, а также инкапсулируем их в методы поведения. Пока это компонент, который вводит поведение, метод может быть вызван удобно.
выполнить:
Создайте новый файл поведения, имя не имеет значения, например, ratio_behavior.js.
// 在 get_relation.js 文件里面
module.exports = Behavior({
methods:{
// 获取父组件实例的快捷方法
_parent () {
// 如果根据该路径获取到acestor组件为null,则说明this为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]
}
}
}
})
Затем введите поведение для компонента b и компонента c и вызовите метод, чтобы получить экземпляры родительских компонентов и одноуровневых компонентов.
// 组件b中
var relation_behavior = require('./path_to_relation_behavior')
Component({
behaviors:[relation_behavior],
methods:{
test () {
// 获得父组件的实例
let parent = this._parent()
// 访问父组件的数据d
console.log(parent.data.name)
// 修改父组件的数据
parent.setData({
name: 'test1'
})
// 获得兄弟组件的实例
let sibling = this._sibling('c')
// 访问兄弟组件的数据
console.log(sibling.data.name)
// 修改兄弟组件的数据
sibling.setData({
name:"test"
})
}
}
})
// 组件c中
var relation_behavior = require('./path_to_relation_behavior')
Component({
behaviors:[relation_behavior],
methods:{
test () {
// 获得父组件的实例
let parent = this._parent()
// 访问父组件的数据d
console.log(parent.data.name)
// 修改父组件的数据
parent.setData({
name: 'test1'
})
// 获得兄弟组件的实例
let sibling = this._sibling('b')
// 访问兄弟组件的数据
console.log(sibling.data.name)
// 修改兄弟组件的数据
sibling.setData({
name:"test"
})
}
}
})
В то же время следует отметить, что два компонента c и b с точки зрения свойства отношения являются потомками компонента a.
Однако областью действия компонента b и компонента c является область действия главной страницы, а входящие свойства — свойства главной страницы, что обеспечивает гибкость данных компонента. Отношения связывают множество компонентов наподобие невидимой цепочки.Связанные компоненты могут обращаться друг к другу и изменять данные друг друга, но каждый компонент может независимо получать данные из внешнего мира.
Прочитав так много теоретических вещей, мне все еще нужен конкретный сценарий для применения.
Например, у нас есть страница для обмена и записи настроения картинки, когда пользователь нажмет кнопку [Нравится], кнопка лайк записи настроения станет красной, а имя того, кто поставил лайк, добавить в следующую колонку.
Если это не компонентизация, то, скорее всего, будет изменена кнопка «Нравится», затем будет выполнен обход данных для обновления данных, и, наконец, будет повторно отображено состояние всех списков записей.
Если он разделен на компоненты: инкапсулируйте кнопку «Мне нравится» как组件b
, поле подобного человека ниже инкапсулировано как组件c,
Каждая запись настроения — это组件a
Ниже приведена реализация кода
// 在主页面内
<view wx:for='{{feed_item}}'>
<a item='{{item}}'>
<b></b>
<c></c>
</a>
<view>
// 在组件a内
var behavior_relation = require('../../relation_behavior.js) //这里引入上文说的Behavior
Component({
behaviors:[behavior_relation],
relations:{
'../b/b':{
type: 'descendant'
}
}
})
// 在组件b内
var behavior_relation = require('../../relation_behavior.js) //这里引入上文说的Behavior
Component({
behaviors:[behavior_relation]
relations:{
'../a/a':{
type: 'ancestor'
}
},
data: {
is_like: false //控制点赞图标的状态
},
methods:{
// 当用户点赞的时候
onClick () {
// 修改本组件的状态
this.setData({
is_like: true
})
// 修改 c 组件的数据
this._sibling('c').setData({
likeStr: this._sibling('c').data.likeStr + '我'
})
}
}
})
// 在组件c内
var behavior_relation = require('../../relation_behavior.js) //这里引入上文说的Behavior
Component({
behaviors:[behavior_relation],
relations:{
'../a/a':{
type: 'ancestor'
}
},
data:{
likeStr:'晓红,小明'
}
})
Таким образом, компонент b может изменять данные в компоненте c. В то же время компонент b и компонент c могут поддерживать независимый обмен данными с главной страницей через систему свойств и событий.