【微信小程序】 自定义组件
创建微信小程序组件
在小程序中创建组件:
1、项目根目录中创建【components】目录,存放自定义组件
2、进入components目录,给组件创建一个组件目录
3、右键组件目录,选择【创建Components】
4、之后回车,会自动生成组件对应的4个文件, 后缀名分别为.js, .json, .wxml和.wxss
一、全局组件和局部组件
局部页面引用组件:
在【页面的.json】配置文件中引用组件的方式,叫做“局部引用”。
示例代码如下:
1 2 3 4 5 | { "usingComponents" : { "test1" : "/components/test1/test1" } } |
全局引用组件:
在【app.json】中配置组件信息
1 2 3 | "usingComponents" : { "test1" : "/components/test1/test1" } |
使用组件:
1 2 | <!-- 全局可以在任意页面中使用引入的组件, 局部组件只允许在引入的页面中使用 --> < test1 ></ test1 > |
组件和页面的区别
从表面来看,组件和页面都是由.js、 json、 .wxml 和.WXSS这四个文件组成的。
但是,组件和页面的js与.json文件有明显的不同:
1 2 3 | ● 组件的 json文件中需要声明"component": true属性< br > ● 组件的 js文件中调用的是Component()函数 < br >● 组件的事件处理函数需要定义到methods节点中 |
二、组件之间的样式隔离问题:
一、组件样式隔离
默认情况下,自定义组件的样式只对当前组件生效,不会影响到组件之外的UI结构
1 2 3 | ● 组件A的样式不会影响组件C的样式 ● 组件A的样式不会影响小程序页面的样式 ● 小程序页面的样式不会影响组件A和C的样式 |
好处:
1 2 3 | ① 防止外界的样式影响组件内部的样式 ② 防止组件的样式破坏外界的样式 |
二、组件样式隔离的注意点
1 2 3 4 | ● app.wxss中的全局样式对组件无效 ● 只有class选择器会有样式隔离效果, id选择器、属性选择器、标签选择器不受样式隔离的影响 |
建议:在组件和引用组件的页面中建议使用class选择器,不要使用id、属性、标签选择器!
三、修改组件的样式隔离选项
默认情况下,自定义组件的样式隔离特性能够防止组件内外样式互相干扰的问题。
但有时,我们希望在外界能够控制组件内部的样式,
此时,可以通过stylelsolation 修改组件的样式隔离选项,
用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // components/test1/test1.js Component({ options: { styleIsolation: 'isolated' } }) // components/test1/test1.json { "component" : true , "usingComponents" : {}, "styleIsolation" : "isolated" } |
四、 stylelsolation的可选值
1 2 3 4 5 6 7 8 | isolated 表示启用样式隔离,在自定义组件内外,使用class指定的样式将不会相互影响 apply-shared 表示页面WXSs样式将影响到自定义组件,但自定义组件wxSS中指定的样式不会影响页面< br > shared 表示页面WxSs样式将影响到自定义组件, 自定义组件Wxss中指定的样式也会影响页面和其他设置了apply-shared或shared的自定义组件 |
三、Data属性 和 Method方法
和页面一样设置
1 2 3 4 5 6 | /** * 组件的初始数据 */ data: { count: 0 }, |
方法是独立的一个对象存放
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** * 组件的方法列表 * 在这里编写自定义方法,和事件处理函数 * 自定义方法推荐使用下划线前缀标记 * 如: * addCount() // 事件执行方法 * _showCount() // 自定义方法 */ methods: { addCount() { this .setData({ count: this .data.count + 1}) this ._showCount() }, _showCount() { wx.showToast({ icon: 'none' , title: `count值:${ this .data.count}` }) } } |
四、Properties属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * 组件的属性列表 * 用来接收外部页面或者其他组件传递进来的属性 */ properties: { // 和vue一样的写法 max: { type: Number, value: 10 // 默认值 } /** * 简化写法,不设置默认值 * max: Number */ }, |
组件使用时可以设置值
1 | < test1 max="{{5}}"/> |
使用propertis数据
等于max值时无法继续叠加
1 2 3 4 5 | addCount() { if ( this .data.count === this .properties.max) return this .setData({ count: this .data.count + 1}) this ._showCount() }, |
五、data和properties的区别
在小程序的组件中,properties 属性和data数据的用法相同,它们都是可读可写的,只不过:
1 2 3 | ● data更倾向于存储组件的私有数据 ● properties更倾向于存储外界传递到组件中的数据 |
两者的地址一致:
1 | this .data === this .properties // true |
给properties属性赋值
1 2 | // 为properties的数据重新赋值 this .setData({ max: this .properties.max + 1 }) |
六、数据监听器
监听器功能再页面不支持
1 2 3 4 5 6 7 8 9 | /** * 组件的数据监听器 */ observers: { // 可以同时监听多个属性, 入参的参数对应属性个数,表示属性更新后的值 'attr1, attr2' : function (newValue1, newValue2) { // todo ... } }, |
演示案例:
组件HTML代码:
1 2 3 4 5 6 7 8 | <!--components/test2/test2.wxml--> < text >components/test2/test2.wxml</ text > < view > {{n1}} + {{n2}} = {{sum}} </ view > < button size="mini" type="primary" bindtap="addN1">n1增加</ button > < button size="mini" type="primary" bindtap="addN2">n2增加</ button > |
组件JS代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // components/test2/test2.js Component({ /** * 组件的数据监听器 */ observers: { 'n1, n2' : function (n1Value, n2Value) { this .setData({ sum: n1Value + n2Value }) } }, /** * 组件的属性列表 */ properties: { }, /** * 组件的初始数据 */ data: { n1: 0, n2: 0, sum: 0 }, /** * 组件的方法列表 */ methods: { addN1() { this .setData({ n1: this .data.n1 + 1 }) }, addN2() { this .setData({ n2: this .data.n2 + 1 }) } } }) |
演示案例2:
一个RGB颜色案例,HTML代码
1 2 3 4 5 6 7 8 9 10 11 12 | <!--components/rgbView/rgbView.wxml--> < text >components/rgbView/rgbView.wxml</ text > < view class="colorBox" style="background-color: rgb({{fullColor}});"> 颜色值:{{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代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | // components/rgbView/rgbView.js Component({ observers: { // 监听,然后重新赋值 'rgb.**' : function (newRgb) { this .setData({ fullColor: `${newRgb.r}, ${newRgb.g}, ${newRgb.b}` }) } }, /** * 组件的属性列表 */ properties: { }, /** * 组件的初始数据 */ data: { rgb: { r: 0, g: 0, b: 0 }, fullColor: '0, 0, 0' }, /** * 组件的方法列表 */ 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显示板样式:
1 2 3 4 5 6 7 8 | /* components/rgbView/rgbView.wxss */ .colorBox { line-height : 200 rpx; font-size : 24 rpx; color : white ; text-shadow : 0 rpx 0 rpx 2 rpx black ; text-align : center ; } |
七、纯数据字段
1.什么是纯数据字段
概念:纯数据字段指的是那些不用于界面渲染的data字段。
应用场景:例如有些情况下,某些data中的字段既不会展示在界面上,也不会传递给其他组件,仅仅在当前
组件内部使用。带有这种特性的data字段适合被设置为纯数据字段。
好处:纯数据字段有助于提升页面更新的性能。
2.使用规则
在Component构造器的options节点中,指定pureDataPattern为一个正则表达式,
字段名符合这个正则表达式的字段将成为纯数据字段,示例代码如下:
1 2 3 4 5 6 7 | // components/rgbView/rgbView.js Component({ options: { // 自定义正则规则来匹配纯数据字段,演示为首字符下划线的属性 pureDataPattern: /^_/ } } |
把之前的JS代码的rgb属性名改为_rgb使用即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // components/rgbView/rgbView.js Component({ options: { // 自定义正则规则来匹配纯数据字段,演示为首字符下划线的属性 pureDataPattern: /^_/ }, observers: { // 监听,然后重新赋值 '_rgb.**' : function (newRgb) { this .setData({ fullColor: `${newRgb.r}, ${newRgb.g}, ${newRgb.b}` }) } }, /** * 组件的属性列表 */ properties: { }, /** * 组件的初始数据 */ data: { _rgb: { r: 0, g: 0, b: 0 }, fullColor: '0, 0, 0' }, /** * 组件的方法列表 */ 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 }) } } }) |
八、组件的生命周期函数
全部的钩子函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // components/rgbView/rgbView.js Component({ lifetimes: { // 创建完成后执行 created() {}, // 组件实例和页面完成dom绑定后执行,等同vue的mounted attached() {}, // 组件再页面的视图渲染完成 ready() {}, // 组件被更新后执行(组件实例移动到节点树的新位置) moved() {}, // 组件从页面的dom树中移除时触发 detached() {}, // 组件发生异常触发 error() {} } }) |
主要的三个函数
2.组件主要的生命周期函数
在小程序组件中,最重要的生命周期函数有3个,分别是created、attached、 detached。 它们各自的特点
如下:
1 2 3 4 5 6 7 8 9 | ① 组件实例刚被创建好的时候,< br > created生命周期函数会被触发 ● 此时还不能调 用setData ● 通常在这个生命周期函数中, 只应该用于给组件的this添加一些自定义的属性字段 ② 在组件完全初始化完毕、< br > 进入页面节点树后,attached 生命周期函数会被触发< br > 此时,this.data 已被初始化完毕 ● 这个生命周期很有 用,绝大多数初始化的工作可以在这个时机进行( 例如发请求获取初始数据)< br > ③ 在组件离开页面节点树后,detached生命周期函数会被触发 ● 退出一个页面时,会触发页面内每个自定义组件的detached生命周期函数 ● 此时适合做一些清理性质的工作 |
九、所属页面的生命周期函数
1.什么是组件所在页面的生命周期
有时,自定义组件的行为依赖于页面状态的变化,此时就需要用到组件所在页面的生命周期。
1 2 3 4 5 6 7 8 9 10 11 | // components/rgbView/rgbView.js Component({ pageLifetimes: { // 所引用的页面被展示时执行 show() {}, // 所引用的页面被隐藏时执行 hide() {}, // 所引用的页面被尺寸变化时执行, 可以获取size大小 resize(size) {}, } }) |
演示案例,在颜色组件中编写一个随机颜色生成的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /** * 组件的方法列表 */ methods: { /** * 生成随机色彩 */ _randomColor() { this .setData({ _rgb: { r: Math.floor(Math.random() * 256), g: Math.floor(Math.random() * 256), b: Math.floor(Math.random() * 256) } }) }, } |
在页面渲染展示的周期时刻调用:
1 2 3 4 5 6 7 | pageLifetimes: { // 所引用的页面被展示时执行 show() { // 在引用页面展示时触发 this ._randomColor() } } |
十、Slot 组件插槽
单个插槽
编写一个组件
1 2 3 4 5 6 7 | <!--components/test4/test4.wxml--> < text >components/test4/test4.wxml</ text > < view > < view >这是组件的内部结构</ view > < slot ></ slot > </ view > |
使用组件:
1 2 3 | < test4 > < text >这是嵌入组件插槽的部分</ text > </ test4 > |
多个插槽
1 2 3 4 5 6 7 | < view > < view >这是组件的内部结构1</ view > < slot name="before"></ slot > < view >这是组件的内部结构2</ view > < slot name="after"></ slot > < view >这是组件的内部结构3</ view > </ view > |
微信新版本需要追加JS配置项:
黑马教程演示没有,说明在老版本可以直接配置
1 2 3 4 5 6 7 | // components/test4/test4.js Component({ options: { // 开启多插槽支持 multipleSlots: true , } } |
使用时需要指明名称:
1 2 3 4 | < test4 > < text slot="before">这是嵌入组件插槽的部分1</ text > < text slot="after">这是嵌入组件插槽的部分2</ text > </ test4 > |
十一、组件之间通信问题
1.父子组件之间通信的3种方式
1 2 3 4 5 6 7 8 9 | ①属性绑定 ●用于父组件向子组件的指定属 性设置数据,仅能设置JSON兼容的数据 ②事件绑定 ● 用于子组件向父组件传递数据,可以传递任意数据 ③获取组件实例 ● 父组件 还可以通过 this .selectComponent()获取子组件实例对象 ● 这样就可以直 接访问子组件的任意数据和方法 |
一、父组件(页面) 向 子组件传递数据:
1 2 | < father counter="{{val1}}" /> < view > father组件 counter值: {{val1}}</ view > |
Father组件接参:
1 2 3 4 5 6 7 8 9 10 11 | // components/father/father.js Component({ /** * 组件的属性列表 */ properties: { counter: { type: Number } } }) |
二、子组件向父组件传递数据
3.事件绑定
事件绑定用于实现子向父传值,可以传递任何类型的数据。使用步骤如下:
1 2 3 4 5 6 7 | ① 在父组件的js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件 ② 在父组件的wxml中,通过自定义事件的形式,将步骤1中定义的函数引用,传递给子组件 ③ 在子组件的js中,通过调用this.triggerEvent(自定义事件名称',{/*参数对象*/ }) ,将数据发送到父组件 ④ 在父组件的js中,通过e.detail获取到子组件传递过来的数据 |
1、Father组件先追加事件和展示
1 2 3 4 5 | <!--components/father/father.wxml--> < text >components/father/father.wxml</ text > < view >展示Father组件 counter值:{{counter}}</ view > < button bindtap="addCounter">+1</ button > |
JS代码,使用事件触发器配置事件和传递值:
1 2 3 4 5 6 7 8 9 10 | /** * 组件的方法列表 */ methods: { addCounter() { this .setData({ counter: this .properties.counter + 1}) // 给父组件进行同步 this .triggerEvent( 'sync' , { value: this .properties.counter}) } } |
页面使用组件时,绑定对应的接收方法:
1 2 | < father counter="{{val1}}" bind:sync="syncCounter" /> < view > father组件 counter值: {{val1}}</ view > |
方法编写:
1 2 3 4 | syncCounter(event) { // 接收从子组件发送过来的参数 this .setData({ val1: event.detail.value }) }, |
三、直接获取组件实例实现调用
可在父组件里调用this.selectComponent("id或class选择器"),获取子组件的实例对象,
从而直接访问子组件的任意数据和方法。
调用时需要传入一-个选择器,例如this.selectComponent(".my-component")。
1 2 3 4 5 6 7 | < father counter="{{val1}}" bind:sync="syncCounter" class="cf" id="componentFather" /> < view > father组件 counter值: {{val1}}</ view > < button bindtap="getComponentFather"> 测试</ button > |
JS代码:
现版本拿不到组件的方法,data属性可以获取
1 2 3 4 5 6 7 8 9 10 11 12 | /** * 直接获取组件实例 */ getComponentFather() { // 或者id选择器 this.selectComponent('#componentFather') // 或者类选择器 this.selectComponent('.cf') const father = this .selectComponent( '.cf' ) console.log(father) console.log(father.data.counter) // 拿不到组件方法? 清空缓存,刷新页面再尝试 father.addCounter() }, |
十二、behaviors
1.什么是behaviors
behaviors是小程序中,用于实现组件间代码共享的特性,类似于Vue.js中的"mixins"
2. behaviors的工作方式
每个behavior可以包含一组属性、 数据、生命周期函数和方法。
组件引用它时,它的属性、数据和方法会被合并到组件中。
每个组件可以引用多个behavior, behavior 也可以引用其它behavior。
3.创建behavior
调用Behavior(Object object)方法即可创建一一个共享 的behavior实例对象,供所有的组件使用:
1 2 3 4 5 6 7 8 9 10 11 | // /behaviors/bhvirs1.js module.exports = Behavior({ // 属性 properties: {}, // 数据 data: { msg: 'Hello Behaviors!' }, // 方法 methods: { } }) |
4.导入并使用behavior
在组件中,使用require()方法导入需要的behavior,
挂载后即可访问behavior中的数据或方法,
示例代码如下:
1 2 3 4 5 6 | // components/father/father.js const b1 = require( '../../behaviors/bhvirs1' ) Component({ behaviors: [b1], }) |
组件可以展示Behaviors中的值
1 | < view >展示Behvior数据 {{msg}}</ view > |
对应的所有设置属性:
冲突问题,见官方文档描述
1 | https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2021-05-04 【DataBase】SQL45 Training 45题训练
2020-05-04 【Spring】04 注解实现自动装配
2020-05-04 【Spring】03 XML配置
2020-05-04 【Spring】02 过程分析
2020-05-04 【Spring】01 快速入门
2020-05-04 【Mybatis】11 注解的使用
2020-05-04 【Mybatis】10 实现分页 & 分页插件