组件模块化

基本概括

  • 模块化一般分为二种,页面和模块。页面由模块构成。
  • 我们拆分模块化可能是这样子的
    • modules(页面模块)
      • pageA
        • A1模块
        • A2模块
      • pageB
        • B1模块
        • B2模块
    • pages(页面)
      • pageA
      • pageB
  • 在小程序当中
    • 我们使用Page注册小程序中的一个页面@官方文档-page说明
    • 使用Component创建自定义组件@官方文档-Component说明
      • 注意下,通过Component创建的组件里面的样式,只会应用于当前组件,比如组件A内部设置了类A,那么在外部即使设置了同样的类名,也不会被应用相同的类名
    • 所以我们创建页面使用Page,创建模块使用Component
  • 模块化后需要注意的点(官方API拷贝过来的)
    • 因为 WXML 节点标签名只能是小写字母、中划线和下划线的组合,所以自定义组件的标签名也只能包含这些字符。
    • 自定义组件也是可以引用自定义组件的,引用方法类似于页面引用自定义组件的方式(使用 usingComponents 字段)。
    • 自定义组件和页面所在项目根目录名不能以“wx-”为前缀,否则会报错。
    • 出于性能考虑,使用 usingComponents 时, setData 内容不会被直接深复制,即 this.setData({ field: obj })this.data.field === obj 。(深复制会在这个值被组件间传递时发生。)

页面使用模块化组件

组件父子传值

父亲给儿子值

1
2
3
4
5
vue时候
<Son :name="name" :age="age"/>

微信小程序
<Son name="{{ name }}" age="{{ age }}"/>
  • 儿子需要做的
    • 就是需要添加properties属性,并未其添加对应的属性说明即可
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
//小程序

// Son.js
Component({
//...

//书写将要接收的值
properties:{
name:{
// 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
type:String,
// 属性初始值(可选),如果未指定则会根据类型选择一个
value: '',
// 属性被改变时执行的函数(可选)
// 其实也可以不在这里写,在observers对象(监听data和properties变化)当中书写也可以
observer: function (newVal, oldVal) { }
},
age:{
type:number,
value:0
}
}

//...
})

//然后就可以正常使用了

//Son.wxml

<view>

<text>名称是:{{ name }}</text>
<text>年龄是: {{ age }}</text>
</view>

儿子给父亲值

  • 方式1: triggerEvent
  • 方式2: 双向绑定

方式1:triggerEvent

  • 资料

  • 父亲需要做的

    • 通过bind:自定义事件名=回调函数传递给儿子
    • 注意,父亲通过triggerEvent接收的参数不单单是子组件传递过来的数据,还有很多其他的数据,子组件传递过来的数据仅仅是在其中的detail字段里面
    • 输出查看儿子传递过来的数据,可以看到,儿子传递过来的name数据被微信小程序放在了detail对象当中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Father.wxml
<Son bind:changething="getChangeParams"/>

// Father.js
Page({
//...

methods:{

changething(e){
console.log(e);
//注意查看上面输出截图
}
},

//...
})
  • 儿子需要做的
    • 通过this.triggerEvent调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Son.wxml
<view>
<text bind:tap="handleChange">点击我触发事件</text>
</view

// Son.js

Component({
//...

methods:{
handleChange(){
// 参数1为触发的事件名
// 参数2为detail对象(也就是我们需要传递给父组件的值)
// 参数3为触发发事件的选项(可选)
const data = {name:'我是子组件传递的数据'}
this.triggerEvent('changething',data)
}
},

//...
})

方式2:双向绑定

todo todo todo todo todo todo todo todo todo todo

获取组件实例对象和组件自定义返回结果

  • 学习学习~

获取组件示例对象同时调用组件实例

组件自定义返回结果

为Component/Page指明Data类型,Method类型(ts)

  • 感觉小程序ts挺乱的吧….话不多说

Page页面指明

  • types.ts(类型文件)
1
2
3
4
5
6
7
8
9
10
11
12

//定义data当中应该有的数据
export interface Data{
name:string,
age:string,
}

//定义应该有的方法
//export type SayHello = () => void;
export interface Methods {
sayHello:() => void;
}
  • index.ts(每一个page都有的入口文件)
1
2
3
4
5
6
7
8
9
10
11
12
import {Data,Methods} from "./types";

Page<Data,Methods>({
data:{
name:'梦洁'
age:18,
sex:'知',//多了,ts检测报错
},
sayHello(){

}
})

Component组件指明

  • Page有一点不一样,因为Component多了一个properties不过这个properties可以要,也可以不要

  • types.ts(类型文件)

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
import MethodOption = WechatMiniprogram.Component.MethodOption;
import PropertyOption = WechatMiniprogram.Component.PropertyOption;
//定义data当中应该有的数据
export interface Data{
name:string,
age:string,
}

//定义Properties属性
export interface ListParams {
page:number
pageSize:number
}

export interface Props extends PropertyOption{
params: {
type: ObjectConstructor,
value: ListParams | any
}
}

//定义methods有的方法
//export type SayHello = () => void;
export interface Methods extends MethodOption {
sayHello:() => void;
}

  • index.ts(每一个Component都有的入口文件)
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
import {Data,Props,Methods} from "./types";

//如果不需要Properties说明,则第二个参数需要为 ‘{}’
Component<Data,Props,Methods>{
data:{
name:'梦洁'
age:18,
sex:'知',//多了,ts检测报错
},

properties:{
params:{
//目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
type: Object,
value: (() => {
page:1,
pageSize:10
}),
}
},

methods:{
sayHello(){

}
}
}


外部样式类

  • @官方文档-外部样式类

  • 启用来源于一个t-design吧,要设置search的背景颜色,发现没有props,但是有external-classes,所以就来学习学习

  • 有时,组件希望接受外部传入的样式类。此时可以在 Component 中用 externalClasses 定义段定义若干个外部样式类。这个特性可以用于实现类似于 view 组件的 hover-class 属性:页面可以提供一个样式类,赋予 viewhover-class ,这个样式类本身写在页面中而非 view 组件的实现中。

注意:在同一个节点上使用普通样式类和外部样式类时,两个类的优先级是未定义的,因此最好避免这种情况。(意思就是你在组件内部通过这个类名设置了样式,又在外部通过暴露的类名设置了样式,当样式发生重叠的时候,优先使用谁的不确定,但是可以使用important来强制)

代码示例:

  • 组件
1
2
3
4
/* 组件 custom-component.js */
Component({
externalClasses: ['my-class']
})
1
2
<!-- 组件 custom-component.wxml -->
<custom-component class="my-class">这段文本的颜色由组件外的 class 决定</custom-component>
  • 页面
1
2
<!-- 页面的 WXML -->
<custom-component my-class="red-text" />
1
2
3
4
/* 页面的 */
.red-text {
color: red;
}

组件的插槽

  • 如果是默认插槽,直接使用就可以,不需要其他做法
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 组件模板 -->
<view class="wrapper">
<view>这里是组件的内部节点</view>
<slot></slot>
</view>

<!-- 引用组件的页面模板 -->
<view>
<component-tag-name>
<!-- 这部分内容将被放置在组件 <slot> 的位置上 -->
<view>这里是插入到组件 slot 中的内容</view>
</component-tag-name>
</view>
  • 默认情况下,一个组件的 wxml 中只能有一个 slot 。需要使用多 slot 时,可以在组件 js 中声明启用
1
2
3
4
5
6
7
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多 slot 支持
},
properties: { /* ... */ },
methods: { /* ... */ }
})
  • 然后在组件当中就可以以不同的name来区分插槽,并且父组件也可以使用了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 组件模板 -->
<view class="wrapper">
<slot name="before"></slot>
<view>这里是组件的内部细节</view>
<slot name="after"></slot>
</view>

<!-- 引用组件的页面模板 -->
<view>
<component-tag-name>
<!-- 这部分内容将被放置在组件 <slot name="before"> 的位置上 -->
<view slot="before">这里是插入到组件slot name="before"中的内容</view>
<!-- 这部分内容将被放置在组件 <slot name="after"> 的位置上 -->
<view slot="after">这里是插入到组件slot name="after"中的内容</view>
</component-tag-name>
</view>

路由传参 todo

小程序登录 todo

  • 登录流程如图所示

  • 巴拉巴拉,就不赘叙了,前端一般都是调用wx.login然后向自己的后端提供的接口发送请求就完成,然后存储token

小程序获取用户信息(正确应该叫头像昵称填写能力)

小程序获取手机号

1
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button>

小程序骨架屏

参考文章