自定义组件的创建和使用
开发者可以将页面内的功能模块抽象成自定义组件,在智能小程序的各个页面中进行使用,提升代码复用度,节省开发成本。
一个自定义组件由4个文件 (.swan .css .js .json) 组成, 例如包含自定义组件 custom 的项目结构:
// 包含自定义组件custom的项目结构
├── app.js
├── app.json
├── project.swan.json
└── components
└── custom
├── custom.swan
├── custom.css
├── custom.js
└── custom.json
要编写一个自定义组件,首先需要在 json 文件中进行自定义组件声明(在 json 文件中将 component 字段设为 true 可将这一组文件设为自定义组件):
// 自定义组件配置 (custom.json)
{
"component": true
}
同时,类似于页面开发。开发自定义组件,可以在 swan 文件中编写组件模板,在 css 文件中引入样式,它们的写法和页面的写法类似。
示例代码
<!-- 自定义组件内部的模板 (custom.swan) -->
<view class="name">
{{name}}
</view>
/* 自定义组件的css,在该自定义组件内部生效 (custom.css) */
.name {
color: red;
}
在自定义组件的 js 文件中,需要使用 Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法。
组件的属性值和内部数据将被用于组件 swan 模板的渲染,其中,属性是可以由组件外部传入的。
示例代码
// 自定义组件逻辑 (custom.js)
Component({
properties: {
// 定义了name属性,可以在使用组件时,由外部传入。此变量可以直接在组件模板中使用
name: {
type: String,
value: 'swan',
}
},
data: {
age: 1
},
methods: {
tap: function(){}
}
})
<!-- 自定义组件内部的模板 (custom.swan) -->
<view class="name" bindtap="tap">
{{name}}{{age}}
</view>
使用自定义组件
使用已注册的自定义组件前,首先要在页面的 json 文件中进行引用声明。除了在页面使用自定义组件,你还可以在自定义组件引用自定义组件,类似于页面引用自定义组件。
以下举例页面级(pages/home/home)的使用场景:
// 项目目录结构
├── app.js
├── app.json
├── project.config.json
└── pages
└── home
├── home.swan
├── home.css
├── home.js
└── home.json
└── components
└── custom
├── custom.swan
├── custom.css
├── custom.js
└── custom.json
首先需要提供每个自定义组件的标签名与其对应的自定义组件文件路径。
提示:
1.自定义组件文件路径: 自定义组件swan、css、js、json文件所在路径 + 该类文件的basename, 例如以上项目目录结构,该路径即是/components/custom/custom;
2.创建自定义组件,推荐内层的文件(swan、css、js、json)与其自定义组件目录保持同名。
示例代码
// 页面json配置 home.json
{
"usingComponents": {
"custom": "/components/custom/custom"
}
}
这样,在页面的 swan 文件中,就可以像使用基础组件一样使用自定义组件。节点名即自定义组件的标签名,节点属性即传递给组件的属性值。
示例代码
<!-- 页面模板 (home.swan) -->
<view>
<!-- 在页面中对自定义组件进行引用 -->
<custom name="swanapp"></custom>
</view>
自定义组件的 swan 节点结构在与数据结合之后,将被插入到引用位置内。
说明:
- 自定义组件只能在
1.10.13以上的 swan.js 中使用; - 同一页面引用的自定义组件,不同路径的自定义组件暂时不能使用相同的自定义组件名字;
- 在页面级的配置(json文件)中不能添加
"component": true,因为将page当做自定义组件使用是不允许的; - 对于自定义组件中的资源引用路径,使用相对路径目前针对的是自定义组件SWAN文件所对应的目录层级,故暂时推荐使用绝对路径。
组件模板和样式
解释: 类似于页面,自定义组件拥有自己的 swan 模板和 css 样式。
组件模板
组件模板的写法与页面模板相同。组件模板与组件数据结合后生成的节点树,将被插入到组件的引用位置上。
在组件模板中可以提供一个 <slot> 节点,用于承载组件引用时提供的子节点。
示例代码
<!-- 组件内部模板 -->
<view class="wrapper">
<view>组件内部节点</view>
<slot></slot>
</view>
<view>
<custom-component>
<view>这里是插入到组件slot中的内容</view>
</custom-component>
</view>
模板数据绑定
与普通的 SWAN 模板类似,可以使用数据绑定,这样就可以向子组件的属性传递动态数据。
<view>
<custom-component prop-a="{{dataFieldA}}" prop-b="{{dataFieldB}}">
<view>这里是插入到组件slot中的内容</view>
</custom-component>
</view>
在以上例子中,组件的属性 propA 和 propB 将收到页面传递的数据。页面可以通过 setData 来改变绑定的数据字段。
组件的slot
解释:
在组件的视图模板中可以通过 slot 声明一个插槽的位置,其位置的内容可以由外层组件或者页面定义。
示例代码
<!-- 组件中的定义 -->
<view>
<slot></slot>
</view>
<!-- 使用组件的页面或者组件 -->
<view>
<custom-component>
<view>我是slot中插入的节点</view>
</custom-component>
</view>
通过 name 属性可以给 slot 命名。一个视图模板的声明可以包含一个默认 slot 和多个命名 slot。外层组件或页面的元素通过 slot="name" 的属性声明,可以指定自身的插入点。
示例代码
<view>
<slot name="slot1"></slot>
<slot name="slot2"></slot>
</view>
<view>
<custom-component>
<view slot="slot1">我会被插入到组件上方</view>
<view slot="slot2">我会被插入到组件下方</view>
</custom-component>
</view>
slot指令应用
解释:
在 slot 声明时应用 if 或 for 指令,可以让插槽根据组件数据动态化。 示例代码**
<view>
<slot s-if="!visible" name="subcomponent"></slot>
</view>
数据环境
解释:
插入 slot 部分的内容,其数据环境为声明时的环境。
示例代码
<!-- custom-component自定义组件 -->
<view class="component-range">
<slot name="inner"></slot>
</view>
Component({
data: {
name: 'swan-inner'
}
});
<!-- 使用组件的页面或者组件 -->
<view>
<custom-component>
<view>{{name}}</view>
</custom-component>
</view>
Page({
data: {
name: 'swan-outer'
}
});
渲染结果:
<view>
<view class="component-range">
<view>swan-outer</view>
</view>
</view>
scoped 插槽
如果 slot 声明中包含 s-bind 或 1 个以上 var- 数据前缀声明,该 slot 为 scoped slot。scoped slot 具有独立的 数据环境。
scoped slot 通常用于组件的视图部分期望由 外部传入视图结构,渲染过程使用组件内部数据。
示例代码
<!-- custom-component自定义组件 -->
<view class="component-range">
<slot name="inner" var-name="name"></slot>
</view>
Component({
data: {
name: 'swan-inner'
}
});
<!-- 使用组件的页面或者组件 -->
<view>
<custom-component>
<view>{{name}}</view>
</custom-component>
</view>
Page({
data: {
name: 'swan-outer'
}
});
渲染结果:
<view>
<view class="component-range">
<view>swan-inner</view>
</view>
</view>
组件样式
组件的样式,可以在组件的 css 文件中编写,并且只对当前组件内节点生效。使用时,需要注意以下几点:
- 只可以使用 class 选择器,其他的选择器,请改为 class 选择器实现;
- 组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用;
- 继承样式,如 font 、 color,会从组件外继承到组件内。
外部样式类
解释:
当组件希望接受外部传入的样式类(类似于 view 组件的 hover-class 属性)时,可以在 Component 中用 externalClasses 定义段定义若干个外部样式类。
注意:在同一个节点上使用普通样式类和外部样式类时,请避免出现两个类的优先级是未定义的情况。
示例代码
/* 组件 custom-component.js */
Component({
externalClasses: ['external-class']
});
<!-- 组件 custom-component.swan --> <view class="external-class">这段文本的颜色由组件外的 class 决定</view>
组件的使用者可以像使用其他属性一样,指定这个样式类对应的 class 。
<!-- 使用组件的页面或者组件 --> <custom-component external-class="red-text" />
.red-text {
color: red;
}
全局样式类
解释:
使用外部样式类可以让组件使用指定的组件外样式类,如果希望组件外样式类能够完全影响组件内部,可以将组件构造器中的options.addGlobalClass字段置为true。
示例代码
/* 组件 custom-component.js */
Component({
options: {
addGlobalClass: true,
}
});
<!-- 组件 custom-component.swan --> <text class="global-class">这段文本的颜色由组件外的 class 决定</text>
/* 组件外的样式定义 */
.global-class {
color: red;
}

// JSON 文件里引用
{
"usingComponents": {
"custom": "/components/custom/custom"
}
}
// /components/custom/custom的样式
.cus { color: red; }
那么 custom的样式会转变为
.custom__cus { color: red; }
所以当新样式的优先级高于加了前缀的样式时,才能覆盖。
未完,待续。。。