字节跳动小程序 【开发】 自学总结
准备
- 微信小程序开发文档 官网
由于字节跳动小程序很类似微信小程序,但是文档的详细程度却差一些,所以需要微信小程序开发文档做对照
开发阶段
目录结构同微信小程序类似,app.json 为全局设置。
- 认证注意事项
企业开发者:适用于企业,个体工商户,政府组织,海外机构等其他机构。每个企业主体可以验证【 10 个企业小程序 】。
特别注意:认证主体后续需与支付主体、广告结算主体保持一致
此外,如果在广告中心开通了激励广告需要注意
1. 目前激励视频广告仅支持抖音端,接入需判断接入宿主及宿主版本, 在不支持的宿主及版本上需要将结果直接展示给用户。
2. 展示广告前向用户说明激励广告规则,明确告知用户看完视频广告后能获得相应奖励。
3. 一个页面最多出现一个激励视频广告。
4. 需要用户主动操作点击按钮,才能创建和获取激励视频广告。
5. 需判断广告异常情况,如不支持激励视频的低版本用户、广告调用失败等情况,应直接给予奖励。
全局设置
- 如增加Tab需要设置图标,
图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,当 postion 为 top 时,此参数无效,不支持网络图片
"tabBar": {
"color":"#666666",
"selectedColor":"#2a76ff",
"backgroundColor":"#FFF",
"list": [
{
"pagePath": "pages/index/index",
"text": "标题1",
"iconPath":"pages/resource/images/icon1.png",
"selectedIconPath":"pages/resource/images/icon1_ac.png"
},
{
"pagePath": "pages/second/index",
"text": "标题2",
"iconPath":"pages/resource/images/icon3.png",
"selectedIconPath":"pages/resource/images/icon3_ac.png"
}
]
}
- 页面跳转分为标签跳转和程序跳转
标签跳转
<navigator
url="navigate?title=navigate"
hover-class="navigator-hover"
>
...
</navigator>
navigator-hover 默认为 {background-color: rgba(0, 0, 0, 0.1); opacity: 0.7;},<navigator/>的子节点背景色应为透明色。
2-0-1. 删除 navigator 默认点击样式
法1
.navigator-hover { background-color:rgba(0,0,0,0); opacity:1;}
法2
<navigator hover-class="none" url="..."></navigator>
程序跳转
tt.navigateTo({
url: '/pages/match_expert/index?planid='+_planId, //绝对路径
url: '../match_expert/index?planid='+_planId, //相对路径
success(res) {
console.log(`${res}`);
},
fail(res) {
console.log(`navigateTo调用失败`);
}
});
【注】: 不能跳转到 TabBar 页面
2-0. 跳转到TabBar的方法
tt.switchTab({
url: '../my/index',
success(res){},
fail(err){
console.log(err);
console.log(`navigateTo调用失败`);
}
});
2-1. 跳转只要到达对应文件夹即可,不用指定到xxx.ttml
2-2. 获取跳转的get参数 , 在被跳转页的js文件,生命周期onload参数中获取
onLoad: function(option){
let pageId = option.detailId || "";
if(pageId){
//获取信息
this.getMes(pageId);
}
}
2-3. 如果需要跳转的页面,在app.json中的tabBar内,则需要使用
tt.switchTab({
url: `pages/my`,
success(res){},
fail(err) {
console.log(`switchTab调用失败`);
}
});
2-4. 返回上一页,如果目标页面为非TAB页,则可以使用
tt.navigateBack({
delta: 1,
success(res) {
console.log(`${res}`);
},
fail(res) {
console.log(`navigateBack调用失败`);
},
});
-
小程序对Javascript语法的支持程度
-
模块化,提取公共脚本
导出
// common.js
function hello(name) {
console.log(`Hello ${name} !`);
}
module.exports.hello = hello;
导入
var common = require("common.js");
Page({
helloWorld: function() {
common.hello("world");
}
})
- 标签有限,基本这三个就够用了
view - div text - span image - img
5-1. 如果渲染的文本内包含html标签,则需要使用rich-text。官方连接文档
如:
<rich-text nodes="{{someData}}"></rich-text>
-
布局单位与实际操作
单位 rpx 据说可以根据屏幕比例变化
| 设备 | rpx 换算 px (屏幕宽度/750) | px 换算 rpx (750/屏幕宽度) |
| iPhone6 | 1rpx = 0.5px | 1px = 2rpx |
建议:
设计师可以用 iPhone6 作为视觉稿的标准。
即使用PSD尺寸为750px的设计稿,然后1:1测量,单位使用rpx即可 -
图片标签新裁切属性属性,同web中CSS3的object-fit
7-1. 如果希望图片宽度100%,高度自适应,
则需要给图片添加mode="widthFix"和样式 width;100% 即可,
如果不设置mode="widthFix",高度样式不设置,那么会图片会走默认的系统预制高度
如果不设置mode="widthFix",高度样式设置auto,那么高度为0
两种都不是图片高度自适应
<image src="../resource/images/banner.jpg" mode="widthFix" />
7-2. 如果希望固定宽高内,不镂空,则需要图片设置宽高尺寸后,使用 mode使用aspectFill
即可
-
渲染转译符 增加属性decode
<view><text decode> </text></view> -
调试工具缓存有时候很大,通过开发者工具清除缓存按钮不好使,直接退出再重进,即可
9-1. setData给对象内属性赋值
Page({
data: {
gameData:{
level:0, //评价等级
totalScore:0, //总分数
questionIndex:0 //当前题目
}
}
});
设置数据
this.setData({
['gameData.totalScore']: 1000
});
9-2. setData给对象内属性赋值,且子对象为变量
data:{
totalMatchData:[ [],[],[],[],[] ]
}
//indexNum为数组索引,且为变量
var _mdata = 'totalMatchData['+indexNum+']';
_that.setData({
[_mdata]: xxx
});
BUG:这种方式如果设置多个动态数据,只有最后一个会生效???!!!!
- 返回顶部 按钮怎么操作页面
- 针对scroll-view
可以使用重置这个属性的值 scroll-into-view ,值为页面上目标点的元素的id即可,注意这个元素必须是 scroll-view 包含结构内的
注:
如果元素的在底部触发了bindscrolltolower触底行为,通过scroll-into-view指向这个元素的ID,
会将scorll-view拉回到这个元素位置,但是其实这样做,会多滚动一屏的高度,需要修正这个位置
所以,可以在这个元素上添加position:absolute定位元素到 负一屏的高度,如果还有偏差可以用padding做二次修正
补充:
- 对于<scroll-view> 必须要添加一个高度限制,否则效果不会生效
- 指定锚点元素的id (不能以数字开头)
- 如果在<scroll-view>内动态添加循环元素,该组件会回到 scrollTop 为 0 的位置,需要将 scroll-view 组件的全部子元素包裹一层 view 可避免该问题 (官方提示)
- 锚点ID元素可以放置在循环元素内部
//--- ttml
<!-- scroll-view -->
<scroll-view
class="scrollViewBox"
scroll-y
scroll-with-animation
scroll-into-view="{{returnTopEle}}"
>
<view class="mainTopShow style2Box">
<!--阵容-->
<text id="topEleTar"></text>
<include src="../../resource/template/match_detail_2.ttml" />
</view>
</scroll-view>
//--- js
data: {
returnTopEle:"topEleTar"
},
returnFn(){
this.setData({
returnTopEle:"topEleTar"
});
}
- 针对非scroll-view
使用API
tt.pageScrollTo({
scrollTop: 0,
duration: 1000,
success(res) {
//console.log(`pageScrollTo调用成功`);
},
fail(res) {
console.log(`pageScrollTo调用失败`);
}
});
-
网络请求需要配置白名单 位置
特别注意:线上环境,网络请求仅支持 https 协议的 URL -
小程序点击,不支持事件处理函数传参,带上参数会认定整体为 函数名,报错未定义
解决通过自定义属性
<view class="selectBtns pos1 ac" bindtap="selectClickFn" data-index="1">
<view class="selectBtn1Bg">
<text>罗纳尔多</text>
</view>
</view>
事件处理函数默认参数为事件对象,通过其可以过得自定义属性
selectClickFn(ev){
console.log(ev.currentTarget.dataset.index); //1
}
12-1. 阻止事件冒泡的行为要通过修改事件本身来做,不支持修饰符,不支持事件对象stopPropagation
如
触摸点击事件: bind
tap --> catch
tap 即可
小程序中存在冒泡的事件:

注:
事件绑定后没有反应的情况,可能是以下情况
- text标签内嵌套text标签,在里面的text上绑定事件,无法触发
- canvas在小程序(非小游戏)中,存在开发工具渲染正常,真机尺寸错误的情况
表现 以 iphone6 为基准绘制的页面,在iphone7 plus上表现 canvas变小,在小米5上表现 canvas变大
因此需要对canvas绘图尺寸进行二次修改
如:
tt.getSystemInfoSync().windowWidth -- 真机宽度
tt.getSystemInfoSync().windowHeight -- 真机高度
开发者工具中,如选择iphone6为开发参照,则获取设备宽高做参照
以iphone6为例
375 -- 模拟器上宽度
603 -- 模拟器上高度
在真机上,模拟器数据需要修正的比例值
宽度修正比例值 = 真机宽度 / 模拟器上宽度
高度修正比例值 = 真机高度 / 模拟器上高度
【实操】: iphoneX修正异常、如果修正后的高度大于宽度,需要调整高度为宽度的数值
再次测试,iPhone与小米真机表现一致了

-
小程序支持的canvas属性 字节跳动小程序官网
-
小程序图片预加载
循环数组数据创建图片,通过图片的bindload
与binderror
的变化,来判断加载进度与是否加载完毕,
暂时没有发现new Image()
或类似 小游戏的tt.createImage
的东西
<!-- ttml -->
<!--加载图片-->
<view class="onlyLoadImgArr">
<view tt:if="{{allImgArr}}" tt:for="{{allImgArr}}" tt:for-index="idx" tt:key="*this">
<image bindload="bindloadFn" binderror="binderrorFn" src="{{item}}" >
</view>
</view>
<!--js-->
//图片加载
bindloadFn(res){
let _that = this;
if(res.type=="load"){
loadNum+=1;
this.setData({
allImgLoad:Math.floor(loadNum/sumLoadNum*100)
});
if(loadNum==sumLoadNum){
this.setData({
allLoadText:'加载完毕'
});
setTimeout(function(){
_that.setData({
scene:2
});
},800);
}
}
},
binderrorFn(err){
console.log('图片加载错误');
console.log(err);
}
- 音频
- 分为背景音频
const backgroundAudioManager = tt.getBackgroundAudioManager();
backgroundAudioManager.src = "https://xxx/0000-0001.mp3";
BackgroundAudioManager.play();
BackgroundAudioManager.pause();
BackgroundAudioManager.stop();
//音频加载回调
BackgroundAudioManager.onWaiting(function callback)
//音频播放中
paused --- boolean | 当前音频是否处于暂停状态,只读
- 普通音频
const innerAudioContext = tt.createInnerAudioContext();
innerAudioContext.src = "https://someaudiourl";
innerAudioContext.volume = 0.5; //范围 0~1。默认为 1 只读
innerAudioContext.onPlay(() => {
console.log("开始播放回调");
});
innerAudioContext.pause();
InnerAudioContext.stop();
- 动画 animate.css 需要修改下后缀名 如 .ttss
<!--触发动画-->
<view class="{{scene==2? 'bounce animated':' '}}"></view>
- 获取 基础库版本 (' 论坛提交问题需要基础库版本号 ');
所有参数
//获取基础库版本
tt.getSystemInfo({
success(res) {
console.log(res.SDKVersion);
}
});
- 全局数据的获取与设置
在app.js中
//获取
onLaunch: function () {
console.log(this.globalData.some_data); // 10
},
//全局数据
globalData: {
some_data:10
},
...
//设置
this.globalData.some_data= 1000;
在非app.js中
const app = getApp()
//获取
console.log(app.globalData.some_data);
//设置
app.globalData.some_data = 1000;
- 获取自定义属性
20-1. 在非组件标签上挂载属性时候,可以使用event.currentTarget.dataset.index
来获取;
//--ttml
<view class="nav" data-index="100" bindtap="navClickFn">
<text>按钮1</text>
</view>
//--js
function navClickFn(event){
if(typeof event.currentTarget.dataset.index!= 'undefined'){
let _index = event.currentTarget.dataset.index;
console.log(_index); //100
}
}
20-2.获取组件
区别与使用普通标签,在组件上挂载data属性,可以使用 event.target.dataset.index
来获取; 如: pinker组件
- 导入ttml模板
<include src="../../resources/ttml/header.ttml" />
- InnerAudioContext与BackgroundAudioManager冲突,音效会终止BackgroundAudioManager背景音
解决的方法:
将背景音频(BackgroundAudioManager)用音效(InnerAudioContext)代替,
//背景音函数
let bgsrc = 'https://www.aaa.com/bgm1.mp3';
function createBGMObj(_src){
var bgmOb = tt.createInnerAudioContext();
bgmOb.src = _src;
bgmOb.autoplay = true;
bgmOb.loop = true;
//音频加载中
bgmOb.onWaiting(function(res){ });
//音频可播放
bgmOb.onCanplay(function(){
bgmOb.play();
});
return bgmOb;
};
const gameBGM = createBGMObj(bgsrc);
if(!gameBGM.paused){
this.setData({
bgmBtnStatue:true //音频播放的UI类名
});
gameBGM.stop && gameBGM.stop();
console.log('暂停');
}else{
this.setData({
bgmBtnStatue:false //音频暂停的UI类名
});
gameBGM.play && gameBGM.play();
console.log('播放');
}
- 小程序轮播图指示点颜色 ( 默认: indicator-color ,选中:indicator-active-color)
更多参数配置
<swiper
indicator-dots="true"
indicator-color="rgba(255,255,255,0.5)"
indicator-active-color="#f60"
autoplay="true"
interval="3000"
duration="500"
>
<block tt:for="{{bannerResult}}">
<swiper-item>
<view class="swiper-item">
<image src="{{item.list_pic}}" mode="aspectFill" />
<text class="mes">{{item.title}}</text>
</view>
</swiper-item>
</block>
</swiper>
- 修改swiper容器高度
//--ttml
<view class="bannerBox">
<swiper
indicator-dots="true"
indicator-color="rgba(0,0,0,0.5)"
indicator-active-color="#f60"
>
...
//--ttss
.homePage .ourCup .bannerBox -- 包裹swiper容器高度
.homePage .ourCup .bannerBox tt-swiper -- swiper自身高度
- 背景图
样式中使用本地背景图,可以将背景图文件与app.json同级,然后通过
background:url('resource/image/bell.png') no-repeat left top;
或者使用 base64、或者网络图片
- 下载远程图片至本机相册
//--- ttml
<button type="primary" bindtap="downloadImgFn">下载</button>
//--- js
downloadImgFn(){
var _src = 'https://www.xxx.com/upload/images/temp/3.d5aabd23.jpg'
tt.getImageInfo({
src: _src,
success(res) {
var _path = res.path
tt.saveImageToPhotosAlbum({
filePath: _path,
success(res) {
console.log(`saveImageToPhotosAlbum调用成功`);
},
fail(res) {
console.log(`saveImageToPhotosAlbum调用失败`);
}
});
}
});
}
26-1. 方式2,通过 tt.downloadFile 下载网络图片至本地缓存,获取tempFilePath,然后通过
tt.saveImageToPhotosAlbum,配置上参数tempFilePath,下载至本地相册
这个过程中会询问用户相册的权限,此外需要配置下载文件白名单
且白名单为https协议,不能加端口号,否则失效

-
组件 switch
修改背景色 使用 属性 color设置
修改大小,使用transform:scale(xxx) 调整 -
定位为fixed的元素不要放在scroll-view中,真机不会生效(不像模拟器)
-
表单输入框、文本域限制字数
ttml
<view class="topArea">
<textarea
class="textareaBox"
placeholder="请输入您的意见或建议"
placeholder-style="color:#c9c9c9;"
bindinput="textareaInputFn"
bindblur="textareaBlurFn"
value="{{txtValue1}}"
maxlength="{{limitNum1}}"
/>
<view class="textareaBtm">
<text>{{txtLength1}}/{{limitNum1}}</text>
</view>
</view>
js
data: {
txtValue1:'',
txtLength1:0,
limitNum1:100
},
textareaInputFn(event){
var txtObj = event.detail;
var _txt = txtObj.value;
var _txtLength = txtObj.cursor;
if(_txt.length == this.data.limitNum1){
commonTool.showPop('字数已经达到上限');
}
//限制字数
var _txt2 = _txt.substring(0,this.data.limitNum1);
var _txtLength2 = _txt2.length;
//事件对象属性修改
txtObj.value = _txt2;
txtObj.cursor = _txtLength2;
this.setData({
txtValue1: _txt2,
txtLength1: _txtLength2
});
},
textareaBlurFn(event){},
注:textarea不像input,无法通过setData来改变绑定其上的value数据,真实限制字数通过maxlength属性生效
29-1. event.detail.cursor 为光标位置
通过输入框光标位置,也可以判断字数达到上限与否
if(event.detail.cursor > 40){
...do something
}
29-2. 表单 input 的type 可以设置多种
值 | 说明 | 最低支持版本 |
---|---|---|
text | 文本输入键盘 | 1.0.0 |
number | 数字输入键盘 | 1.0.0 |
digit | 带小数点的数字键盘 | 1.0.0 |
-
真机与模拟器在include上渲染不一
模拟器可以使用<include src="../../resource/template/xxx.ttml" />,引入模板文件;
但是在真机上无法完成渲染,
解决方法,将内容从include中拿出来 -
纯文本中存在
\r\n
,需要渲染出换行效果,
pre-wrap : 保留空白符序列,但是正常地进行换行。
<view style="white-space:pre-wrap">
{{item.scoreTabData.description}}
</view>
-
tt:for操作报错
Polymer::Attributes: couldn't decode Array as JSON:
解决方法,
修改循环单位名字 如: tt:for-item="seasonItem" -
多重三目运算
matchInsetItem.status=='Uncertain'?'待定':(matchInsetItem.status=='Postponed'?'推迟':(matchInsetItem.status=='Played'?'结束':''))
-
swiper与按钮联动
点击按钮,切换swiper的current,联动触发swiper其bindchange事件,
相反的,切换swiper,并不会触发按钮的bindtap事件,
所以关联是单向的,最终会体现在swiper的bindchange上
因此,为了防止swiper中嵌套scroll-view后,纵向滑动scroll-view引起事件,触发swiper横向操作误判
可以操作索引后,仅在swiper的bindchange上,开启延迟定时器,触发事件 -
【优化】
tt:if 显示隐藏 -- 渲染成本高 [ 初始化渲染使用,不频繁显示消失 ]
通过样式控制显示隐藏 -- 渲染成本低 [ 频繁切换显示、消失使用 ] -
隐藏loading,弹出toast,存在冲突
loading 的实现基于 toast,所以hideLoading也会将 toast 隐藏。
解决:
app.showPop('登录成功',400);
setTimeout(()=>{
app.hideLoadPop();
},800);
- 授权被拒,无法拉起再次授权
常规情况下,是主观还是意外拒绝授权后,是无法再次拉起授权的。需要退出小程序,二次进入,才可重新打开授权
但是,可以通过openSetting,来拉起,( 设置页面只包含用户请求过的权限 )
tt.openSetting({
success:function(res){
... 内部逻辑
},
fail:function(err){
...
}
});
37-1. 授权被拒后,内部逻辑,可以根据用户最新授权变化,再进行业务
具体的授权列表
tt.openSetting({
success:function(res){
if(res.authSetting['scope.userInfo']){
//再次登录逻辑
}
},
fail:function(err){
...
}
});
- 上传图片
(第一步).需要拉起本地相册,【需要用户授权】
tt.chooseImage({
sourceType: ["album"],
count:1,
success(res) {
this.setData({
imagePath: res.tempFilePaths[0],
imageFile: res.tempFiles[0]
});
},
fail(res) {
console.log(`chooseImage调用失败`);
}
});
(第二步).上传文件
let fileTask = tt.uploadFile({
url: _baseUrl+'api/file',
filePath: (上一步的imagePath),
name: "file",
success(res) {
if(res.statusCode === 200){
//将用户头像在数据库内修改
....
}
},
fail(err){
console.log(err);
console.log(`uploadFile调用失败`);
}
});
38-1. 上传图片分为2步操作,选择图片部分可以一次选择多张,但是上传图片目前API只支持单张上传
-
输入框修改内容如何优化
通过bindinput修改数据,但是不要使用setData,降低设置数据性能消耗,将其值存在变量中
在bindblur时候,进行setData,将变量赋值到对应数据上去;
此外bindblur时候setData需要时间,不是立即完成的,所以需要开启延迟定时器,再去setData -
版本更新
要点:1.需要做低版本兼容 2.上一个版本需要有此代码,此代码才有反应,否则没有返回
//获取版本信息
if(tt.getUpdateManager){
var updateManager = tt.getUpdateManager();
updateManager.onCheckForUpdate(function(res) {
// 请求完新版本信息的回调
console.log("onCheckForUpdate", res.hasUpdate);
if (res.hasUpdate) {
tt.showToast({
title: "即将有更新请留意"
});
}
});
updateManager.onUpdateReady(() => {
tt.showModal({
title: "更新提示",
content: "新版本已经准备好,是否立即使用?",
success: function(res) {
if (res.confirm) {
// 调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate();
} else {
tt.showToast({
icon: "none",
title: "小程序下一次「冷启动」时会使用新版本"
});
}
}
});
});
updateManager.onUpdateFailed(() => {
tt.showToast({
title: "更新失败,下次启动继续..."
});
});
}else{
tt.showModal({
title: "提示",
content:
"当前客户端版本过低,无法使用该功能,请升级客户端或关闭后重启更新。"
});
}
- 生命周期
- navigateTo, redirectTo 只能打开非 tabBar 页面。
- switchTab 只能打开 tabBar 页面。
- reLaunch 可以打开任意页面。
同级AB栏目之间的 TAB切换
A ~> B A.onHide(), B.onLoad(), B.onShow()
C ~> A C为A详细页 C.onUnload(), A.onShow()
一般情况,先onload,后续同级TAB切换为onShow ; TAB进去非TAB详细页则,触发onLoad,onShow
- 跳转返回上一步
tt.redirectTo不能跳转到 TabBar 页面
但是 redirectTo方法生成的页面,可以返回到 TabBar 页面
backBtnFn(){
tt.navigateBack({
delta: 1,
success(res) {
// console.log(`${res}`);
},
fail(res) {
console.log(`navigateBack调用失败`);
}
});
}
- 下拉刷新、上拉加载
(1).配置app.json中window属性,enablePullDownRefresh 与 onReachBottomDistance
"window":{
"navigationBarTextStyle":"black",
"navigationBarBackgroundColor": "#fff",
"backgroundTextStyle": "dark",
"navigationBarTitleText": "xxxxxxx",
"enablePullDownRefresh": true,
"onReachBottomDistance":50
},
(2).在页面的js中配置
//下拉刷新
onPullDownRefresh(){
console.log('onPullDownRefresh');
tt.stopPullDownRefresh();
},
//上拉加载
onReachBottom(){
console.log('加载下一页');
}
(3).不能使用scroll-view组件,需要使用普通view
(4).返回顶部,使用tt.pageScrollTo()
- 分享
(1). 按钮的分享
(2).<button open-type="share">转发到微头条</button>
(3). 后台配置分享与等待审核
(4). js页面内配置 onShareAppMessage 事件处理函数
Page({
...
onShareAppMessage (option) {
// option.from === 'button'
return {
title: '这是要转发的小程序标题',
desc: '这是默认的转发文案,用户可以直接发送,也可以在发布器内修改',
path: '/pages/index/index?from=sharebuttonabc&otherkey=othervalue', // ?后面的参数会在转发页面打开时传入onLoad方法
imageUrl: 'https://e.com/e.png', // 支持本地或远程图片,默认是小程序 icon
templateId: '这是开发者后台设置的分享素材模板id',
success () {
console.log('转发发布器已调起,并不意味着用户转发成功,微头条不提供这个时机的回调');
},
fail () {
console.log('转发发布器调起失败');
}
}
},
onLoad (query) {
if (query.from === 'sharebuttonabc') {
// do something...
}
}
});
- 关于登录授权流程
先使用tt.login获取临时登录code凭证,在把code、appid、secret发送后台,获取openid(openid 是用户的唯一标识)
后台流程地址
获取openid
-
企业级账号中 webview配置
首先,开发设置 - webview域名 - 下载检验文件
其次,将授权文件放置在需要配置域名的根路径下,确保可以通过域名+检验文件,可以访问文件内容即可 -
同时一次同时设置多个数据,如果涉及缓动动画与表单焦点聚焦,可能会引起渲染问题,
解决方式,先设置有动画的数据,再添加一个演示定时器,设置获取焦点的数据 -
浮层上有表单,如果设置点击空白区域使浮层消失,那么点击表单输入(bindinput),会引起冒泡行为,造成浮层关闭。
解决方法:
第一步,通过设置表单的焦点数据(focus),以及丢失焦点事件(bindfocus),在点击浮层之外的空白区域时候,判断输入框是否存在焦点状态(focus数据情况),如果存在就不要做浮层消失,否则就叫浮层消失
第二步,表单输入框失去焦点事件中(bindfocus),将表单的焦点属性数据(focus)重置,使浮层可以被正常关闭
解决方法2:百度一下,未解决
给表单元素添加catchtap事件,事件处理函数为空,但是效果是,表单无法输入文字了,???? -
scroll-view 如果希望其内部横向无限滚动,只需要设置两个样式
其一,scroll-view容器设置 width:100%;
其二,scroll-view内部包裹一个滚动元素,为其设置 display:inline-block; white-space:nowrap; -
页面滚动,导航的吸顶效果
准备:
第一,判断方法存在与否 if(tt.createSelectorQuery){ ... }
说明:
一般新增的 api 在低版本基础库上是不存在的,贸然调用会导致错误。建议做如下判断:
if (tt.navigateToMiniProgram) {
tt.navigateToMiniProgram();
} else {
tt.showModal({
title: "提示",
content:
"当前客户端版本过低,无法使用该功能,请升级客户端或关闭后重启更新。",
});
}
第二,在一个web-view中绑定滚动事件 bindscroll="scrollFn"
第三,在滚动事件中,调用选择元素的方法,判断其距离顶部距离
然后改变数据,渲染导航fixed类名存在与否
if(domQuery){
domQuery.select('#filterhead').boundingClientRect(rect=>{
// console.log(rect.top);
if(rect.top<=0){
if(!_isFilterFixed){
_that.setData({
"isFilterFixed":true
});
}
}else{
if(_isFilterFixed){
_that.setData({
"isFilterFixed":false
});
}
}
}).exec();
}
第四,注意尽量节流,添加判断条件,除非必要,否则不要setData吸顶与否的类名
否则,由于滚动事件触发频率极快,因此即使设置的是相同的数据,也会造成导航在状态之间切换,因为setData也是需要消耗时间的,且这个时间可能要大于触发事件的间隔频率
- 组件配置
第一,先配置【子组件】信息,新建对应的ttml、ttss、js、json
组件json需要配置
{
"component": true
}
组件的js内要设置组件信息
Component({
properties: {
//通过父组件属性,传递至子组件内的数据
diyattr: {
type: String,
value: "默认标题文案",
}
},
data:{
// 组件内部数据
defaultStates: { ... }
},
methods:{
// 自定义方法,可以将数据100通过自定义事件'myevent',传递给父组件
fn1(){
this.triggerEvent(
'myevent', '传递的数据', ‘配置的数据(bubbles、composed、capturePhase)’
)
}
}
});
链接:配置事件选项
第二,配置【父组件】信息,新建对应的json
配置组件简称与路径
{
"usingComponents": {
"my-component": "/components/test/index"
}
}
在ttml内使用组件
<my-component
diyattr="传递给子组件内的数据~"
bindmyevent="子组件自定义事件名myevent"
class="comp {{isShow?'compShow':''}}"
>
<view>通过slot传递到子组件内的数据</view>
</my-component>
如果配置了json,如果不写东西,会报错
所以得写点什么
{ "component": false }
{ "usingComponents": {} }
在自定义事件bindmyevent的事件处理函数中,通过event的detail获取传递的数据
51-1. 自定义组件无法使用全局样式,则在组件js中配置
options: {
addGlobalClass: true
}
即可
51-2. 组件无法使用组件外样式,在组件内样式,只能使用当前组件上的类名
有些样式不允许在组件内使用
Some selectors are not allowed in component ttss, including ID selectors, and attribute selectors
- 作用域 js
第一、导出js,声明 文件夹 /resources/js/md5.js
...xxxx....
module.exports.hex_md5 = hex_md5;
第二、引入js,在/app.js中
let mdjs = require("/resources/js/md5.js");
App({
md5Fn(str){
return mdjs.hex_md5(str);
}
})
第三、外部页面使用 js中
app.md5Fn('xxxx')
css作用域:将外部css引入app.ttss
/** app.ttss **/
@import "common.ttss";
-
两个非TAB页面之间跳转,数据状态不同步
如:
详细页通过路由(tt.navigateBack)返回列表页,在列表页触发了onShow钩子函数,但是数据不会重新加载
这样会引起一个问题:
如果详细页点击取消关注,返回列表页,不会重新渲染,因为数据有缓存,列表页不会重新渲染
解决方法:
将关注列表内容放到localStorge内,如果有操作关注的东西,及时改变localStorage,来作为变化参照凭证 -
二级联动pinker组件,TAB页面之间跳转,会出现问题
表现: 是联动数据一级内容,为之前某二级列表内容,而非标题
解决: 页面,onshow生命周期 重置联动pinker初始索引 -
转发与分享
第一步,开发者后台配置小程序分享,过审后,获得分享ID
第二步,添加标签
<button open-type="share">转发到微头条</button>
第三部,配置分享触发生命周期函数 官方示例 -- 配置参数,其中包括上面获得的分享ID参数 -
支付接入
先获取订单orderid、再获取orderInfo(后台返回),最后调用tt.pay
其中orderInfo里的 risk_info是字符串格式,里面是json,注意符号 ' 与 " 的使用。
risk_info: "{'ip':'xxx.xxx.xxx.xxx'}"
支付宝官方工具:
通过orderInfo内的alipay_url,可以查询支付宝支付,能否拉起。
-
浮层上如果有一个textarea, 如果通过修改class类名方式,控制浮层的显示与消失,那么textarea会不显示文字,且无法获得焦点,拉起手机键盘。
解决方法,通过tt:if 来控制显示层的显示与隐藏,那么textarea就可以操作了 -
在小程序中,使用第三方客服拆件,用于聊天功能
方法一,其核心是调用小程序官方组件<button type='default' open-type='contact'> 打开客服 </button>
:
芝麻小客服 接入引导视频
芝麻小客服 官方链接地址
客服按钮配置
方法二,其核心是使用webview
芝麻小客服 接入引导视频
小程序需要企业账号(需上传校验文件至服务器根目录,完成校验),且三方平台必须是付费用户才可以设置自定义域名(付费用户包括标准版、专业版、企业版等付费版本)
配置自定义域名--官方连接
自定义域名也可以传递参数
- 微信小程序迁移字节跳动小程序
提前申请一个字节小程序,获取appid,开发者工具迁移按钮,依照要求输入微信小程序项目地址、字节小程序输出地址、appid、小程序名即可进行迁移
后续工作:
手动进行的语法转化
1. tt:for-items 修改为 tt:for ; tt:key修改为tt:for-index="idx";
2. navigator跳转,在pages下的页面需要在app.json中注册,但是微信小程序好像在pages下二级文件夹文件无需配置,这个在字节跳动小程序不行
3. 组件不一样,如pinker
-
小程序 时间对象 开发工具正常,但是iphone真机报错
new Date("2019-07-24 19:57") 应该写成 new Date("2019/07/24 19:57")
需要对时间字符串处理下,如 new Date(tm.replace(/-/g,'/')) -
图片预览的轮播API 地址
预览一组图片,可以理解为一个封装好的 图片pop banner
62.通过抖音挂载能力,可以抖音发布小视频时候,挂载小程序。
这一功能需要提前申请

代码内调用 ( 仅针对当前页面有效,属于二次修改分享内容,默认分享是开发者后台首次申请的配置文案 )
onShareAppMessage (option) {
// option.from === 'button'
return {
title: app.globalData.shareMes.tit,
desc: app.globalData.shareMes.txt,
path: app.globalData.shareMes.path, // ?后面的参数会在转发页面打开时传入onLoad方法
imageUrl: '', // 支持本地或远程图片,默认是小程序 icon
templateId: app.globalData.shareMes.templateId,
success(){
//console.log('转发发布器已调起,并不意味着用户转发成功,微头条不提供这个时机的回调');
},
fail(){
console.log('转发发布器调起失败');
}
}
}
......占位,填坑........