微信小程序自定义组件
好吧,突然发现学不完了,一下子,那就分开吧,由于时间太久,直接重新大致复习了一下
微信小程序自定义组件
微信小程序支持自定义组件
下方的目录
其中,components为组件目录,nodemodules为模块目录,pages为小程序的页面目录,utils为一些基础功能的封装。好比安装的第三方百度统计功能在此。
总说
创建一个组件
一个组件包括json,wxml,wxss,js四个文件组成。
wxml文件如下
<view class="inner">
{{innerText}}
</view>
<slot></slot>
编写js文件
// components/component.js
Component({
/**
* 组件的属性列表
*/
properties: {
innerText: {
type: String,
value: 'hello world'
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
完成对组件的初始化,包括设置属性列表,初始化数据,以及设置相关的方法。
使用自定义组件
需要在json文件中声明。
{
"usingComponents": {
"component": "/components/component"
}
}
在page目录下设置组件的声明,
<view><component></component></view>
好啦,上方的是一个最简单的自定义组件
组件模板和样式
组件模板
组件模板中有一个
<slot>
用于承载组件引用的时候提供的子节点。
ps 在page中引用的组件,必须在json文件中进行声明。否则为无效节点
在wxml文件中
<view>
<component>
<text>这是文字</text>
</component>
</view>
而模板文件如下
<view class="inner">
{{innerText}}
</view>
<slot></slot>
这样在page中的text节点会加载在slot节点的位置中。
使用多个slot
如果要使用多个slot需要在js文件中声明
options: {
multipleSlots: true // 允许组件中使用多个slot
}
然后在组件的wxml文件中设置slot的内容
<view class="inner">
<slot name="before"></slot>
{{innerText}}
<text>这是组件的内部内容</text>
<slot name="after"></slot>
</view>
使用slot的name属性确定组件的内容
在page页面中,使用该组件
<view>
<component>
<text slot="before">这是文字</text>
<text slot="after">hello world</text>
</component>
</view>
组件样式
对于组件样式来说,使用
:host
来指定组件的默认样式。
即可指定默认样式
外部样式类
使用外部传入的属性,在component中使用,即使用page中的wxss。
直接在component构造函数中externalClasses属性中,使用数组。
在同一个节点上使用普通样式和外部样式,两个权重是相同的,会造成不可思议的bug产生。
在组件中,使用components构造函数的externalClasses属性确定外部样式表的名称
externalClasses: ['my-class']
然后在组件的wxml文件中,使用该外部样式表
<view class="my-class">
<slot name="before"></slot>
{{innerText}}
<text>这是组件的内部内容</text>
<slot name="after"></slot>
</view>
然后,在page中使用
<view>
<component class="my-class">
<text slot="before">这是文字</text>
<text slot="after">hello world</text>
</component>
</view>
是滴,直接使用page中的样式表,page中的样式表
.my-class {
color:yellow
}
全局样式表
使用全局样式表设置js文件中的options对象中的addGlobalClass属性为true可以使用全局样式表
component构造器
使用component构造器,进行构造。
该构造函数用于定义组件。调用Component函数能指定组件的数据,属性和方法。
这个和视图层的page构造函数很类似。
在properties定义段中,属性名采用驼峰命名法,wxml采用连字符的命名,之间相互转换。
tips 在网页中,也有这一点。
定义组件的js
Component({
behaviors: [], // 进行代码复用机制
properties: {
myProperty: { // 属性名
type: String, // 属性的类型(必填)
value: '', // 属性的初值
observer: (newValue, oldValue, changedPath) => {
console.log(newValue);
console.log(oldValue)
}
},
myProperty2: String // 一种简化的定义方式
},
data: {}, // 私有数据,用于模板渲染
lifetimes: {
// 组件的生命周期函数,用于声明组件的生命周期
attached: () => {},
moved: () => {},
detached: () => {}
},
pageLifetimes: {
// 组件所在页面的生命周期函数
show: () => {},
hide: () => {}
},
methods: {
// 组件的方法,其中下划线开头为私有方法
onMyButtonTap: function() {
this.setData({
myProperty: "hello world"
})
},
// 内部方法,使用下划线开头
_myPrivateMethod: function() {
this.setData({
'A[0].B': 'myPrivateData'
})
}
}
})
定义组件的wxml
<custom-component>
<view>{{myProperty}}</view>
<button bindtap='onMyButtonTap'>Button</button>
<view>{{A[0].B}}</view>
<button bindtap='_myPrivateMethod'>_myPrivateMethod</button>
</custom-component>
然后在page中使用该组件
在这之前json中设置该组件
<my-component />
接着运行如下
使用Component构造函数构造页面
小程序的页面可以视为自定义组件,因此,页面同样可以使用Component构造函数构造,此时要求对应的json文件拥有usingComponents定义段
此时组件的属性可以用于接收页面的参数,
在app.json文件中添加一个页面,并在导航栏设置该页面
{
"pages":[
"pages/helloWorld/hello",
"pages/index/index",
"pages/logs/logs",
"components/component"
],
"window":{
"backgroundTextStyle":"dark",
"navigationBarBackgroundColor": "#c7dbc8",
"navigationBarTitleText": "小小",
"navigationBarTextStyle":"whiter",
"enablePullDownRefresh": true,
"backgroundColor": "#fceaea"
},
"tabBar": {
"list": [{
"text": "ming",
"pagePath": "pages/logs/logs"
}, {
"text":"home",
"pagePath": "pages/index/index"
}, {
"text": "hello",
"pagePath": "pages/helloWorld/hello"
}, {
"text": "ing",
"pagePath": "components/component"
}],
"color": "#f8fcea",
"backgroundColor": "#ff9999",
"selectedColor": "#c5ff99",
"borderStyle": "white",
"position": "top"
},
"functionalPages": true
}
添加的参数为pages参数,以及tabBar参数
并设置编译模式,设置页面的启动参数
组件的js文件如下
// components/component.js
Component({
/**
* 组件配置
**/
options: {
multipleSlots: true // 允许组件中使用多个slot
},
/**
* 组件的属性列表
*/
properties: {
innerText: {
type: String,
value: 'hello world'
},
paramA: Number,
paramB: Number,
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
onLoad: function() {
console.log(this.data.paramA);
console.log(this.data.paramB);
}
},
/**
* 使用外部样式表
**/
externalClasses: ['my-class']
})
添加了一个properties,并添加一个methods事件,在页面加载的时候,触发该事件。
启动编译,控制台输出当前页面参数,参数获取完成。
组件间通信和事件
通信的几种方法
WXML数据绑定,用于父组件,向子组件指定的属性设置数据。此方法仅仅能设置JSON数据。
事件,用于子组件向父组件传递数据,可以传递任意数据。
监听事件
用于监听子组件,如果子组件被触发,则父组件将会触发该事件。
<view>
<component class="my-class" bindmyevent="onMyEvent">
<text slot="before">这是文字</text>
<text slot="after">hello world</text>
</component>
</view>
当子组件触发了myevent事件时候,将会调用onMyEvent方法。
onMyEvent: function(e) {
console.log(e.detail); // 自定义组件触发的时候。提供的detail事件。将会返回当前点击的鼠标坐标
}
触发事件
使用triggerEvent方法,完成对父组件事件的触发
wxml中添加
<button bindtap="onTap">点击按钮</button>
然后在js中添加
onTap: function() {
var myEventDetail = {}; // 提供给事件的监听函数
var myEventOption = {}; // 触发事件的选项
this.triggerEvent('myevent', myEventDetail, myEventOption)
},
确保该组件将会有myevent供父组件进行触发
类似于网页中的自定义组件
完成绑定以后,由于上一节,父组件以及完成事件的监听,此时点击组件内的按钮,将会完成父组件绑定的事件的触发
由于冒泡和传播的存在,父组件依旧可以通过冒泡和传播来进行获取
triggerEvent方法详细解释
有三个参数,第一个参数为暴露给父节点的事件类型。第二个参数为向父组件传递的数据,第三个参数为选项,传入对象进去
向父组件传递数据
组件的js文件中
onTap: function() {
var myEventDetail = {
a:3,
b:4,
c:5
}; // 提供给事件的监听函数
var myEventOption = {}; // 触发事件的选项
this.triggerEvent('myevent', myEventDetail, myEventOption)
},
将对象传入第二个选项中
接收数据,在父组件的e.detail中接收子传给父的内容
完成了数据从子传递到父
上上上节介绍了父传递到子的过程
第三个参数
bubbles
该选型确定的是是否冒泡
由于composed默认为false则该事件只在主树上触发,不会进入任何其他组件的内部。
编写两个嵌套的组件
在components目录下继续新建一个目录为body
原谅自己的命名技术,component命名╮(╯▽╰)╭
配置页面的json文件信息
{
"usingComponents": {
"component": "/components/component",
"body": "/components/body/body"
}
}
接着继续配置
书写页面的wxml文件
<body>
<component/>
</body>
由于是在原有基础上添加,继续书写body组件的内容,确定挂载点
<view>
<slot/>
</view>
编译一个最基本的组件嵌套完成。为body组件,嵌套一个component组件
接着进行事件的绑定
书写内层组件的bubbles,为允许进行冒泡
var myEventOption = {
bubbles: true
}; // 触发事件的选项
即完成允许冒泡。
接着,继续,书写pages的wxml文件,完成事件和节点的绑定
<body bindmyevent="list2">
<component bindmyevent="list1"/>
</body>
接着单击按钮完成事件的触发
至此,完成了事件的冒泡。
componse
确定事件是否进入内部,即,是否触发组件内部
接着,在原来的代码的基础上继续添加内容。
由于内部组件依旧是一个事件类型为myevent
接着,修改内部组件的配置
onTap: function() {
var myEventDetail = {
a:3,
b:4,
c:5
}; // 提供给事件的监听函数
var myEventOption = {
bubbles: true,
composed: true
}; // 触发事件的选项
this.triggerEvent('myevent', myEventDetail, myEventOption)
},
onMyEvent: function(e) {
console.log(e.detail); // 自定义组件触发的时候。提供的detail事件。
}
修改composed的值为true。
绑定body的事件
<view bindmyevent="list3">
<slot/>
</view>
绑定body事件完成以后,接着单击按钮,触发事件
触发过程为1,3,2说明事件是先进入父组件,触发父组件的事件完成以后,在继续触发引用组件的节点树上的事件。
capturePhase
为事件是否有捕获阶段。
由于事件是先冒泡,后捕获,所以必须要先进行冒泡
修改配置如下
var myEventOption = {
bubbles: false,
composed: true,
capturePhase: true
}; // 触发事件的选项
然后触发事件,由于是捕获,将会触发回调myevent的list1的回调函数进行处理。
behaviors
一种代码复用机制
类似于C++的模板 ?? 确定吗? 木有学习过c++,其实我一直在思考css文件如何实现复用。因为我不想写大段代码呀,(@ο@) 哇~
每个behavior都会包含一组属性,数据,生命周期函数和方法。组件引用的时候,上述将会合并
类似于深拷贝,不过js中的深拷贝是直接开辟了一块新的储存空间,浅拷贝属于直接进行引用,js进行赋值操作执行的是浅拷贝
使用Behavior()构造函数,进行构造出代码的复用
文件目录如下
微信的路径太坑了。
模板文件如下
module.exports = Behavior({
behaviors: [],
properties: { // 外部数据
myBehaviorProperty: {
type: String,
value: 'hello world'
}
}
})
属于配置项目,接着继续书写内部组件
// components/component.js
var myBehavior = require('/behaviors/behavior')
Component({
// 代码复用
behaviors: [myBehavior],
/**
* 组件配置
**/
options: {
multipleSlots: false // 允许组件中使用多个slot
},
/**
* 组件的属性列表
*/
properties: {
innerText: {
type: String,
value: 'hello world'
},
paramA: Number,
paramB: Number,
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
onLoad: function() {
console.log(this.data.paramA);
console.log(this.data.paramB);
},
onTap: function() {
var myEventDetail = {
a:3,
b:4,
c:5
}; // 提供给事件的监听函数
var myEventOption = {
bubbles: false,
composed: true,
capturePhase: true
}; // 触发事件的选项
this.triggerEvent('myevent', myEventDetail, myEventOption)
},
onMyEvent: function(e) {
console.log(e.detail); // 自定义组件触发的时候。提供的detail事件。
}
},
/**
* 使用外部样式表
**/
externalClasses: ['my-class']
})
在最上方引入文件,(微信小程序的路径一个大坑),接着在behaviors引入即可。可以behaviors引入behaviors即包的相互依赖。
构建一个复杂的程序很有必要进行分包
内置的behaviors
wx://form-field
使得自定义组件有类似表单控件的功能,将会在页面触发submit事件的时候将会直接附带提交
演示
先创建一个组件
此时目录结构
好吧。是有一点复杂了
添加内置组件,并设置data数据中的value的值
// components/custom-form-field/custom-form-field.js
Component({
/**
* 代码复用 .让其拥有表单属性
**/
behaviors: ['wx://form-field'],
/**
* 组件的属性列表
*/
properties: {
value: {
type: String,
value: "hello world"
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
接着书写page页面中的内容
引入组件
{
"usingComponents": {
"component": "/components/component",
"body": "/components/body/body",
"custom-form-field": "/components/custom-form-field/custom-form-field"
}
}
完后接着继续书写wxml中添加该表单组件,并添加提交按钮
<form bindsubmit="formSubmit">
<custom-form-field name="custom-name">hello world</custom-form-field>
<button form-type="submit">提交</button>
</form>
添加事件的处理程序
formSubmit: function (e) {
console.log('form', e.detail.value)
console.log(333)
}
单击按钮,控制台输出键值对,到此完成。
智能推荐
Linux搭建LAMP,源码安装
Linux搭建LAMP,源码安装 LAMP是Linux Apache MySQL PHP的简写,即把Apache、MySQL以及PHP安装在Linux系统上,组成一个环境来运行PHP的脚本语言,通常是网站。Apache 是最常用的Web服务软件,而MySQL是比较小型的数据库软件,这两个软件以及PHP都可以安装到Windows的机器上。 我们可以把Apache+PHP安装在一台机器上,再把MySQ...
模拟按键 —— 鼠标
背景 之前写自动化脚本的时候总是遇到一些很尴尬的问题: 跑脚本时模拟鼠标按键时,光标是真实的跑到了那个位置的,也就是说跑脚本的时候会很影响电脑的正常使用,导致不得不开一个虚拟机专门跑。 另外因为光标只有一个所以很难实现多线程去同时操作多个窗口,当线程1 模拟鼠标但还没有结束时,线程2 已经开始执行模拟操作,这就导致了线程1 的模拟操作被终止了,被迫之下只能开多个虚拟机(但实在太占用性能🙄) 解决...
Hibernate学习总结(一)
一、Hibernate简介 一个持久层的ORM框架。ORM:Object Relational Mapping(对象关系映射)。指的是将一个Java中的对象与关系型数据库中的表建立一种映射关系,从而操作对象就可以操作数据库中的表。 二、Hibernate入门 1、创建一个项目,引入jar包 hibernate用到的jar包 2、创建表 3、创建实体类 4、创建映射(*****) 映射需要通过XML...
Linux系统NFS
文章目录 1. nfs简介 1.1 nfs特点 1.2 使用nfs的好处 1.3 nfs的体系组成 1.4 nfs的应用场景 2. nfs工作机制 2.1 RPC 2.2 NIS 2.3 nfs工作机制 3. exports文件的格式 4. nfs管理 5. 作业 5.1手动搭建一个nfs服务器 5.1.1开放/nfs/shared目录,供所有用户查阅资料 5.1.2 开放/nfs/upload目...
关于java中String,StringBuffer,StringBuilder的区别以及StringBuffer,StringBuilder的安全性问题
这里的结果就是正确的然后我们来看他的append方法 它在前边加了一个synchronized来修饰,相当于同时只能有一个线程来访问他,这样就不会产生上边的问题但同时他的效率也就比StringBuilder低,...
猜你喜欢
Django连接现有mysql数据库
1、打开cmd后cd到项目位置 2、建立项目 django-admin startproject test2 3、编辑项目中的配置文件, mysite/settings.py ,告诉Django你的数据库连接参数和数据库名。具体的说,要提供 DATABASE_NAME , DATABASE_ENGINE , DATAB...
ShareSDK新浪微博登录时报错error:redirect_uri_mismatch
今天用 ShareSDK 做第三方登录的时候碰到个问题,明明在微博平台的应用审核已经通过了,但是调用登录接口的时候一直报错,错误如下: 出现这个错误是因为在微博开放平台上没有设置回调地址,或者设置的回调地址与本地XML中的地址不一致。 在sharesdk.xml文件当中对于微博的设置: 其中RedirectUrl为设置的回调地址,这里的地址必须要与微博开发平台设置的地址相同,否则就会出现上面的错误...
python解析网络封包方法
2019独角兽企业重金招聘Python工程师标准>>> 在使用Python解析网络数据包时,使用网络字节序解析,参见下表。 C语言的数据类型和Python的数据类型对照表请参见下表。 接下来对封包与解包进行举例说明。 version type id content unsigned short unsigned short unsigned int unsigned int 封包...
python3:时间方法,异常处理,系统文件相关模块(os)
文章目录 时间方法 time模块 时间表示方法: time模块的方法 datetime模块 异常处理 触发异常 创建mydiv.py脚本,要求如下: 创建myerror.py脚本,要求如下: os模块 实现ls -R(os.walk) os.path pickle模块 记账脚本 时间方法 time模块 时间表示方法: 时间戳:自1970-1-1 0:00:00到某一时间点之间的秒数 UTC时间:世...
负载均衡群集——LVS+DR模型
一、实验组成 调度器 192.168.100:41 web1 192.168.100:42 web2 192.168.100.43 NFS共享服务器 192.168.100.44 二、实验拓扑 三、实验配置 3.1在调度器配置:192.168.100.41 配置虚拟IP地址(VIP) 调整/proc响应参数 对于 DR 群集模式来说,由于 LVS 负载调度器和各节点需要共用 VIP 地址,应该关闭...