微信小程序自定义组件(二)

微信小程序自定义组件

ps 由于作业部落貌似出了点问题,耽误了点时间,找了一个stackedit.io准备写。无奈,这是要自己建编辑器的节奏啊。没有一个能靠的注

为何存在组件

组件间的关系

使用relations实现组件的关系,即父子关系。

定义和使用组件间的关系

有时需要使用如下的组件间的关系

 <custom-ul> 
    <custom-li> item1 </ custom-li> 
    <custom-li> item2 </ custom-li> 
</ custom-ul> 

在上方中,
两个<custom-ul>以及<custom-li>两个组件都为自定义组件,如果进行通信会非常的难以操作,至此通过relations完成子父组件的定义,简化通信。
同样的以上方的栗子作为举例。

继续上一个栗子,新建一个页面,在新的页面中使用组件间的关系。

由于同属于一个custom大组件,所以直接在components中新建一个custom文件夹,表示一个大的新组件
由于其拥有一个子组件,所以再新建一个li文件夹,表示custom-li
目录如下

菜鸟一枚,设置的不一定正确。也不一定是最正统的,只是感觉。╮(╯▽╰)╭

设置custom/custom.js文件的relations的值

// components/custom/custom.js
Component({
  relations: {
    './li/li' : {
      type: 'child',  // 设置关联的目标节点为子节点
    }
  }
})

接着设置祖先节点,即设置custom/li/li.js文件的内容

// components/custom/li/li.js
Component({
  relations: {
    '../../custom': {
      type: 'parent'  // 应为祖先节点
    }
  }
})

设置组件的wxml文件

<! - 组件/自定义/立/ li.wxml  - >
< view > components / custom / li / li.wxml </ view > < slot />

<!--components/custom/custom.wxml-->
<view>components/custom/custom.wxml</view>
<slot/>

接着设置page页面的wxml页面

<!--pages/ming/ming.wxml-->
<text>hello world</text>
<custom-ul>
  <custom-li></custom-li>
  <custom-li></custom-li>
  <custom-li></custom-li>
  <custom-li></custom-li>
</custom-ul>

至此完成。

关联一类组件

被微信的路径折腾的不轻,好吧,无奈,决定重新写

微信路径

微信路径太坑了。
理所应当应该是

/ 根目录
../ 父级目录
./ 当前目录

结果非要

../../

至今也没搞清楚路径是这么回事。算了,决定在同一个目录下完成模块的问题,不在另外的分一个模块的文件夹了。

总说

要形成的在page下的结构如下

<custom-form>
	<view>
		input
		<custom-input></custom-input>
	</view>
	<custom-submit>shubmit</custom-submit>
</custom-form>

创建目录

创建目录如下

好啦,目录如上

这一次放弃将模块放在另外一个文件夹,这一场所有的和组件相关的内容都放在同一个文件夹下 。符合组件的精神

其中form表明该为一个form的组件。module表明组件的内容,其中module下还有一个behaviors表明是behaviors的内容的模块,input和submit表明是其子组件。

behaviors

书写behaviors的内容。

// components/form/module/behaviors/controls

module.exports = Behavior({

// ...

})

父组件

书写父组件及form的内容

// components/form/form.js

var formControls = require('./module/behaviors/controls.js')

Component({

relations: {

'formControls': {

type: 'descendant', // 关联目标的节点应为子孙节点

target: formControls // 所有设置behavior的组件的节点都为其子孙节点

}

}

})

继续书写wxml的内容,其实就是添加一个挂载点的问题。

<!--components/form/form.wxml-->

<text>components/form/form.wxml</text>

<slot/>

input组件

// components/form/input/input.js

var formControls = require('../module/behaviors/controls.js')

Component({

behaviors: [formControls],

relations: {

'../form': {

type: 'ancestor', // 关联的目标节点应为祖先节点

}

}

})

wxml

<!--components/form/input/input.wxml-->

<text>components/form/input/input.wxml</text>

<slot/>

submit组件

此为from的子组件

// components/form/submit/submit.js

var formControls = require('../module/behaviors/controls.js')

Component({

behaviors: [formControls],

relations: {

'../form': {

type: 'ancestor', // 关联的目标节点应为祖先节点s

}

}

})

继续写wxml加上一个

<!--components/form/submit/submit.wxml-->

<text>components/form/submit/submit.wxml</text>

<label><slot/></label>

json配置文件

{

"usingComponents": {

"component": "/components/component",

"body": "/components/body/body",

"custom-form": "/components/form/form",

"custom-input": "/components/form/input/input",

"custom-submit": "/components/form/submit/submit"

}

}

编写页面的wxml

<custom-form>

<view>

<custom-input/>

</view>

<custom-submit/>

</custom-form>

完成(o)/
至此,根据一个behaviors完成一个组件

抽象性节点

抽象节点类似于挂载点,但是和挂载点不同的是,可以通过属性来更改挂载的组件。需要注意的一点是,其值需要为静态值,不能为动态值,抽象节点只能使用静态的内容。

但是个人感觉和挂载点还是有一点类似的作用,不过这个是通过不同的条件达到调用的目的。

抽象节点核心在于调用的时候才能确定内部需要什么组件,只有调用才能确认需要的组件,核心在于将业务和逻辑分离,彻底达到消除耦合的目的。

组件的目的在于尽可能的减少业务逻辑在里面。
注意,组件的确是要尽可能的减少逻辑在里面,因为组件的核心在于复用,在于大量的复用。减少重复代码的书写,即将一段业务中的重复的,多次的抽象出来,提取成为一个组件,如果因为某些原因,必须要存在一定的业务逻辑在里面,这个时候就需要抽象节点。

抽象节点和挂载点的不同就在上方体现出来了,抽象节点是必须有的,但是挂载点可有可无

抽象节点的核心在于分离,抽象。
再次感受抽象的重要性

在组件中使用抽象节点

在自定义模板中的一些节点,其对应的自定义组件不是由自定义组件本身确定的,由调用者确定,称为抽象节点

这定义╮(╯▽╰)╭

例如下面的代码

<view>
	<label>
		<selectable disabled="{{false}}"/>
	</label>
</view>

在上方的代码中,selectable是由调用者确定的,需要在调用的时候根据属性值进行替换
还需要在json文件中添加如下的配置

{
	"componentGenerics": {
		"selectable": true
	}
}

直接声明该节点为抽象节点,其值由调用者确定

使用包含抽象节点的组件

上方是在代码中定义抽象节点。仅仅是定义,还不能使用。
如果要是使用抽象节点,需要再次添加属性

generic 为一个选项

在page页面中写入如下内容

<custom-form  generic:selectable="component">

</custom-form>

表明引入一个组件,其中的抽象节点的selectable替换为component内容。

需要注意的是,需要在json文件中引入component的内容

默认组件

即在未指定组件内容的时候使用的组件
在组件文件夹中的json声明。
此时不需要使用true即可声明抽象节点

{

"usingComponents": {},

"componentGenerics": {

"selectable": {

"default": "/components/component"

}

}

}

自定义组件扩展

自定义组件的扩展实质为提供了修改自定义组件定义段的能力。使用自定义组件的扩展能动态的修改的自定义组件的扩展。

一直别一个及其简单的问题困扰了很久,es6中新增加的对象属性声明,并赋值,可以直接省去function关键字。

关于es6

关于es6的问题,是滴,被微信官方文档的一个写法纠结了很久

```js
module.exports = Behavior({
  definitionFilter(defFields) {
    defFields.data.from = 'behavior'
  },
})

就上方的写法,由于是一种新的写法,上方的等价于下方的内容

module.exports = Behavior({
	definitionFilter: function definitionfilter(defFields) {
		defFields.data.form = 'behavior'
	}
})

仅仅是一种新的es6的写法。一种声明私有函数的方式,一般在组件里声明私有函数。这个时候,可以直接省去function。
好啦,最大的障碍解决了。

definitionfilter函数

Behavior()构造器定义了一个新的段,即definitionfilter段。
该函数具有两个定义段,分别是defFields以及 definitionFilterAll此为两个参数
下面解释这两个参数

defFields参数

对于该参数来说,是当前被调用使用的behavior,这个灰常简单不在多说

definitionFilterAll参数

这个参数为behaviors顺序。
使用一个官方的栗子来解释吧

// behavior3.js
module.exports = Behavior({
    definitionFilter(defFields, definitionFilterArr) {},
})

// behavior2.js
module.exports = Behavior({
  behaviors: [require('behavior3.js')],
  definitionFilter(defFields, definitionFilterArr) {
    // definitionFilterArr[0](defFields)
  },
})

// behavior1.js
module.exports = Behavior({
  behaviors: [require('behavior2.js')],
  definitionFilter(defFields, definitionFilterArr) {},
})

// component.js
Component({
  behaviors: [require('behavior1.js')],
})

在上方的栗子中,每个defFelds都为当前调用的behaviors,而definitionFilterArr是这样的情况
当调用2的时候,因为会调用3的definitionFilter函数,对其内容进行更改,在3中的definitionFilter函数有两个参数,第一个参数为2的behavior的定义段,即2中的各项内容进行更改,第二个参数为3的behaviors的内容,由于3没有引用其他的behaviors,所以为一个空数组

总结,当调用的时候,第一个参数为调用者的behaviors,而第二个参数为其本身的behaviors

当进行到1的时候,将会调用2的definitionFilter,其2的该函数的第一个参数为1的behaviors,和其他的一些项,第二个参数为2引用的behaviors,由于2引用了3的behaviors,而3没有引用,所以是一个只有一项的数组,该数组的内容为2引用的behaviors,即3的definitionFilter定义段

如果当调用1的时候,要调用3的definitionFilter函数
分析,3的definitionFilter函数由2的behaviors函数调用,而2的·definitionFilter函数是由1的behaviors调用,并且3的definitionFilter函数在2中的definitionFilter函数的第二个参数的第一项(数组)中有其内容,所以需要在2中写数组,用来调用3的definitionFilter函数。
所以第2中有definitionFilterArr[0](defFields)表明是调用3的definitionFilter而参数defFields表明是2中的behaviors中的内容。

同理使用Component构造函数的时候,将会调用1的definitionFilter函数对Component内容进行更改。

最后,总结就是一句话

当调用的时候,第一个参数为调用者的behaviors,而第二个参数为其本身的behaviors

官方扩展包 https://github.com/wechat-miniprogram/computed 实现动态的计算属性

哦。貌似切图仔最重要的瀑布流还没有学习

第三方自定义组件

终于到自己的知识范畴啦。目前已经会node.js和npm,下面的就比较好学习了。
微信小程序的官方ide支持npm
官方提供有一个模板 https://github.com/wechat-miniprogram/miniprogram-custom-component
属于小程序的自定义脚手架的相关内容。
官方的事例的组件 https://github.com/wechat-miniprogram/slide-view
以及官方提供的命令行工具 https://github.com/wechat-miniprogram/miniprogram-cli

命令行工具

npm install -g @wechat-miniprogram/miniprogram-cli

东西有点多

安装完成以后进行初始化

miniprogram init [options] [dirPath]

进行选择即可。

miniprogram

即第三方的自定义组件,custom-component为创建一个空的自定义组件目录,miniprogram为一个小程序的自定义组件的快速的开始,会有一个从github上下的一个模板,写代码即可。
属于脚手架的一部分。

由于涉及到glup,暂时搁置。

目录如下

|--miniprogram_dev // 开发环境构建目录
|--miniprogram_dist // 生产环境构建目录
|--src // 源码
|   |--common // 通用 js 模块
|   |--components // 通用自定义组件
|   |--images // 图片资源
|   |--wxml // 通用 wxml 模版资源
|   |--wxs // 通用 wxs 资源
|   |--wxss // 通用 wxss 资源
|   |
|   |--xxx.js/xxx.wxml/xxx.json/xxx.wxss // 暴露的 js 模块/自定义组件入口文件
|
|--test // 测试用例
|--tools // 构建相关代码
|   |--demo // demo 小程序目录,开发环境下会被拷贝生成到 miniprogram_dev 目录中
|   |--test // 测试工具相关目录
|   |--config.js // 构建相关配置文件
|
|--gulpfile.js

即,按照上方进行构建相关的组件即可。目前src部分能看明白,暴露的接口和node.js的包如出一辙,都是直接在主文件中进行暴露出接口的,最上方两个文件,最开始接触到的是git的工作流,根据git的工作流也能明白,最后test和tools这一点还有点晕。测试用例使用下方的命令构建出测试用例。

npm run test

tools中的demo为一个演示,即开发者下载下来内容以后将会直接出现的内容,例如,文档中的使用微信小程序打开这一点就是参考这样的,
test测试工具相关目录,进行测试的工具存放的目录。例如进行自动化测试的一些脚本要书写在这里。
config.js为进行自动化构建所要进行的文件,

ps 由于构建工具未学,构建工具的学习重点肯定是配置文件的书写。以及对接口的暴露等。

至此,暂时结束微信小程序的自定义组件化,明天写插件。

版权声明:本文为melovemingming原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/melovemingming/article/details/82762436

智能推荐

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 地址,应该关闭...