• 微信小程序第四天


    自定义组件

    自定义组件

    组件的创建与引用

    1. 在项目的根目录中,鼠标右键,创建components->test文件夹
    2. 在新建的components->test文件夹上,鼠标右键,点击“新建Component”
    3. 键入组件的名称之后回车,会自动生成组件对应的4个文件,后缀名分别为.js,.json,.wxml和.wxss

    引用组件
    局部引用:页面的.josn文件中
    "usingComponents": { "my-test1": "/components/test/test"}

    全局引用: app.json中配置

    全局引用vs局部引用:
    如果某个组件在多个页面当中都用到了,就全局引用
    如果只在特定的页面中才使用,就局部引用

    组件和页面之间的区别

    组件和页面的.js与.json文件有明显的不同

    1. 组件的.json文件中需要声明“component”: true属性
    2. 组件的.js文件中调用的是Component()函数
    3. 组件的事件处理函数需要定义到methods节点中

    样式

    组件样式

    组件样式隔离的注意点:
    app.wxss全局样式里面的样式,对组件是无效
    只有class选择器会有样式隔离效果,id选择器、属性选择器、标签选择器不受样式隔离的影响。

    修改组件的样式隔离选项

    有时候 我们希望在外界能够控制组件内部的样式,此时可以通过stylelsolation修改组件的样式隔离选项,用法如下:
    { "styleIsolation": "isolated" }

    Component 构造器

    properties属性
    在小程序组件中,properties是组件的对外属性,用来接收外界传递到组件当中的数据,
    实例代码如下:

    Component({
    	// 属性定义
    	properties: {
    		max: {   // 完整定义属性的方式
    			type: Number, // 属性值的数据类型
    			value: 10  // 属性默认值
    		},
    		max: Number  //简化定义属性方式
    	}
    
    })
    
    <my-test1 max="20"> <my-test1>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    data和properties的区别

    在小程序里面,两者都是可读可写的
    data更倾向于存储组件的私有数据
    properties更倾向于存储外界传递到组件中的数据
    由于data数据和properties属性在本质上没有任何区别,因此properties属性也可以用于页面渲染,或使用setData为properties中的属性重新赋值。

    数据监听器

    数据监听器

    在这里插入图片描述

    组件的.wxml

    <!--components/test/test.wxml-->
    <view>{{n1}} + {{n2}} = {{sum}}</view>
    <button size="mini" bindtap="addN1" type="primary">n1自增</button>
    <button size="mini" bindtap="addN2">n2自增</button>
    
    • 1
    • 2
    • 3
    • 4
    // components/test/test.js
    Component({
      /**
       * 组件的属性列表
       */
      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
          })
        }
      },
      observers: {
        'n1, n2': function(n1, n2) {
          this.setData({
            sum: n1 + n2
          })
        }
      }
    })
    
    
    • 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

    案例

    在这里插入图片描述

    app.json
    "usingComponents": { "my-test2": "/components/test2/test2" }

    test2.wxml

    <!--components/test2/test2.wxml-->
    <text>components/test2/test2.wxml</text>
    <view class="rgb" style="background-color: rgb({{ fullColor}});">
      <text>颜色值:{{fullColor}}</text>
    </view>
    <button size="mini" type="default" bindtap="changeR">R</button>
    <button size="mini" type="primary" bindtap="changeG">G</button>
    <button size="mini" type="warn" bindtap="changeB">B</button>
    
    <view>{{rgb.r}},{{rgb.g}},{{rgb.b}}</view>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    test2.js

    // components/test2/test2.js
    Component({
      /**
       * 组件的属性列表
       */
      properties: {
    
      },
    
      /**
       * 组件的初始数据
       */
      data: {
        rgb: {
          r: 0,
          g: 0,
          b: 0,
        }, 
        fullColor: '0, 0, 0' //根据rgb对象的三个属性,动态计算fullColor的值
      },
    
      /**
       * 组件的方法列表
       */
      methods: {
        changeR() {
          this.setData({
            'rgb.r': this.data.rgb.r + 5 > 255 ? 255 : this.data.rgb.r + 5
          })
        },
        changeG() {
          this.setData({
            'rgb.g': this.data.rgb.g + 5 > 255 ? 255 : this.data.rgb.g + 5
          })
        },
        changeB() {
          this.setData({
            'rgb.b': this.data.rgb.b + 5 > 255 ? 255 : this.data.rgb.b + 5
          })
        },
      },
      observers: {
        // 'rgb.r, rgb.g, rgb.b': function(r, g, b) {
        //   this.setData({
        //     fullColor: `${r}, ${g}, ${b}`
        //   })
        // }
        'rgb.**': function(obj) {
          this.setData({
            fullColor: `${obj.r}, ${obj.g}, ${obj.b}`
          })
        }
      }
    })
    
    
    • 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
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    test2.wxss

    /* components/test2/test2.wxss */
    .rgb {
      height: 300rpx;
      line-height: 300rpx;
      font-size: 36rpx;
      color: white;
      text-shadow: 0rpx 0rpx 2rpx black;
      text-align: center;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    纯数据字段

    纯数据字段

    只在业务逻辑中使用,页面渲染中不使用
    好处:可以提升页面更新的性能
    改造上面 的案例

    // components/test2/test2.js
    Component({
      options: {
        pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
      },
      /**
       * 组件的初始数据
       */
      data: {
        _rgb: {
          r: 0,
          g: 0,
          b: 0,
        }, 
        fullColor: '0, 0, 0' //根据rgb对象的三个属性,动态计算fullColor的值
      },
    
      /**
       * 组件的方法列表
       */
      methods: {
        changeR() {
          this.setData({
            '_rgb.r': this.data._rgb.r + 5 > 255 ? 255 : this.data._rgb.r + 5
          })
        },
        changeG() {
          this.setData({
            '_rgb.g': this.data._rgb.g + 5 > 255 ? 255 : this.data._rgb.g + 5
          })
        },
        changeB() {
          this.setData({
            '_rgb.b': this.data._rgb.b + 5 > 255 ? 255 : this.data._rgb.b + 5
          })
        },
      },
      observers: {
        // '_rgb.r, _rgb.g, _rgb.b': function(r, g, b) {
        //   this.setData({
        //     fullColor: `${r}, ${g}, ${b}`
        //   })
        // }
        '_rgb.**': function(obj) {
          this.setData({
            fullColor: `${obj.r}, ${obj.g}, ${obj.b}`
          })
        }
      }
    })
    
    
    • 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
    • 50
    • 51

    组件的生命周期

    生命周期

      lifetimes: {
        created() {
          console.log('created')
        },
        attached() {
          console.log('attached')
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    组件所在页面的生命周期

    pageLifetimes: {
        show: function() {
          // 页面被展示
          console.log('show')
        },
        hide: function() {
          // 页面被隐藏
          console.log('hide')
        },
        resize: function(size) {
          // 页面尺寸变化
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    生成随机的RGB颜色值

      methods: {
        // 生成随机RGB颜色的方法,非事件处理函数建议以_开头
        _randomColor() {
          this.setData({
            _rgb: {
              r: Math.floor(Math.random() * 256),
              g: Math.floor(Math.random() * 256),
              b: Math.floor(Math.random() * 256)
            }
          })
        },
    },
    pageLifetimes: {
        show: function() {
          // 页面被展示
          // console.log('show')
          this._randomColor()
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    插槽

    插槽

    组件通信

    父子组件之间的通信

    有3种方式:

    1. 属性绑定
      用于父组件向子组件的指定属性设置数据,仅能设置JSON兼容的数据
    2. 事件绑定
      用于子组件向父组件传递数据,可以传递任意数据
    3. 获取组件实例
      父组件还可以通过this.selectComponent()获取子组件实例对象
      这样就可以直接访问子组件的任意数据和方法

    属性绑定
    属性绑定用于实现父向子传值,而且只能传递普通类型的数据,无法将方法传递给子组件。父组件的示例代码如下:

    //父组件的data节点
    data: {
    	count: 0
    }
    
    //父组件的wxml结构
    <my-test3 count="{{count}}"></my-test3>
    <view></view>
    <view>父组件中,count值为:{{count}} </span>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    子组件在properties节点种声明对应的属性并使用。示例代码如下:

    //子组件的properties节点
    properties: {
    	count: Number
    }
    
    //子组件的wxml结构
    <text>子组件中,count值为:{{count}}</text>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    事件绑定
    事件绑定用于实现子向父传值,可以传递任何类型的值。
    使用步骤如下:

    1. 父组件的js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
    2. 父组件的wxml中,通过自定义事件的形式,将步骤一中定义的函数引用,传递给子组件
    3. 子组件的js中,通过调用this.triggerEvent('自定义事件名称', {/* 参数对象*/}),将数据发送到子组件
    4. 父组件的js中,通过e.detail获取到子组件传递过来的数据

    步骤1

    // 在父组件中定义syncCount方法
    // 将来,这个方法会被传递给子组件,供子组件进行调用
    syncCount() {
    	console.log('syncCouont')
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    步骤2

    <!-- 使用bind:自定义事件名称 (推荐 结构清晰) -->
    <my-test3 count="{{count}}" bind:sync="syncCouont"></my-test3>
    <!-- 或在bind后面直接写上自定义事件名称 -->
    <my-test3 count="{{count}}" bindsync="syncCount"></my-test3>
    
    • 1
    • 2
    • 3
    • 4

    步骤3

    // 子组件的wxml结构
    <text> 子组件中,count的值为: {{count}} </text>
    <button type="primary" bindtap="addCount"> + 1 </button>
    
    // 子组件的js代码
    methods: {
    	addCount() {
    		this.setData({
    			count: this.properties.count + 1
    		})
    	}
    	//触发自定义事件 将数值同步给父组件
    	this.triggerEvent('sync', {value: this.properties.count})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    步骤4

    syncCount(e) {
    	this.setData({
    		count: e.detail.value
    	})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    获取组件实例
    可以在父组件里调用this.selectComponent("id或者class选择器"),获取子组件实例对象,从而直接访问子组件的任意数据和方法。
    调用时需要传入一个选择器,例如this.selectComponent(".my-component")

    // wxml结构
    <my-test3 count="{{count}}" bind:sync="syncCount" class="customA" id="cA"> </my-test3>
    
    <button bindtap="getChild"> 获取子组件实例</button>
    
    getChild() { //按钮的tap事件处理函数
     const child = this.selectComponent('.customA)
     child.setData({count: child.properties.count+1}) //调用子组件的setData方法
     child.addCount() //调用子组件的addCount方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    behaviors

    behaviors

    创建behaviors
    根目录下创建behaviors/my-behaviors.js
    导入并使用behaviors

    // my-component.js
    var myBehavior = require('../../behaviors/my-behavior')
    Component({
      behaviors: [myBehavior],
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    同名字段的覆盖和组合规则*

    组件和它引用的behaviors中可以包含同名的字段,此时可以参考如下3种同名时的处理规则

    1. 同名的数据字段(data)
    2. 同名的属性(properties)或方法(methods)
    3. 同名的生命周期函数

    总结

    在这里插入图片描述

    使用npm包

    目前,小程序中已经支持使用npm安装第三方包,从而来提高小程序的开发效率。但是,在小程序中使用npm包有如下3个限制:

    1. 不支持依赖于node.js内置库的包
    2. 不支持依赖于浏览器内置对象的包
    3. 不支持依赖于C++插件的包

    Vant Weapp

    Vant Weapp是有赞前端团队开源的一套小程序UI组件库,助力开发者快速搭建小程序应用。它所使用的是MIT开源许可协议。类似于Vue中使用的elementUI
    官方文档

    安装Vant组件库

    快速上手

    在这里插入图片描述

    npm init -y生成package.json文件
    npm i @vant/weapp@1.10.3 -S --production

    定制全局主题样式

    Vant Weapp使用CSS变量来实现定制主题

    app.wxss中,写入css变量,即可对全局生效

    page{
    	/* 定制警告按钮的背景颜色和边框颜色 */
    	--button-danger-background-color: #C00000;
    	--button-danger-border-color: #D60000;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    API Promise化

    默认情况下,小程序官方提供的异步API都是基于回调函数实现的,例如,网络请求的API需要按照如下的方式调用:

    wx.request({
      url: 'example.php', //仅为示例,并非真实的接口地址
      data: {
        x: '',
        y: ''
      },
      header: {
        'content-type': 'application/json' // 默认值
      },
      success (res) {
        console.log(res.data)
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    缺点:容易造成回调地狱的问题,代码的可读性、维护性差。

    API Promise化,指的是通过额外的配置,将官方提供的、基于回调函数的异步API,升级改造为基于Promise的异步API,从而提高代码的可读性、维护性,避免回调地狱的问题。

    在小程序中,实现API Promise化主要依赖于miniprogram-api-promise这个第三方的npm包。
    它的安装和使用步骤如下:
    npm install --save miniprogram-api-promise@1.0.4
    安装后再次通过工具-构建npm

    // 在小程序入口文件app.js中,只需调用一次promisifyAll()方法
    // 即可实现异步API的Promise化
    import {promisifyAll} from 'miniprogram-api-promise'
    
    const wxp = wx.p = {}
    promisifyAll(wx, wxp)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    调用promise化之后的异步API

    // 页面的wxml结构
    <van-button type="danger" bindtap="getInfo"> vant按钮 </van-button>
    
    // 页面的js文件中,定义对应的tap事件处理函数
    async getInfo() {
    	const { data: res } = await wx.p.request({
    		method: 'GET',
    		url: 'https://www.escook.cn/api/get',
    		data: {name: 'zs', age: 20}
    	})
    	console.log(res)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    全局数据共享

    全局数据共享(又叫做:状态管理)是为了解决组件之间数据共享的问题
    开发中常用的全局共享方案有Vuex、Redux、MobX等
    在小程序中,可使用mobx-miniprogram配合mobx-miniprogram-bindings实现全局数据共享。
    其中:
    mobx-miniprogram用来创建Store实例对象
    mobx-miniprogram-bindings用来把Store中的共享数据或方法,绑定到组件或页面中使用。

    MobX

    安装MobX相关的包
    npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
    安装后记得重新构建npm

    创建MobX的Store实例

    根目录下创建store文件夹
    store/store.js

    // 在这个JS 文件中,专门来创建Store的实例对象
    import {observable} from 'mobx-miniprogram'
      
    export const store = observable({
      num1: 1,
      num2: 2
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    分包

    案例-自定义tabBar

  • 相关阅读:
    43、Flink 自定义窗口触发器代码示例
    环境数据监测在环保物联网有什么价值?
    赚钱=玩养成类游戏,用玩家思维轻松搞副业
    常用linux解压命令
    UrlBasedCorsConfigurationSource无法转换为CorsConfigurationSource的原因
    本人碰到的RN项目的坑
    基于SSM的图书商城网站设计与实现
    PHP对接钉钉群机器人
    MySQL-----多表查询(一)
    python opencv
  • 原文地址:https://blog.csdn.net/weixin_45732235/article/details/125485763