百度app下载:http://mo.baidu.com/
开发工具下载:https://smartprogram.baidu.com/docs/develop/devtools/history/
{
// 设置页面路径的数组
"pages": [
"component/component",
"api/api"
],
// 分包结构配置
"subPackages": [
{
"root": "subpackage",
"pages": [
"pages/subpageone/subpageone",
"pages/subpagetwo/subpagetwo"
]
}
],
// 设置页面展现
"window": {
// 导航栏标题文字内容
"navigationBarTitleText": "Demo",
// 导航栏背景色
"navigationBarBackgroundColor": "#000000",
// 导航栏标题颜色 balck/white
"navigationBarTextStyle": "white",
// 导航栏样式 default/custom
"navigationStyle": "default",
// 自定义导航栏custom的组件定义
"usingComponents": {
"nav-bar": "/components/navBar/navBar",
"content": "/components/content/content"
},
// 背景颜色
"backgroundColor": "#ffffff",
// 下拉背景字体、loading图的样式 dark/light
"backgroundTextStyle": "dark",
// 顶部窗口的背景色 仅IOS支持
"backgroundColorTop": "#ffffff",
// 底部窗口的背景色 仅IOS支持
"backgroundColorBottom": "#ffffff",
// 是否开启下拉刷新
"enablePullDownRefresh": "true",
// 页面上拉触底事件时距页面底部距离(px)
"onReachBottomDistance":"50",
// 小程序页面是否禁止响应字体大小的设置 auto(响应)、none(不响应)
"textSizeAdjust": "auto"
// 小程序页面方向 portrait(默认为竖屏显示)、landscape(横屏显示)、auto(跟随系统方向显示)
"pageOrientation": "auto"
},
// 分包预下载规则
"preloadRule": {
"pages/index": {
"network": "all",
"packages": ["subpackage"]
}
},
// 底部tab栏的表现
"tabBar": {
// tab列表
"list": [
{
"pagePath": "component/component",
"text": "首页",
"iconPath": "/images/API_normal.png",
"selectedIconPath": "/images/API_selected.png"
},
{
"pagePath": "api/api",
"text": "详情",
"iconPath": "/images/component_normal.png",
"selectedIconPath": "/images/component_selected.png"
}
],
// tab背景色
"backgroundColor" : "#ffffff",
// tab边框颜色 white/black
"borderStyle": "white",
// tab上文字默认的颜色
"color": "#000",
// tab上文字选中颜色
"selectedColor": "#6495ED"
},
// 需要在后台使用的能力,如音乐播放
"requiredBackgroundModes": ["audio"],
// 网络超时
"networkTimeout": {
// request超时时间
"request": 30000,
// connectSocket超时时间
"connectSocket": 10000,
// uploadFile超时时间
"uploadFile": 10000,
// downloadFile超时时间
"downloadFile": 10000
},
// 小程序权限相关设置
"permission": {
// 位置相关权限
"scope.userLocation": {
// 高速公路行驶持续后台定位
"desc": "你的位置信息将用于小程序位置接口的效果展示"
}
},
// 自定义路由相关设置
"routes": [
{
// 投放入口,scheme中的path
"path": "home",
// 真实的物理存储路径
"page": "pages/home/home"
}
],
// 小程序cookie机制配置
"cookie": {
"enableStore": true
}
}
App({
/************** 生命周期函数 **************/
// 监听Web态小程序登录成功:初次登陆成功触发(只会触发一次)
onLogin: function (options) {
// 仅在Web态小程序有效,App端是无效的
// 使用 options.code 换取 session_key
},
// 监听小程序的初始化:小程序初始化完成触发(只会触发一次)
onLaunch: function (options) {
/* options的属性
** scene: 场景值
** path: 打开小程序的路径,
** query: 当前页面路径中的参数
** shareTicket: 标记转发对象
** referrerInfo: 从另一个小程序打开该小程序
** referrerInfo.appId: 来源小程序的AppKey
** referrerInfo.extraData: 来源小程序传过来的数据
*/
console.log('SWAN launch');
},
// 监听小程序的显示:小程序初始化完成、从后台进入前台都会触发
onShow: function () {
console.log('SWAN展现');
},
// 监听小程序的隐藏:从前台进入后台触发
onHide: function () {
console.log('SWAN当前处于后台');
},
// 错误监听函数:发生脚本错误、API调用失败时触发
onError: function () {
console.log('SWAN发生错误');
},
// 页面不存在的监听函数:打开的页面不存在时触发
onPageNotFound: function () {
};
// 全局变量
globalData: 'SWAN'
});
// XXX.js
const appinfo = getApp();
console.log(appinfo.globalData);
// 上述写法不生效,可试试下述方法
Page({
data: {
appData: getApp().globalData
},
onShow() {
console.log(this.data.appData);
}
})
.css:样式文件
.js:控制交互逻辑的动态语言
Page({
/************** 初始化数据 **************/
data:{
text: '百度小程序',
id: 1,
title: 'cs',
price: '100'
},
/************** 生命周期函数 **************/
// 页面初始化时触发(一个页面只会调用一次)
onInit(param) {
// param当前页面路径的参数
// 不能进行任何依赖视图层的操作
// 并非所有基础库都支持,兼容问题需考虑
// 性能优化,建议将页面的数据网络请求放在 Page.onInit 中,并在网络请求的回调中执行 setData ,可以提升页面的加载速度。
},
// 页面加载时触发(一个页面只会调用一次)
onLoad(param) {
// param当前页面路径的参数
},
// 页面显示 / 切入前台时触发
onShow() {},
// 页面初次渲染完成时触发(一个页面只会调用一次)
onReady() {},
// 页面隐藏 / 切入后台时触发
onHide() {},
// 页面卸载时触发
onUnload() {},
/************** 页面事件处理函数 **************/
// 监听该页面用户下拉刷新事件
onPullDownRefresh() {
// 需要在app.json的window选项中开启 enablePullDownRefresh
// 如果需要单个页面支持下拉刷新,可以直接在页面目录下的 json 配置文件中开启enablePullDownRefresh
// 当处理完数据刷新后,swan.stopPullDownRefresh可以停止当前页面的下拉刷新。
},
// 监听该页面用户上拉触底事件
onReachBottom(e) {
// 可以在 app.json 的 window 选项中或页面配置中设置触发距离 onReachBottomDistance
// 在触发距离内滑动期间,该事件只会被触发一次。
console.log('onReachBottom');
// 常见的业务场景是开发者在这里请求分页数据
},
// 监听用户滑动页面事件
onPageScroll(e) {
// e.scrollTop:页面在垂直方向已滚动的距离(单位:px)
// 慎重调用此方法,避免在onPageScroll中过于频繁的执行setData等引起逻辑层-渲染层通信的操作
},
// 设置该页面的分享信息
// 用户点击页面内的"分享"按钮(button 组件open-type="share")或者页面右上角菜单的"分享"按钮会调用
// 此事件需要 return 一个Object,用于自定义分享内容。
onShareAppMessage(e) {
// e.from:分享事件来源。button:页面内转发按钮;menu:右上角分享菜单
// e.target: 如果from值是button,则target是触发这次转发事件的button,否则为undefined
return {
// 分享标题
title: this.data.title,
// 分享内容(推荐设置为小程序简介或描述)
content: '世界很复杂,百度更懂你——小程序简介或详细描述',
// 分享图标
imageUrl: 'https://b.bdstatic.com/miniapp/images/bgt_icon.png',
// 页面 path,必须是以/开头的完整路径。路径中的参数须通过encodeURIComponent进行编码。
path: '/index/index',
// 分享成功回调函数
success(res) {},
// 分享失败回调函数
fail(err) {},
// 分享结束(无论成功或失败)回调函数
complete(res) {},
};
},
// 点击 tab 时触发
onTabItemTap(item) {
// item.index: 被点击tabItem的序号,从 0 开始
// item.pagePath: 被点击tabItem的页面路径
// item.text: 被点击tabItem的按钮文字
},
// 监听页面 URL query 改变
// 引起页面 URL query 更新的原因有:调用 swan.setURLQuery
onURLQueryChange({newURLQuery, oldURLQuery}) {
console.log(newURLQuery, oldURLQuery);
},
// 监听页面方向变化事件
onResize(res) {
/* res的属性
** orientation:当前页面方向 (竖屏: portrait、横屏: landscape)
** statusBarHeight:状态栏高度
** screenWidth:屏幕宽度
** screenHeight:屏幕高度
** windowWidth:窗口宽度
** windowHeight:窗口高度
**
*/
},
/************** 组件事件处理函数 **************/
//
onTap() {},
// this.setData(data, callback)
// this,setData({ id: 1 }, ()=> {});
// getCurrentPages()
// 全局函数用于获取当前页面栈的实例
// 以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面
})
.swan:页面的展现模板
<view>{{test}}view>
<view s-for="p in persons">{{p.name}}view>
<view s-if="is4G">4Gview>
<view s-elif="isWifi">Wifiview>
<view s-else>Otherview>
<view class="view-more" bind:tap="loadMore">点击加载更多view>
<view data-swan="test" bind:tap="onTap">view>
.json:对本页面的窗口表现进行配置
{
// 导航栏背景色
"navigationBarBackgroundColor": "#ffffff",
// 导航栏标题颜色 black/white
"navigationBarTextStyle": "black",
// 导航栏标题文件内容
"navigationBarTitleText": "智能小程序接口功能演示",
// 导航栏样式 custom/default
"navigationStyle": "default",
// 窗口背景色
"backgroundColor": "#eeeeee",
// 是否下拉刷新
"enablePullDownRefresh": false,
// 下拉loading样式 dark/light
"backgroundTextStyle": "light",
// 页面上拉触底事件触发时距离页面底部距离
"onReachBottomDistance": 50,
// 不允许页面上下滚动
"disableScroll": false,
// 页面方向
"pageOrientation": "auto"
}
路由方式 | 页面栈表现 | 触发时期 | 路由前页面 | 路由后页面 |
---|---|---|---|---|
初始化 | 新页面入栈 | 智能小程序打开的第一个页面 | onLoad, onShow | |
打开新页面 | 新页面入栈 | 调用 API swan.navigateTo 或使用组件 < navigator open-type=“navigateTo”/ > | onHide | onLoad, onShow |
页面重定向 | 当前页面出栈,新页面入栈 | 调用 API swan.redirectTo 或使用组件 < navigator open-type=“redirectTo”/ > | onUnload | onLoad, onShow |
页面返回 | 页面出栈 | 调用 API swan.navigateBack 或使用组件 < navigator open-type=“navigateBack”/ > 或用户按左上角返回按钮 | onUnload | onShow |
Tab 切换 | 页面全部出栈,只留下初始的 Tab 页面 | 调用 API swan.switchTab 或使用组件 < navigator open-type=“switchTab”/ > 或用户切换 Tab | 具体分析 | 具体分析 |
重加载 | 页面全部出栈,只留下新的页面 | 调用 API swan.reLaunch 或使用组件 < navigator open-type=“reLaunch”/ > | onUnload | onLoad, onShow |
说明:
path?key=value&key2=value2
,如果跳转的页面路径是 tabBar 页面则不能带参数。一个自定义组件由 4 个文件 (.swan .css .js .json) 组成
.json文件
{
"component": true
}
.swan文件
<view class="name" bindtap="tap">
{{name}}{{age}}
view>
.css文件
.name {
color: red;
}
.js文件
Component({
properties: {
// 定义了name属性,可以在使用组件时,由外部传入。此变量可以直接在组件模板中使用
name: {
type: String,
value: 'swan',
}
},
data: {
// 这里是一些组件内部数据
age: 1
},
methods: {
// 这里是一个自定义方法
tap: function(){}
}
})
页面在其json文件中引用,在swan中直接引用
// 页面json配置 home.json
{
"usingComponents": {
"custom": "/components/custom/custom"
}
}
<view>
<custom name="swanapp">custom>
view>
<view class="wrapper">
<slot>slot>
<view>组件内部节点view>
<slot name="slot1">slot>
<slot name="slot2">slot>
view>
<view>
<custom-component>
<view>这里是插入到组件slot中的内容view>
<view slot="slot1">我会被插入到组件上方view>
<view slot="slot2">我会被插入到组件下方view>
custom-component>
view>
<view class="component-range">
<slot name="inner" var-name="name">slot>
view>
<view>
<custom-component>
<view>{{name}}view>
custom-component>
view>
<view class="external-class">这段文本的颜色由组件外的 class 决定view>
<custom-component external-class="red-text" />
<text class="global-class">这段文本的颜色由组件外的 class 决定text>
// 组件内部模板
Component({
// 组件样式
externalClasses: ['external-class'],
// 全局样式类
options: {
addGlobalClass: true,
},
data: {
name: 'swan-inner'
}
});
/* 使用组件的页面或者组件 */
.red-text {
color: red;
}
.global-class {
color: red;
}
// 自定义组件js
Component({
// 组件的对外属性,是属性名到属性设置的映射表,属性设置中可包含三个字段,
// type 表示属性类型、
// value 表示属性初始值、
// observer 表示属性值被更改时的响应函数
properties: {
// 属性名
propName: {
// 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null
type: String,
// 属性初始值(必填)
value: 'val',
observer: function(newVal, oldVal) {
// 属性被改变时执行的函数(可选)
}
}
},
// 监听指定字段的数据发生改变时触发
observers: {
'some.subfield': function(subfield) {
// 使用 setData 设置 this.data.some.subfield 时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
subfield === this.data.some.subfield
},
'some.field.**': function(field) {
// 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
field === this.data.some.field
},
'**': function(value) {
// 数据发生变化即触发,这里的 value 是 properties 和 data 的合集
},
},
// 私有数据,可用于模板渲染
data: {},
// 类似于 mixins 和 traits 的组件间代码复用机制
behaviors: [],
// 组件接受的外部样式类
externalClasses: [],
// 一些选项
options:{},
// 组件生命周期声明对象,
// 组件的生命周期:created、attached、ready、detached 将收归到 lifetimes 字段内进行声明,
// 原有声明方式仍旧有效,如同时存在两种声明方式,则 lifetimes 字段内声明方式优先级最高
lifetimes: {},
// 组件所在页面的生命周期声明对象,目前仅支持页面的 show 和 hide 两个生命周期
pageLifetimes: {},
// 定义段过滤器,用于自定义组件扩展
definitionFilter: {},
// 生命周期函数:在页面初始化时执行
onInit: function () {},
// 生命周期函数:在组件实例刚刚被创建时执行,注意此时不能调用 setData
created: function () {},
// 生命周期函数: 在组件实例进入页面节点树时执行,可以为函数,或一个在methods段中定义的方法名
attached: function () {},
// 生命周期函数: 在组件布局完成后执行,此时可以获取节点信息
ready: function () {},
// 生命周期函数: 在组件实例被从页面节点树移除时执行
detached: function () {},
// 组件的方法,包括事件响应函数和任意的自定义方法
methods: {
onTap: function () {
this.setData({
// 更新属性和数据的方法与更新页面数据的方法类似
});
}
},
});
组件的通用属性和方法
属性
方法
// 1、通过 dispatch 方法与父组件通信
/* 父组件逻辑 */
Component({
messages: {
'childmessage': function (e) {
console.log('childmessage', e);
}
}
});
/* 子组件逻辑 */
Component({
created() {
this.dispatch('childmessage', {
name: 'swan'
});
}
});
// 2、通过 triggerEvent 方法与父组件通信
/* 组件child逻辑 */
/* */
Component({
properties: {},
methods: {
onTap: function() {
// detail对象,提供给事件监听函数
var myEventDetail = {}
// 触发事件的选项 bubbles:是否冒泡 capturePhase:事件是否拥有捕获阶段
var myEventOption = {bubbles:true}
this.triggerEvent('myevent', myEventDetail, myEventOption);
}
}
});
/* 使用该组件的页面 */
/* */
Page({
listener: function (e) {
console.log(e);
}
})
// 3、通过 this.selectComponent 方法获取子组件实例对象
<!-- 组件child页面 -->
<!-- <view>这是组件child</view> -->
<!-- 使用child的页面 -->
<!-- <child id="page-id">这是使用child</child> -->
// 使用该组件的逻辑
Page({
onLoad: function () {
const res = this.selectComponent('#page-id');
console.log(res);
}
});
自定义组件模板中的一些节点,其对应的自定义组件不是由自定义组件本身确定的,而是由自定义组件的调用者确定的。这时可以把这个节点声明为“抽象节点”。
例如,我们现在来实现一个“选框组”(selectable-group)组件,它其中可以放置单选框(custom-radio)或者复选框(custom-checkbox)
<view s-for="{{labels}}">
<label bindtap="itemTap" data-index="{{index}}">
<selectable disabled="{{false}}" selected="{{selected[index]}}" name="{{name}}">selectable>
{{item}}
label>
view>
<selectable-group generic:selectable="custom-radio" />
<selectable-group generic:selectable="custom-checkbox" />
<!-- selectable-group.json -->
{
"componentGenerics": {
"selectable": true,
// 可放个默认组件
"selectable": {
"default": "path/to/default/component"
}
}
}
<!--调用的组件或页面d的json文件-->
{
"usingComponents": {
"custom-radio": "path/to/custom/radio",
"custom-checkbox": "path/to/custom/checkbox"
}
}
<view>{{test}}view>
<view s-for="persons">{{index}}: {{item.name}}view>
<view s-for="p,index in persons">{{index}}: {{p.name}}view>
<view s-for="persons" s-for-index="idx" s-for-item="p">{{idx}}: {{p.name}}view>
<input s-for="list trackBy item" placeholder="请输入内容" />
<button bindtap="delete">删除首项button>
<view s-if="is4G">4Gview>
<view s-elif="isWifi">Wifiview>
<view s-else>Otherview>
<template name="person-card">
<view>
<text>位置: {{pos}}text>
<text>姓名: {{name}}text>
view>
template>
<template is="person-card" data="{{{...person}}}" />
<view class="view-more" data-swan="test" bind:tap="loadMore">点击加载更多view>
/* 事件的分类
** tap: 触摸后马上离开
** longtap: 触摸后超过 350ms 再离开(推荐使用 longpress 事件代替)
** longpress: 触摸后超过 350ms 再离开,如果是指定了事件回调函数并触发了这个事件,tap 事件将不被触发
** touchstart: 触摸开始时
** touchmove: 触摸后移动时
** touchend: 触摸结束时
** touchcancel: 触摸后被打断时,如来电等
** touchforcechange: 支持 3D Touch 的 iPhone 设备,重按时会触发
** transitionend: 会在 transition 或 swan.createAnimation 动画结束后触发
** animationstart: 会在 animation 动画开始时触发
** animationiteration: 会在 animation 一次迭代结束时触发
** animationend: 会在 animation 动画完成时触发
*/
/* 事件绑定和冒泡
** key以bind或catch开头,衔接事件类型,例如bindtapcatchtouchcancel。也可以在bind和catch后可以紧跟一个冒号,如bind:tap、catch:touchstart,其功能不变
** bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡
*/
/* 事件的捕获
** 捕获阶段是位于冒泡阶段之前,在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反
** 在捕获阶段监听的方式是采用capture-bind、capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段
** Tip:在安卓及开发者工具、Web 态特定浏览环境(早期浏览器),嵌套最内层元素 capture 与 bind 事件触发时机取决于模板中事件声明前后顺序,如果需要同时使用 capture 与 bind,需要保证其先后顺序避免导致触发顺序在不同平台不一致的问题。
*/
/* 事件对象
** type: 事件的类型
** timeStamp: 页面打开到触发事件所经过的毫秒数
** target: 触发事件的组件的属性值集合
** currentTarget: 当前组件的一些属性值集合
** detail: 自定义事件对象属性列表
** touches: 触摸事件类型存在,存放当前停留在屏幕中的触摸掉新增的数组
** changedTouches: 触摸事件类型存在,存放当前变化的触摸点信息的数组
*** 扩展1:target/currentTarget
**** dataset: 事件绑定的组件上由 data-开头的自定义属性组成的集合
**** id: 事件绑定组件的id
**** offsetTop: 元素向上偏移的像素值
**** offsetLeft: 元素向下偏移的像素值
*** 扩展2:detail
**** 是自定义事件所携带的数据,具体详见组件定义中各个事件的定义。
*** 扩展3:dataset
**** 在组件的事件被触发时,也可以传递自定义的数据
*** 扩展4:touch
**** identifier: 触摸点的标识符
**** clientX, clientY: 距离页面可显示区域(屏幕除去导航条)左上角的 X 轴与 Y 轴的距离
**** pageX, pageY: 距离文档左上角的 X 轴与 Y 轴的距离
*** 扩展5:changedTouch
**** 数据格式同 touches,指的是有变化的触摸点,如 touchstart(开始),touchmove(变化),touchend,touchcancel(结束)等
*/
/*
** 在JavaScript文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,且不会互相影响。
** 通过全局函数getApp()可以获取全局的应用实例,如果需要全局的数据可以在App()中设置
*/
/* 1、import */
<template name="A">
<text> A template text>
template>
<import src="../templateA/templateA.swan"/>
<template name="B">
<text> B template text>
template>
<template is="A"/>
<import src="../templateB/templateB.swan"/>
<template is="A"/>
<template is="B"/>
/* 2、include */
<include src="header.swan"/>
<view> body view>
<include src="footer.swan"/>
<view> header view>
<view> footer view>
// pages/utils.sjs中编写SJS逻辑
const bar = function(name) {
return 'swan-' + name;
}
const foo = 'hello swan';
export default {
bar: bar,
foo: foo
};
// 或者使用CMD的形式导出
// module.exports = {
// bar: bar,
// foo: foo
// };
<import-sjs src="../utils.sjs" module="utils" />
<view class="container">{{utils.bar(name)}}view>
<view>{{utils.foo}}view>
swan-sjs
hello swan
相关属性:
module: 当前
标签的模块名。必填字段
src: 引用.sjs
文件的路径,仅当本标签为单闭合标签或标签的内容为空时有效; 如果当做 sjs 代码容器标签,则不必填写。
注意:import-sjs
标签除了引用其它sjs
模块,还可直接作为SJS
代码的容器,使用module
制定该模块名称,用法与上等同。
<import-sjs module="utils">
const bar = function(name) {
return 'swan-' + name;
}
const foo = 'hello swan';
export default {
bar: bar,
foo: foo
};
import-sjs>
<view class="container">{{utils.bar(name)}}view>
<view>{{utils.foo}}view>
undefined
;// 在SJS模块中
var count = 110;
var bar = 'hello swan';
// undef === undefined
var undef;
const NAME = 'SJS';
let str = 'string';
变量命名必须符合下面两个规则:
// pages/utils/sjs
// const NAME = 'sjs';
/**
* let str = 'swan';
*/
与 javascript 一致
与 javascript 一致
if语句、switch语句、for语句、while语句
SJS
语言目前共有以下几种数据类型:
方法
推荐使用功能更全的 SJS 功能。Filter 功能将不再更新,请勿在
s-if
、s-for
、template
、自定义组件等标签中使用。
Filter 是小程序的过滤器,结合 SWAN 模板,可以构建出页面的结构。
<view> {{swan.message()}} view>
<filter module="swan">
export default {
message: function() {
return 'Hello world';
}
}
filter>
<view>{{swan.maxin(array)}}view>
<filter src="./index.filter.js" module="swan">filter>
// index.js
Page({
data: {
array: [1, 3, 6, 8, 2, 0]
}
});
// index.filter.js
export default {
maxin: arr => {
var max = undefined;
for (var i = 0; i < arr.length; ++i) {
max = max === undefined ?
arr[i] :
(max >= arr[i] ? max : arr[i]);
}
return max;
}
};