全局数据
多个页面需要用到一个公共数据,简单的写法可能会如下代码所示:
index.js文件
Page({
data: { // index.js页面需要baiduUrl数据 baiduUrl: 'https://www.baidu.com' } });
detail.js文件
Page({ data: { // detail.js页面需要baiduUrl数据 baiduUrl: 'https://www.baidu.com' } });
但是如果每个页面都自己定义baiduUrl,不利于后期统一更改,因此无需每个页面定义值,只需在app.js定义,如下代码所示:
app.js文件
App({ // 直接放在全局js里,如挂靠在全局的数据一样的道理,可供每个页面访问 baiduUrl: 'https://www.baidu.com' });
而index页面如果想要使用,只需要按照如下代码,detail页面同样
index.js文件 Page({ data: { baiduUrl: '' }, // 页面加载完成的生命周期方法 onLoad() { // 设置更改data里baiduUrl的值为全局的js上挂靠的值 this.setData({ baiduUrl: app.baiduUrl }) // 此时的baiduUrl为“https://www.baidu.com” console.log(this.data.baiduUrl) } }); // 全局的getApp函数可以用来获取全局app.js里的小程序实例,例如:app.baiduUrl拿到app.js里全局定义的baiduUrl值 let app = getApp();
多个页面使用的数据,直接写在全局,后期需更改只需要更改app.js里的值,方便维护。
自定义组件(参考文档:框架 - 自定义组件)
在此之前,先阅读(自定义组件 - 创建自定义组件:https://smartprogram.baidu.com/docs/develop/framework/custom-component/)
在pages同级目录新建components文件夹,用来存放公共组件
例一:头部
在components文件夹里新建header文件夹存放header组件,并在其文件夹下新建所需文件
header代码内容如下:
header.swan文件
<view class="headerTitle">{{title}}</view>
在js 文件中,需要使用 Component() 来注册组件,并提供组件的属性定义properties、内部数据data和自定义方法methods。
header.js文件
// 自定义组件逻辑 (custom.js) Component({ properties: { // 定义了title属性,可以在使用组件时,由外部传入。此变量可以直接在组件模板中使用,例如<text>{{title}}</text>
(title为外部传入的属性名,String为传入title的数据类型) title: String },
// 内部数据,如vue中的data data: { }, // 进入页面节点树时执行,相当于vue中mounted,下方methods里的方法在这里调用 attached() { }, /** * 组件的方法列表 */ methods: { } })
在 json 文件中进行自定义组件声明(在 json 文件中将 component 字段设为 true 可将这一组文件设为自定义组件)
header.json文件
{ "component": true }
header.css文件
.headerTitle { 100%; height: 80rpx; line-height: 80rpx; background: greenyellow; text-align: center; color: #fff; margin: 20rpx 0; }
页面上使用header组件:
index的json文件中引入组件
index.json文件 { // 原本就存在的头部名称设置 "navigationBarTitleText": "index", // 引入组件 (注册的组件名:组件路径) "usingComponents": { "header": "/components/header/header" } }
index的swan文件中使用组件
index.swan文件
<view class="group"> // 传给组件所需的title内容 (json文件中组件注册的组件名做为标签名) <header title="index页面头部"></header> </view>
detail同上
detail.json文件 { "navigationBarTitleText": "detail", "usingComponents": { "header": "/components/header/header" } }
detail.swan文件 <view class="group"> <header title="detail页面头部"></header> </view>
效果如下,index和detail页面都引入header组件,并根据页面不同显示不同内容。
index页面:
detail页面:
例二:页面tab栏
在components文件夹里新建header文件夹存放header组件,并在其文件夹下新建所需文件
nav代码内容如下:
nav.swan
<view class="nav"> <view class="nav-item "> <text class="{{addActiveIndex == index?'addActive':''}}" s-for="item, index in navList">{{item}}</text> </view> </view>
nav.js
Component({ /** * 组件的属性列表 */ properties: { // 定义了page属性,可以在使用组件时,由外部传入。此变量可以直接在组件模板中使用
(page为外部传入的属性名,String为传入page的数据类型) page: String }, /** * 组件的初始数据 */ // 内部数据,如vue中的data data: { navList: ['index页面','detail页面'], addActiveIndex: '' }, // 进入页面节点树时执行,相当于vue中mounted,下方methods里的方法在这里调用 attached() { this.addActive(); }, /** * 组件的方法列表 */ methods: { addActive() { // 设置addActiveIndex添加选中下标为外部传进来的值 this.setData({ addActiveIndex: this.properties.page }) } } })
将这一组文件设为自定义组件
nav.json { "component": true }
nav.css
.nav { margin-top: 40rpx; } .nav .nav-item text{ display: inline-block; 50%; height: 100rpx; line-height: 100rpx; background: #ccc; text-align: center; } /* 当前页面的nav添加选中样式 */ .addActive { background: greenyellow!important; }
页面上使用nav组件:
index的json文件中引入组件
index.json
{
"navigationBarTitleText": "index",
"usingComponents": {
"nav": "/components/nav/nav"
}
}
index的swan文件中使用组件
index.swan <view class="group"> // 传入所需的page内容,作为tab显示选中的下标 <nav page="0"></nav> </view>
detail同上
detail.json { "navigationBarTitleText": "detail", "usingComponents": { "nav": "/components/nav/nav" } }
detail.swan
<view class="group">
// 传入所需的page内容,作为tab显示选中的下标
<nav page="1"></nav>
</view>
效果如下,index和detail页面都引入nav组件,并根据页面显示当前所在的tab。
index页面:
detail页面:
例三:选择器
在components文件夹里新建selector文件夹存放selector组件,并在其文件夹下新建所需文件
selector代码内容如下:
selector.swan
<view class="selectorContent">
<!-- 可点击的选框 --> <view class="inputContent" bind:tap="showSelectorAction"> <input class="selectInput {{selectVal?'selectInputChecked':''}}" value="{{selectVal}}" placeholder='{{selectorData.val}}' placeholder-style="color:#999" disabled/> <text class="selectArrow {{selectVal?'selectArrowChecked':''}}"></text> </view>
<!-- 显示的下拉框 --> <view class="selector {{showSelector == 'true'?'moveIn':'moveOut'}}"> <view class="list"> <text class="title-item">{{selectorData.val}}</text> <text class="list-item" s-for="item in selectorData.select" bind:tap="selectListAction" data-lab="{{selectorData.lab}}" data-val="{{selectorData.val}}" data-item="{{item}}">{{item.val}}</text> </view> <text class="cancel" bind:tap="selectCancelAction">取消</text> </view>
<!-- 遮罩层 --> <view class="mask" s-if="showMask == 'true'"></view>
</view>
selector.js
Component({ /** * 组件的外部属性列表(外部传进来的数据) */ properties: { data: Array }, /** * 组件的初始数据 */ data: { showSelector: 'false',// 是否显示选择器 showMask: 'false',// 是否显示遮罩层 selectorData: {},// 放传过来的选择器列表数据 saveSelectData: {},// 用来暂时保存selector选择器选中数据,然后传到外部 }, // 组件实例进入页面节点树时执行 attached() { this.getSelectorData(); }, /** * 组件的方法列表 */ methods: { // 方法 - 获得外部传进来的选择器数据,并保存到selectorData里 getSelectorData() { this.setData({ selectorData: this.properties.data }) }, // 方法 - 点击显示选择器和遮罩层 showSelectorAction(e) { this.setData({ showSelector: 'true', showMask: 'true' }) }, // 方法 - 列表选中(selector列表选中的数据保存在saveSelectData) selectListAction(e) { let selectData = e.currentTarget.dataset; let defaultVal = e.currentTarget.dataset.val; let selectVal = e.currentTarget.dataset.item.val; this.setData({ showSelector: 'false', // 关闭选择器 showMask: 'false', // 关闭遮罩层 selectVal: defaultVal+' '+'('+selectVal+')',// 把选中的值赋给输入框 saveSelectData: selectData // 选中的值保存到saveSelectData里,可供下方传递到外部 }) // 将组件数据传到外部的方法为this.triggerEvent('方法名',{要传递的数据})。方法名要和外部bind绑定的方法名一致 this.triggerEvent('saveSelectDataChange', this.data.saveSelectData); }, // 方法 - 取消选择 selectCancelAction(e) { // 取消的话传到外部的数据里添加cancel,以便于外部通过判断数据里是否有cancel属性名来确定是否取消删除该数据 // 在saveSelectData里新增key值,并设置值
let key = 'saveSelectData.cancel'; this.setData({ showSelector: 'false',// 关闭选择器 showMask: 'false',// 关闭遮罩层 selectVal: '',// 清空输入框的值 [key]: 'true' // 让key为cancel的值为true }) // 将组件数据传到外部的方法为this.triggerEvent('方法名',{要传递的数据})。方法名要和外部bind绑定的方法名一致 this.triggerEvent('saveSelectDataChange', this.data.saveSelectData); } } })
selector.json
{ "component": true }
selector.css
/* 遮罩层 */ .mask { 100%; height: 100%; background: #000; position: fixed; left: 0; top: 0; opacity: .5; z-index: 2; } /* 下拉选择器 */ .selector { 100%; position: fixed; z-index: 3; bottom: 0; left: 0; overflow: hidden; margin-left: 20rpx; margin-right: 20rpx; } .selector .list { border-radius: 12rpx; background: #fff; border: 1rpx solid #CBCBCB; text-align: center; } .selector .list .title-item { display: block; height: 80rpx; line-height: 80rpx; font-size: 26rpx; color: #8F8E94; border-bottom: 1rpx solid #CBCBCB; } .selector .list .list-item { display: block; height: 110rpx; line-height: 110rpx; font-size: 40rpx; color: #007AFF; border-bottom: 1rpx solid #CBCBCB; } .selector .list .list-item:last-child { border: none; } .selector .cancel { display: block; height: 110rpx; line-height: 110rpx; font-size: 40rpx; color: #007AFF; border: 1rpx solid #CBCBCB; border-radius: 12rpx; background: #fff; margin: 20rpx 0; text-align: center; } /* 下拉选框 */ .inputContent { 100%; height: 92rpx; position: relative; margin-bottom: 20rpx; } .selectInput { display: inline-block; 100%; height: 92rpx; line-height: 92rpx; padding-left: 30rpx; border: 1rpx solid #ddd; position: absolute; left: 0; top: 0; z-index: 1; font-size: 32rpx; color: #999; } .selectArrow { display: inline-block; 30rpx; height: 30rpx; background: url(../../images/down-gray.png) no-repeat; background-size: 30rpx 30rpx; position: absolute; right: 30rpx; top: 30rpx; } .selectInputChecked { border: 1rpx solid #4b46fa!important; color: #4b46fa!important; } .selectArrowChecked { background: url(../../images/down.png) no-repeat!important; background-size: 30rpx 30rpx!important; } /* 选择器移入移出动画 */ /* 动画时间 */ .moveIn { display: block; animation: moveIn 1s; animation-fill-mode: forwards; } .moveOut { display: none; animation: moveOut 1s; animation-fill-mode: forwards; } /* 动画过程 */ @keyframes moveIn { from { bottom: -100%; } to { bottom: 0; } } @keyframes moveOut { from { bottom: 0; } to { bottom: -100%; } }
页面上使用selector组件:(如果要单个选择器)
index的swan文件中使用组件(bind绑定的方法要和组件内this.triggerEvent('方法名',{要传递的数据}); 的方法名一致)
index.swan
<view class="group"> <selector data="{{selector}}" bind:saveSelectDataChange="saveSelectDataChange"></selector> </view>
index.js
Page({ data: { // 传递给组件的选择器数据 selector: { lab: 'A', val: '吃吃吃', select: [ {lab: 'a1', val: '汉堡'}, {lab: 'a2', val: '肠粉'}, {lab: 'a3', val: '绝味'} ] } }, // 方法 - 选择器发生改变时,组件内通过this.triggerEvent('方法名',{要传递的数据});传递过来的选中数据,会在e的detail里 saveSelectDataChange(e) { let data = e.detail;
console.log(data) // 选择器选中的数据,打印出来的内容请看下方“附上选中图”。选择器取消时,打印的内容请看下方“附上取消图”
}
});
效果如下,index页面引入selector组件。
默认效果
点击显示选择器效果
选中内容效果
附上选中图:选中传递给外部的数据:console.log(data)
附上取消图:选中传递给外部的数据:console.log(data) (注:取消时会有cancel时段,可以通过判断组件传递过来的数据是否有cancel字段,如果没有,保存数据,如果有,则从保存数据的地方对应删除掉)
页面上使用selector组件:(如果要多个选择器)
index的swan文件中使用组件(bind绑定的方法要和组件内this.triggerEvent('方法名', {要传递的数据}); 的方法名一致)
index.swan
<view class="group">
index.js
Page({ data: { // 传递给组件的选择器数据 selector: [ { lab: 'A', val: '吃吃吃', select: [ {lab: 'a1', val: '汉堡'}, {lab: 'a2', val: '肠粉'}, {lab: 'a3', val: '绝味'} ] }, { lab: 'B', val: '喝喝喝', select: [ {lab: 'b1', val: '可乐'}, {lab: 'b2', val: '金桔柠檬水'}, {lab: 'b3', val: '蜂蜜水'} ] }, { lab: 'C', val: '玩玩玩', select: [ {lab: 'c1', val: '过山车'}, {lab: 'c2', val: '遨游太空'}, {lab: 'c3', val: '跳楼机'} ] }, { lab: 'D', val: '买买买', select: [ {lab: 'd1', val: '口红'}, {lab: 'd2', val: '护肤品'}, {lab: 'd3', val: '衣服'} ] } ] }, // 方法 - 选择器发生改变时,组件内通过this.triggerEvent('方法名',{要传递的数据});传递过来的选中数据,会在e的detail里 saveSelectDataChange(e) { let data = e.detail; console.log(data) } });
效果如下,index页面引入selector组件。
默认效果
点击显示选择器效果
选中内容效果
也能多选