IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 微信小程序第四天 -> 正文阅读

[移动开发]微信小程序第四天

自定义组件

自定义组件

组件的创建与引用

  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>

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>
// 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
      })
    }
  }
})

案例

在这里插入图片描述

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>

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}`
      })
    }
  }
})

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;
}

纯数据字段

纯数据字段

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

// 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}`
      })
    }
  }
})

组件的生命周期

生命周期

  lifetimes: {
    created() {
      console.log('created')
    },
    attached() {
      console.log('attached')
    }
  }

组件所在页面的生命周期

pageLifetimes: {
    show: function() {
      // 页面被展示
      console.log('show')
    },
    hide: function() {
      // 页面被隐藏
      console.log('hide')
    },
    resize: function(size) {
      // 页面尺寸变化
    }
  }

生成随机的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()
    }
  }

插槽

插槽

组件通信

父子组件之间的通信

有3种方式:

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

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

//父组件的data节点
data: {
	count: 0
}

//父组件的wxml结构
<my-test3 count="{{count}}"></my-test3>
<view></view>
<view>父组件中,count值为:{{count}} </span>

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

//子组件的properties节点
properties: {
	count: Number
}

//子组件的wxml结构
<text>子组件中,count值为:{{count}}</text>

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

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

步骤1

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

步骤2

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

步骤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})
}

步骤4

syncCount(e) {
	this.setData({
		count: e.detail.value
	})
}

获取组件实例
可以在父组件里调用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方法

behaviors

behaviors

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

// my-component.js
var myBehavior = require('../../behaviors/my-behavior')
Component({
  behaviors: [myBehavior],
  })

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

组件和它引用的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;
}

API Promise化

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

wx.request({
  url: 'example.php', //仅为示例,并非真实的接口地址
  data: {
    x: '',
    y: ''
  },
  header: {
    'content-type': 'application/json' // 默认值
  },
  success (res) {
    console.log(res.data)
  }
})

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

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)

调用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)
}

全局数据共享

全局数据共享(又叫做:状态管理)是为了解决组件之间数据共享的问题
开发中常用的全局共享方案有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 {action, observable} from 'mobx-miniprogram'
  
export const store = observable({
  num1: 1,
  num2: 2,
  // 计算属性
  get sum() {
    return this.num1 + this.num2
  },
  // actions 方法, 用来修改store中的数据
  updateNum1: action(function(step) {
    this.num1 += step
  }),
  updateNum2: action(function(step) {
    this.num2 += step
  })
})

将Store中的成员绑定到页面中

// 页面的.js文件
import {createStoreBindings} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'

Page({
	onLoad: function () { //生命周期函数-监听页面加载
		this.storeBindings = createStoreBindings(this, {
			store,
			fields: ['num1','num2','sum'],
			actions: ['updateNum1']
		})
	},
	onUnload: function() { //生命周期函数-监听页面卸载
		this.storeBindings.destoryStoreBindings()
	} 
}

在页面上使用Stroe的成员

<!--pages/message/message.wxml-->
<view>{{num1}} + {{num2}} = {{sum}}</view>
<van-button type="primary" bindtap="btnHandler1" data-step="{{1}}">num1 + 1</van-button>

<van-button type="primary" bindtap="btnHandler1" data-step="{{-1}}">num1 - 1</van-button>



 btnHandler1(e) {
    this.updateNum1(e.target.dataset.step)
  },

将Store中的成员绑定到组件中

import {storeBindingsBehavior} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'

Component({
	behaviors: [storeBindingsBehavior], // 通过storeBindingsBehavior来实现自动绑定
	storeBindings: {
		store, // 指定要绑定的Store
		fields: { //指定要绑定的字段数据
			num1: () => store.num1,
			num2: (store) => store.num2,
			sum: 'sum'
		},
		actions: { //指定要绑定的方法
			updateNum2: 'updateNum2'
		}
	},

})

在组件中使用Store中的成员

<!--components/test/test.wxml-->
<view>{{num1}} + {{num2}} = {{sum}}</view>
<van-button type="danger" bindtap="btnHandler2" data-step="{{1}}">num2+1</van-button>

<van-button type="primary" bindtap="btnHandler2" data-step="{{-1}}">num2-1</van-button>


methods: {
    btnHandler2(e) {
      this.updateNum2(e.target.dataset.step)
    }
  }

分包

分包的好处:

  1. 可以优化小程序首次启动的下载时间
  2. 在多团队共同开发时可以更好的解耦协作

分包的加载规则

  1. 在小程序启动时,默认会下载主包并启动主包内页面
    tabBar页面需要放到主包中
  2. 当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示
    非tabBar页面可以按照功能的不同,划分为不同的分包之后,进行按需下载

使用分包

独立分包
独立分包不依赖主包即可运行

分包预下载

案例-自定义tabBar

tabBar

扩展能力

custom-tab-bar
index.wxml

<van-tabbar active="{{ active }}" bind:change="onChange" active-color="#13A7A0">
  <van-tabbar-item wx:for="{{list}}" wx:key="index" info="{{item.info ? item.info : '' }}">
    <image
      slot="icon"
      src="{{item.iconPath}}"
      mode="aspectFit"
      style="width: 30px; height: 18px;"
      
    />
    <image
      slot="icon-active"
      src="{{item.selectedIconPath}}"
      mode="aspectFit"
      style="width: 30px; height: 18px;"
    />
    {{item.text}}
  </van-tabbar-item>
</van-tabbar>

index.wxss

/* custom-tab-bar/index.wxss */
.van-tabbar-item {
  --tabbar-item-margin-bottom: 0;
}

index.js

// custom-tab-bar/index.js
import {storeBindingsBehavior} from 'mobx-miniprogram-bindings'
import {store} from '../store/store'
Component({
  options: {
    styleIsolation: 'shared',
  },
  behaviors: [storeBindingsBehavior], // 通过storeBindingsBehavior来实现自动绑定
	storeBindings: {
		store, // 指定要绑定的Store
		fields: { //指定要绑定的字段数据
      sum: 'sum',
      active: 'activeTabBarIndex'
		},
		actions: { //指定要绑定的方法
			updateActive: 'updateActiveTabBarIndex'
		}
  },

  observers: {
    'sum': function(val) {
      this.setData({
        "list[1].info" : val
      })
    }
  },
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {
    "list": [
      {
        "pagePath": "/pages/home/home",
        "text": "首页",
        "iconPath": "/images/tabs/home.png",
        "selectedIconPath": "/images/tabs/home-active.png"
      },
      {
        "pagePath": "/pages/message/message",
        "text": "消息",
        "iconPath": "/images/tabs/message.png",
        "selectedIconPath": "/images/tabs/message-active.png",
        "info": 0
      },
      {
        "pagePath": "/pages/contact/contact",
        "text": "联系我们",
        "iconPath": "/images/tabs/contact.png",
        "selectedIconPath": "/images/tabs/contact-active.png"
      }
    ]
  },

  /**
   * 组件的方法列表
   */
  methods: {
    onChange(event) {
      // event.detail 的值为当前选中项的索引
      // this.setData({ active: event.detail });
      this.updateActive(event.detail)
      wx.switchTab({
        url: this.data.list[event.detail].pagePath,
      })
    }
  }
})

store.js

// 在这个JS 文件中,专门来创建Store的实例对象
import {action, observable} from 'mobx-miniprogram'
  
export const store = observable({
  num1: 1,
  num2: 2,
  activeTabBarIndex: 0,
  // 计算属性
  get sum() {
    return this.num1 + this.num2
  },
  // actions 方法, 用来修改store中的数据
  updateNum1: action(function(step) {
    this.num1 += step
  }),
  updateNum2: action(function(step) {
    this.num2 += step
  }),
  updateActiveTabBarIndex: action(function(index) {
    this.activeTabBarIndex = index
  })
})

总结

在这里插入图片描述

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-06-29 19:12:58  更:2022-06-29 19:14:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/24 21:40:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码