小程序自定义组件
创建自定义组件
开发者可以将页面内的功能模块抽象成自定义组件,在小程序的各个页面中进行使用,提升代码复用度,节省开发成本。
解释:一个自定义组件由 4 个文件组成(.dlt,.css,.js,.json)组成,例如包含自定义组件 custom-component 的项目结构:
// 包含自定义组件 custom-component 的项目结构
├── app.js
├── app.json
└── pages
└── components
├── custom-component.dlt
├── custom-component.css
├── custom-component.js
└── custom-component.json
要编写一个自定义组件,首先需要在 json 文件中进行自定义组件声明(在 json 文件中将 component 字段设为 true 可将这一组文件设为自定义组件):
// 自定义组件配置 (custom-component.json)
{
"component": true
}
同时,类似于页面开发。开发自定义组件,可以在 dlt 文件中编写组件模板,在 css 文件中引入样式,它们的写法和页面的写法类似。 代码示例
<!-- 自定义组件内部的模板 (custom-component.dlt) -->
<view class="name"> {{name}} </view>
/* 自定义组件的 css,在该自定义组件内部生效 (custom-component.css) */
.name {
color: red;
}
在自定义组件的 js 文件中,需要使用 Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法。
组件的属性值和内部数据将被用于组件 dlt 模板的渲染,其中,属性是可以由组件外部传入的。
// 自定义组件逻辑 (custom-component.js)
Component({
properties: {
// 定义了 name 属性,可以在使用组件时,由外部传入。此变量可以直接在组件模板中使用
name: {
type: String, // 类型(必填),目前接受类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
value: "hello world", // 属性初始值(必填)
observer: function (newVal, oldVal) {
// 属性被改变时执行的函数(可选)
},
},
},
data: {
// 这里是一些组件内部数据
age: 1,
},
methods: {
// 这里是一个自定义方法
tap: function () {},
},
});
使用自定义组件
使用已注册的自定义组件前,首先要在页面的 json 文件中进行引用声明。除了在页面使用自定义组件,你还可以在自定义组件引用自定义组件,类似于页面引用自定义组件。
以下举例页面级(pages/index/index)的使用场景:
// 项目目录结构
├── app.js
├── app.json
└── pages
├──index
│ ├── index.dlt
│ ├── index.css
│ ├── index.js
│ └── index.json
└── components
├── custom-component.dlt
├── custom-component.css
├── custom-component.js
└── custom-component.json
首先需要提供每个自定义组件的标签名与其对应的自定义组件文件路径。
提示:
1.自定义组件文件路径: 自定义组件 dlt、css、js、json 文件所在路径 + 该类文件的 basename,例如以上项目目录结构,该路径即是/pages/components/custom-component;
2.创建自定义组件,推荐内层的文件(dlt、css、js、json)与其自定义组件目录保持同名。
代码示例
// 页面 json 配置 index.json
{
"navigationBarTitleText": "小程序自定义组件示例",
"usingComponents": {
"custom-component": "/pages/components/custom-component"
}
}
这样在页面的 dlt 文件中,就可以像使用基础组件一样使用自定义组件。节点名即自定义组件的标签名,节点属性即传递给组件的属性值。
<!-- 页面模板 (index.dlt) -->
<view>
<!-- 在页面中对自定义组件进行引用 -->
<custom-component></custom-component>
</view>
自定义组件的 dlt 节点结构在与数据结合之后,将被插入到引用位置内。
组件模板
组件模板的写法与页面模板相同。组件模板与组件数据结合后生成的节点树,将被插入到组件的引用位置上。
在组件模板中可以提供一个<slot>
节点,用于承载组件引用时提供的子节点。
代码示例
<!-- 自定义组件内部的模板 (custom-component.dlt) -->
<view class="wrapper">
<view bind:tap="onTap">组件内部节点:{{val}}</view>
<slot></slot>
</view>
<view>
<custom-component>
<view>这里是插入到组件slot中的内容</view>
</custom-component>
</view>
模板数据绑定(页面向自定义组件传值)
与普通的 dlt 模板类似,可以使用数据绑定,这样就可以向子组件的属性传递动态数据。
<!-- 自定义组件所在页面 index.dlt-->
<view>
<custom-component :message="msg"> </custom-component>
</view>
// 自定义组件所在页面的 index.js
const app = getApp();
Page({
data: {
msg: "pageOldMessage",
},
changeData: function () {
this.setData({
msg: "pageNewMessage",
});
},
});
以上写法,在触发 changeData 后,传入给自定义组件的 message 就会被更新为 pageNewMessage
// 自定义组件 custom-component.js
Component({
properties: {
message: {
// 属性名
type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
value: "val", // 属性初始值(必填)
observer: function (newVal, oldVal) {
console.log("====newVal, oldVal====", newVal, oldVal);
// 属性被改变时执行的函数(可选)
},
},
},
data: {},
});
<!-- 自定义组件内部的模板 (custom-component.dlt) -->
<view> {{message}} </view>
以上自定义组件渲染出来的 message 字段来自于页面容器的 msg 字段,当页面的 data.msg 变更时,这里获取到的 message 也会同步变更。
自定义组件与页面的事件通信(改变页面的数据)
通过 triggerEvent 方法与父组件通信
<!-- 自定义组件所在页面 index.dlt-->
<view>
<view>{{pageData}}</view>
<custom-component bindmyevent="change" :message="pageData"></custom-component>
</view>
// 自定义组件所在页面的 index.js
Page({
data: {
pageData: "hello",
},
change: function (data) {
// 用于给自定义组件变更数据的函数
this.setData({
pageData: data.val,
});
},
});
// 自定义组件的逻辑 custom-component.js
Component({
properties: {
message: {
type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
value: "val", // 属性初始值(必填)
observer: function (newVal, oldVal) {
console.log("====newVal, oldVal====", newVal, oldVal);
// "====newVal, oldVal====", world, hello
},
},
},
data: {},
methods: {
onTap: function () {
var myEventDetail = {
val: "world",
}; // detail 对象,提供给事件监听函数
var myEventOption = {}; // 触发事件的选项
this.triggerEvent("myevent", myEventDetail, myEventOption);
// 注意这里的事件名为 myevent,在组件标签上绑定的是 bindmyevent,这里不可以写作 :myevent 和 bind:myevent
},
},
});
📢 注意:
triggerEvent 的事件名在标签绑定时要加上 bind,并且不可以用 :连接,即: myevent => bindmyevent="在页面上定义的函数名称"
Component 构造器
代码示例
// 自定义组件 js
Component({
properties: {
propName: {
// 属性名
type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
value: "val", // 属性初始值(必填)
observer: function (newVal, oldVal) {
// 属性被改变时执行的函数(可选)
},
},
},
data: {
val: "hello",
}, // 私有数据,可用于模版渲染
pageLifetimes: {
show: function () {
// 组件所在的页面被展示时触发
console.log("==Component=pageLifetimes=show====");
},
hide: function () {
// 组件所在的页面被隐藏时触发
console.log("==Component=pageLifetimes=hide====");
},
resize: function () {
// 组件所在的页面切换屏幕方向时触发 -- 暂不支持
console.log("==Component=pageLifetimes=resize====");
},
},
lifetimes: {
created: function () {
// 在组件实例进入页面节点树时执行
console.log("==Component=lifetimes=created====");
},
attached: function () {
// 在组件实例进入页面节点树时执行
console.log("==Component=lifetimes=attached====");
},
ready: function () {
// 在组件实例进入页面节点树时执行
console.log("==Component=lifetimes=ready====");
},
detached: function () {
// 在组件实例被从页面节点树移除时执行
console.log("==Component=lifetimes=detached====");
},
},
methods: {
onTap: function () {
this.setData({
// 更新属性和数据的方法与更新页面数据的方法类似
val: "world",
});
},
},
});
自定义组件的生命周期可以参考 小程序生命周期
自定义组件内使用 sjs
自定义组件内支持使用 sjs,sjs 使用参考小程序 SJS 介绍与使用
使用示例
// 项目目录结构
├── app.js
├── app.json
└── pages
└── index
├── index.dlt
├── index.css
├── index.js
└── index.json
└── components
├── custom-component.dlt
├── custom-component.css
├── custom-component.js
├── componentSjs.sjs
└── custom-component.json
代码示例
<!-- 自定义组件内部的模板 (custom-component.dlt) -->
<view class="wrapper">
<view class="title" bind:tap="onTap">组件内部节点======</view>
<slot></slot>
<view>message-----{{componentSjs.message()}}</view>
<view>{{val}}</view>
<view bind:tap="{{componentSjs.tapitem}}">tapitem</view>
<import-sjs module="componentSjs" src="./componentSjs.sjs"></import-sjs>
</view>
// componentSjs.sjs
export default {
message: function () {
return "hello world ";
},
tapitem: function (event, instance) {
instance.setStyle({
color: "#ff0",
});
},
};