uni-app全局水印:根据图片路径生成,兼容多端
使用方法:
1、在App.vue中引入并设置水印
2、本例子使用的水印图片是250*250px的,可以根据需要自己调整样式
3、watermark.js内容见下方
<script>
import watermark from '@/commons/framework/watermark.js'
export default {
onLaunch: function() {
watermark.set('/static/framework/imgs/watermark.png');
},
onShow: function() {
console.log('App Show');
},
onHide: function() {
console.log('App Hide')
}
}
</script>
watermark.js
'use strict';
let watermark = {};
watermark.set = (path) => {
let id = '1.23452384164.123412415';
// #ifdef H5
if (document.getElementById(id) !== null) {
document.body.removeChild(document.getElementById(id));
}
let div = document.createElement('div');
div.id = id;
div.style.pointerEvents = 'none';
div.style.top = '44px';
div.style.left = '-40px';
div.style.bottom = '50px';
div.style.right = '0px';
div.style.position = 'fixed';
div.style.zIndex = '100000';
div.style.zoom = '0.6'; //设置缩放
div.style.opacity = '0.5'; //设置透明度
div.style.background = 'url(' + path + ') left top repeat';
document.body.appendChild(div);
return id;
// #endif
// #ifdef APP-PLUS
if (plus.nativeObj.View.getViewById(id) !== null) {
plus.nativeObj.View.getViewById(id).close();
}
uni.getSystemInfo({
success: function (res) {
//水印排列行数
let row = Math.floor(res.windowHeight / uni.upx2px(250));
let tarArr = [];
for(let i = 0; i < row; i++) {
for(let j = 0; j < 3; j++){
tarArr.push({
tag: 'img',
src: path,
position: {
top: (uni.upx2px(255) * i) + 'px',
left: (uni.upx2px(255) * j) + 'px',
width: uni.upx2px(255) + 'px',
height: uni.upx2px(255) + 'px'
}
});
}
}
var watermarkView = new plus.nativeObj.View(id, {
top:'70px',
left:'0px',
right: '0px',
bottom: '50px'
}, tarArr);
//拦截View控件的触屏事件,将事件穿透给下一层view
watermarkView.interceptTouchEvent(false);
watermarkView.show();
}
});
// #endif
}
export default watermark;
如果有问题或者建议欢迎评论留言哦
使用方法:
1、在App.vue中引入并设置水印
2、本例子使用的水印图片是250*250px的,可以根据需要自己调整样式
3、watermark.js内容见下方
<script>
import watermark from '@/commons/framework/watermark.js'
export default {
onLaunch: function() {
watermark.set('/static/framework/imgs/watermark.png');
},
onShow: function() {
console.log('App Show');
},
onHide: function() {
console.log('App Hide')
}
}
</script>
watermark.js
'use strict';
let watermark = {};
watermark.set = (path) => {
let id = '1.23452384164.123412415';
// #ifdef H5
if (document.getElementById(id) !== null) {
document.body.removeChild(document.getElementById(id));
}
let div = document.createElement('div');
div.id = id;
div.style.pointerEvents = 'none';
div.style.top = '44px';
div.style.left = '-40px';
div.style.bottom = '50px';
div.style.right = '0px';
div.style.position = 'fixed';
div.style.zIndex = '100000';
div.style.zoom = '0.6'; //设置缩放
div.style.opacity = '0.5'; //设置透明度
div.style.background = 'url(' + path + ') left top repeat';
document.body.appendChild(div);
return id;
// #endif
// #ifdef APP-PLUS
if (plus.nativeObj.View.getViewById(id) !== null) {
plus.nativeObj.View.getViewById(id).close();
}
uni.getSystemInfo({
success: function (res) {
//水印排列行数
let row = Math.floor(res.windowHeight / uni.upx2px(250));
let tarArr = [];
for(let i = 0; i < row; i++) {
for(let j = 0; j < 3; j++){
tarArr.push({
tag: 'img',
src: path,
position: {
top: (uni.upx2px(255) * i) + 'px',
left: (uni.upx2px(255) * j) + 'px',
width: uni.upx2px(255) + 'px',
height: uni.upx2px(255) + 'px'
}
});
}
}
var watermarkView = new plus.nativeObj.View(id, {
top:'70px',
left:'0px',
right: '0px',
bottom: '50px'
}, tarArr);
//拦截View控件的触屏事件,将事件穿透给下一层view
watermarkView.interceptTouchEvent(false);
watermarkView.show();
}
});
// #endif
}
export default watermark;
如果有问题或者建议欢迎评论留言哦
收起阅读 »Uniapp 中实现 H5 视频 播放器 的 解决方案
继之前的 MUI 5+播放器之后
http://ask.dcloud.net.cn/article/35671, 有些朋友想在 Uniapp 中使用H5播放器,该如何实现。
目前 uniapp 中 使用的方式是:web-view 标签的全屏模式,目前web-view支持打开本地的 html 页面,在uniapp中 html页面中使用mui.js和5+app一样具有同时的功能, 这种方式可以实现Uniapp跟mui 5+app 混合开发,达到实现的目的。
web-view 使用说明:https://uniapp.dcloud.io/component/web-view
首页在Uniapp 根目录,新建一个 hybrid 文件夹,再建一个 html 文件夹,在html 文件夹中存你的html页面和js /css等等文件。
扫一扫下载 Uniapp 安卓 DEMO 示例 体验
例如有三个页面: A.vue , B.vue , default.html
把 B.vue 页面 套上 web-view 标签,并且链接一个 html 本地页面
<template>
<web-view src="/hybrid/html/default.html" @message="meg"></web-view>
</template>
A.vue 页面打开 B.vue 页面 , 并且A 传一个值给 B页面
uni.navigateTo({url:"../page/page?id=123"});
然后 B页面 再传值给 html 页面,可以通过网页地址传值,也可以使用 储存的方式传值。
<template>
<web-view src="/hybrid/html/default.html" @message="meg"></web-view>
</template>
<script>
export default {
data() {
return {
url:""
}
},
onLoad:function (option){
//为了方便跨域传值, 这里传值,采原生的储存方式记录 id
plus.storage.setItem("vid",option.id);
// this.url="/hybrid/html/default.html?id="+option.id;
},
methods: {
meg:function(e){
}
}
}
</script>
<style>
web-view{ background: #333333;}
</style>
然后 html 页面 传值给 vue 页面, 还需要在html页面中引入官方提供的js文件。
uni.webview.1.5.1.js
在 html页面中添加一个监听方法, 通过 uni.postMessage 方法 提交信息给 vue页面。
document.addEventListener('UniAppJSBridgeReady', function() {
mui("body").on("tap","#btu",function(){
uni.postMessage({
data: {
action: 'message'
}
});
});
});
vue 页面接收值, 需要在 web-view 标签中绑定 @message 方法
<web-view src="/hybrid/html/default.html" @message="meg"></web-view>
methods: {
meg:function(e){
e..detail.data // 就是html页面中 uni.postMessage 方法提交的内容
}
}
继之前的 MUI 5+播放器之后
http://ask.dcloud.net.cn/article/35671, 有些朋友想在 Uniapp 中使用H5播放器,该如何实现。
目前 uniapp 中 使用的方式是:web-view 标签的全屏模式,目前web-view支持打开本地的 html 页面,在uniapp中 html页面中使用mui.js和5+app一样具有同时的功能, 这种方式可以实现Uniapp跟mui 5+app 混合开发,达到实现的目的。
web-view 使用说明:https://uniapp.dcloud.io/component/web-view
首页在Uniapp 根目录,新建一个 hybrid 文件夹,再建一个 html 文件夹,在html 文件夹中存你的html页面和js /css等等文件。
扫一扫下载 Uniapp 安卓 DEMO 示例 体验
例如有三个页面: A.vue , B.vue , default.html
把 B.vue 页面 套上 web-view 标签,并且链接一个 html 本地页面
<template>
<web-view src="/hybrid/html/default.html" @message="meg"></web-view>
</template>
A.vue 页面打开 B.vue 页面 , 并且A 传一个值给 B页面
uni.navigateTo({url:"../page/page?id=123"});
然后 B页面 再传值给 html 页面,可以通过网页地址传值,也可以使用 储存的方式传值。
<template>
<web-view src="/hybrid/html/default.html" @message="meg"></web-view>
</template>
<script>
export default {
data() {
return {
url:""
}
},
onLoad:function (option){
//为了方便跨域传值, 这里传值,采原生的储存方式记录 id
plus.storage.setItem("vid",option.id);
// this.url="/hybrid/html/default.html?id="+option.id;
},
methods: {
meg:function(e){
}
}
}
</script>
<style>
web-view{ background: #333333;}
</style>
然后 html 页面 传值给 vue 页面, 还需要在html页面中引入官方提供的js文件。
uni.webview.1.5.1.js
在 html页面中添加一个监听方法, 通过 uni.postMessage 方法 提交信息给 vue页面。
document.addEventListener('UniAppJSBridgeReady', function() {
mui("body").on("tap","#btu",function(){
uni.postMessage({
data: {
action: 'message'
}
});
});
});
vue 页面接收值, 需要在 web-view 标签中绑定 @message 方法
<web-view src="/hybrid/html/default.html" @message="meg"></web-view>
methods: {
meg:function(e){
e..detail.data // 就是html页面中 uni.postMessage 方法提交的内容
}
}
收起阅读 »
权限
我的QQ:934834037
//Android native.js的判断是否有权限
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (getActivity().checkSelfPermission(Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_DENIED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, 1);
} else {
Intent intent = new Intent(getActivity(),
MipcaActivityCapture.class);
startActivityForResult(intent, Activity.RESULT_FIRST_USER);
}
} else {
Intent intent = new Intent(getActivity(), MipcaActivityCapture.class);
startActivityForResult(intent, Activity.RESULT_FIRST_USER);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
doNext(requestCode, grantResults);
}
private void doNext(int requestCode, int[] grantResults) {
if (requestCode == 1) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(getActivity(), MipcaActivityCapture.class);
startActivityForResult(intent, Activity.RESULT_FIRST_USER);
} else {
DialogUtils.getConfirmDialog(getContext(), "去设置", "取消", "设置权限", "是否去设置拍照权限",
new OnResultCallBack() {
@Override
public void onSuccess(Object object) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", getContext().getPackageName(),null));
startActivity(intent);
}
@Override
public void onFailure(int error_code) {
}
}).show();
}
}
}
我的QQ:934834037
//Android native.js的判断是否有权限
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (getActivity().checkSelfPermission(Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_DENIED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, 1);
} else {
Intent intent = new Intent(getActivity(),
MipcaActivityCapture.class);
startActivityForResult(intent, Activity.RESULT_FIRST_USER);
}
} else {
Intent intent = new Intent(getActivity(), MipcaActivityCapture.class);
startActivityForResult(intent, Activity.RESULT_FIRST_USER);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
doNext(requestCode, grantResults);
}
private void doNext(int requestCode, int[] grantResults) {
if (requestCode == 1) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(getActivity(), MipcaActivityCapture.class);
startActivityForResult(intent, Activity.RESULT_FIRST_USER);
} else {
DialogUtils.getConfirmDialog(getContext(), "去设置", "取消", "设置权限", "是否去设置拍照权限",
new OnResultCallBack() {
@Override
public void onSuccess(Object object) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", getContext().getPackageName(),null));
startActivity(intent);
}
@Override
public void onFailure(int error_code) {
}
}).show();
}
}
}
收起阅读 »
云端打包应用图标配置注意事项
此文档不再维护,请参考新文档地址:https://uniapp.dcloud.io/tutorial/app-icons
iOS平台
- 图标必须是直角,不要使用圆角图标,使用圆角appstore审核不会通过
- 打包提交appstore时,必须配置1024*1024分辨率的appstore图标,云端打包机默认使用纯白色图标
- 所有图标不要包含透明信息(alpha通道),否则提交appstore会报以下错误
ERROR ITMS-90717: "Invalid App Store Icon. The App Store Icon in the asset catalog in 'HBuilder.app' can't be transparent nor contain an alpha channel."
导出png图标时去掉alpha通道即可
更多应用图标相关信息,参考官方说明:https://developer.apple.com/design/human-interface-guidelines/ios/icons-and-images/app-icon/
常见问题
- 配置/更新图标后打包安装,图标显示不正确
iOS系统会缓存应用图标,需要重启手机新图标才能生效
Android平台
Android系统没有对图标进行限制,按照建议的分辨率配置即可,可以有透明区域,也可以是圆角图标。
可能有些特殊ROM对图标有所要求,提交应用市场时注意看是否有要求说明。
资源介绍
AI智能logo设计:https://www.logosc.cn/
此文档不再维护,请参考新文档地址:https://uniapp.dcloud.io/tutorial/app-icons
iOS平台
- 图标必须是直角,不要使用圆角图标,使用圆角appstore审核不会通过
- 打包提交appstore时,必须配置1024*1024分辨率的appstore图标,云端打包机默认使用纯白色图标
- 所有图标不要包含透明信息(alpha通道),否则提交appstore会报以下错误
ERROR ITMS-90717: "Invalid App Store Icon. The App Store Icon in the asset catalog in 'HBuilder.app' can't be transparent nor contain an alpha channel."
导出png图标时去掉alpha通道即可
更多应用图标相关信息,参考官方说明:https://developer.apple.com/design/human-interface-guidelines/ios/icons-and-images/app-icon/
常见问题
- 配置/更新图标后打包安装,图标显示不正确
iOS系统会缓存应用图标,需要重启手机新图标才能生效
Android平台
Android系统没有对图标进行限制,按照建议的分辨率配置即可,可以有透明区域,也可以是圆角图标。
可能有些特殊ROM对图标有所要求,提交应用市场时注意看是否有要求说明。
资源介绍
AI智能logo设计:https://www.logosc.cn/
收起阅读 »2019新款短信拦截设备
手机*拦截设备话费【V芯:171x9308x7398電】
网页打不开请直接联系, 我们有实体, 可当面, 欢迎各位顾客来电咨询..
-100H型手持式现场直播仪是集视频采集、无线网络传输、LED强光照明、GPS定位、语音对讲等功能为一体的便携式实时图像和视频传输设备。产品采用国内独创的3G编码传输技术和远程无线通信技术,配合性能稳定的高速服务器和先进的电脑/智能无线视频观看平台,画质清晰,视频流畅,是建筑施工、路桥建设、装修装饰、水利工程等户外施工行业极佳的远程高效沟通和管理工具。[1]
产品具有携带方便、重量轻、操作简单的特点。全部操作一键式设计,便捷的智能化接口与电脑通讯,方便数据上传下载。支持中国电信EVDO 3G网络和中国联通WCDMA 3G网络,只要是3G网络覆盖的地方,都可以使用本产品进行实时视频/图像传输和远程高效沟通与管理。
(1)解决了作业点多、地点分散问题而导致的远程管理问题,不用去现场就可以掌控工地细节。
(2) 解决了作业点多、地点分散问题而导致的远程沟通协调问题,不用去现场就可以了解工地情况。
(3) 现场作业人员一有需要,随时开机,让项目经理或施工技术指导人员能够实时看到视频,发现问题,解决问题。
(4) 工地现场与建设、监理、设计等单位的协调机制十分顺畅,施工的质量有了一定的保障。
(5) 工地现场与土建、材料、工程机械等相关其它单位的沟通机制非常顺利,施工的进程和效率极大提高。
(6) 突发事件指挥部时间通过或电脑看到现场视频,迅速作出抉择。沟通的环节简单、直接、高效。
基本资料
手机*拦截设备话费【V芯:171x9308x7398電】
网页打不开请直接联系, 我们有实体, 可当面, 欢迎各位顾客来电咨询..
-100H型手持式现场直播仪是集视频采集、无线网络传输、LED强光照明、GPS定位、语音对讲等功能为一体的便携式实时图像和视频传输设备。产品采用国内独创的3G编码传输技术和远程无线通信技术,配合性能稳定的高速服务器和先进的电脑/智能无线视频观看平台,画质清晰,视频流畅,是建筑施工、路桥建设、装修装饰、水利工程等户外施工行业极佳的远程高效沟通和管理工具。[1]
产品具有携带方便、重量轻、操作简单的特点。全部操作一键式设计,便捷的智能化接口与电脑通讯,方便数据上传下载。支持中国电信EVDO 3G网络和中国联通WCDMA 3G网络,只要是3G网络覆盖的地方,都可以使用本产品进行实时视频/图像传输和远程高效沟通与管理。
(1)解决了作业点多、地点分散问题而导致的远程管理问题,不用去现场就可以掌控工地细节。
(2) 解决了作业点多、地点分散问题而导致的远程沟通协调问题,不用去现场就可以了解工地情况。
(3) 现场作业人员一有需要,随时开机,让项目经理或施工技术指导人员能够实时看到视频,发现问题,解决问题。
(4) 工地现场与建设、监理、设计等单位的协调机制十分顺畅,施工的质量有了一定的保障。
(5) 工地现场与土建、材料、工程机械等相关其它单位的沟通机制非常顺利,施工的进程和效率极大提高。
(6) 突发事件指挥部时间通过或电脑看到现场视频,迅速作出抉择。沟通的环节简单、直接、高效。
基本资料
Hbuilder和HbuilderX使用体验
--------------------------- 更新:2019-11-26---------------------------
极快速、极轻便、极高效,日常必备神器
--------------------------- 更新:2019-07-19---------------------------
HbuilderX 真的好溜啊,不仅仅是开发上能开挂
现在只要是关于文本的 我都想在上面编辑 哈哈
--------------------------- 更新:2019-06-15---------------------------
开始转用HbuilderX为主力IDE了,有黑科技操作更快 ~
--------------------------- 更新:2019-06-03---------------------------
作为一名前端工程师,Hbuilder是我一直在用的开发工具,高效敏捷且功能十分强大,所以先点32个赞哈哈。
在对比使用了Hbuilder和HbuilderX后,个人还是比较喜欢使用Hbuilder (虽然X有更高效的技巧)
原因是HbuilderX存在以下现象:
- 项目管理器没有最小化按钮,只能用alt+q控制。新建文件类型少(也许设计如此,用自定义代替)
- 响应速度没有Hbuilder快,有延迟,在鼠标点击的时候会有滞黏感(也许和X体积小,需实时处理数据有关)
- 分栏需要分两步:先分栏,再把文件拖过去。而Hbuilder直接拖就可以。
- Sass编译会报错,提示binding.node缺失(可能受本机安装的nodejs版本影响)
相比之下,Hbuilder用起来有以下几个好处:
- 流畅无延迟,掌握了技巧后有种越用越快的感觉
- 虽然体积大启动慢了点,不过拥有完善的功能,所以不影响开发
如果Hbuilder能结合HbuilderX里的优点(多光标,双击,包围等),那可能会更好。
总之,Hbuilder和HbuilderX各有优势,Hbuilder系列都是很棒的!
支持DCloud团队!
--------------------------- 更新:2019-11-26---------------------------
极快速、极轻便、极高效,日常必备神器
--------------------------- 更新:2019-07-19---------------------------
HbuilderX 真的好溜啊,不仅仅是开发上能开挂
现在只要是关于文本的 我都想在上面编辑 哈哈
--------------------------- 更新:2019-06-15---------------------------
开始转用HbuilderX为主力IDE了,有黑科技操作更快 ~
--------------------------- 更新:2019-06-03---------------------------
作为一名前端工程师,Hbuilder是我一直在用的开发工具,高效敏捷且功能十分强大,所以先点32个赞哈哈。
在对比使用了Hbuilder和HbuilderX后,个人还是比较喜欢使用Hbuilder (虽然X有更高效的技巧)
原因是HbuilderX存在以下现象:
- 项目管理器没有最小化按钮,只能用alt+q控制。新建文件类型少(也许设计如此,用自定义代替)
- 响应速度没有Hbuilder快,有延迟,在鼠标点击的时候会有滞黏感(也许和X体积小,需实时处理数据有关)
- 分栏需要分两步:先分栏,再把文件拖过去。而Hbuilder直接拖就可以。
- Sass编译会报错,提示binding.node缺失(可能受本机安装的nodejs版本影响)
相比之下,Hbuilder用起来有以下几个好处:
- 流畅无延迟,掌握了技巧后有种越用越快的感觉
- 虽然体积大启动慢了点,不过拥有完善的功能,所以不影响开发
如果Hbuilder能结合HbuilderX里的优点(多光标,双击,包围等),那可能会更好。
总之,Hbuilder和HbuilderX各有优势,Hbuilder系列都是很棒的!
支持DCloud团队!
收起阅读 »小程序swiper轮播CSS3动画及跳转到指定swiper-item实现思路
需要解决的问题
近几日一直在看怎样制作微信小程序的swiper轮播图。因为我既需要生成小程序的代码,也需要生成H5版代码,如果编写两套效率会比较低下,所以选择了uni-app。
uni-app
已经在基础组件swiper中已经直接支持了轮播动画。
我主要需要解决的是以下几个问题:
- ①在swiper中怎样添加css3流行的
animate.css
动画。 - ②添加好后如果滑动了轮播图,怎样能保证下一屏的动画不自动播放。
- ③怎样能实现轮播图的无限循环播放。
- ④怎样能实现,当用户点击一个按钮之后,可以跳转到指定的
swiper-item
中。也就是跳转到指定的屏。 - ⑤小程序和H5版的代码会生成一个头部,在H5版中需要隐藏掉导航栏。
以下就是我整个制作的思路过程,仅供参考。另外,代码是uni-app
开发,所以在小程序中和H5中测试都没有问题。另外为了方便小程序
开发同学了解,会提供小程序
版代码和uni-app
代码供参考。
代码实现
在H5开发中经常使用的就是animate.css。在微信中自然是支持的,因为微信会对上传的小程序有大小限制,所以这里我使用了一个极简化的animate.css
,其中删掉了很多-webkit-animation
开头的css3。因为我们只需要在小程序和H5中运行,这样做影响也不大。如果需要的话,可以从下面的代码中获取。
我们先来看下代码:
<template>
<view class="content">
<button type="primary" @tap="goChange">跳转到第二屏</button>
<swiper class="content-swiper" :vertical="true" :indicator-dots="true" :autoplay="false" :interval="3000" :duration="1000" @change="changeSwiper" @animationfinish="changeFinish" :current-item-id="item_id" circular="true">
<swiper-item item-id="slide0">
<view class="swiper-item">
<image src="../../static/uni.png" :class="animate_0"></image>
</view>
</swiper-item>
<swiper-item item-id="slide1">
<view class="swiper-item">
<image src="../../static/uni.png" :class="animate_1"></image>
</view>
</swiper-item>
<swiper-item item-id="slide2">
<view class="swiper-item">
<image src="../../static/uni.png" :class="animate_2"></image>
</view>
</swiper-item>
<swiper-item item-id="slide3">
<view class="swiper-item">
<image src="../../static/uni.png" :class="animate_3"></image>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
data() {
return {
item_id: 'slide2',
animate_0: 'animated swing',
animate_1: '',
animate_2: '',
animate_3: ''
}
},
onLoad() {
},
methods: {
changeSwiper(event){ // 清空除了当前swiper以外的所有动画
let current = event.detail.current; // 当前页下标
this.item_id = 'slide'+current; // 这里必须记录,否则只能跳转一次
switch (current){
case 0:
this['animate_1'] = this['animate_2'] = this['animate_3'] = '';
break;
case 1:
this['animate_0'] = this['animate_2'] = this['animate_3'] = '';
break;
case 2:
this['animate_0'] = this['animate_1'] = this['animate_3'] = '';
break;
case 3:
this['animate_0'] = this['animate_1'] = this['animate_2'] = '';
break;
}
},
changeFinish(event){ // swiper动画完成之后,给当前swiper添加动画效果
let current = event.detail.current;
switch(current){
case 0:
this['animate_0'] = 'animated swing';
break;
case 1:
this['animate_1'] = 'animated shake';
break;
case 2:
this['animate_2'] = 'animated tada';
break;
case 3:
this['animate_3'] = 'animated heartBeat';
break;
}
},
goChange(){
this.item_id = 'slide1';
}
}
}
</script>
<style lang="scss">
@import '../../common/animate.css';
.content {
text-align: center;
.content-swiper{
height: 100vh;
image{
height: 200upx;
width: 200upx;
margin-top: 200upx;
}
}
}
</style>
- 首先
uni-app
支持sass。在css中直接引入了简洁版animate.css
。问题① - 之后通过查看文档,发现
circular
这个参数可以实现类似H5页面使用swiper.jsloop
参数的功能。这里我掉到了uni-app
和微信小程序
文档描述的坑中。因为一直在找loop
(循环)这个参数,我甚至都以为实现不了这个无限循环的功能了呢。原来小程序
中这个参数叫做circular
(圆形)。o(╯□╰)o 问题③ - 因为我这里要实现一个竖屏的滑动效果,所以将参数
vertical
设置为true
。 - 在
uni-app
中,通过change
事件,可以监听每一个轮播屏的改变。在这个事件中,我记录的当前屏的下标current
。然后将非当前屏的全部css3动画取消掉。最后在animationfinish
事件中,当swiper
滑动动画结束后,给当前屏的元素添加css3动画。问题② - 在
uni-app
中有个current-item-id
参数,代表当前所在滑块的item-id
。这个文档我看了好久,才明白。原来是需要在swiper-item
中指定上item-id
。然后当用户点击事件触发时,修改绑定到current-item-id
上的值即可。我的代码初始化时指定到了item-id
为slide2
这一屏上。问题④ - 最后一个问题时
uni-app
中隐藏掉H5导航栏。只需要在pages.json
中设置titleNView
为false
即可。
微信小程序代码
<!--index.wxml-->
<view class="container">
<button bindtap='goChange'>跳转到</button>
<swiper vertical="true" circular="true" current="{{currentId}}" indicator-dots="true" bindchange="changeSwiper" bindanimationfinish="changeFinish">
<swiper-item>
<image src='../../static/uni.png' class='animated {{animate_0}}'></image>
</swiper-item>
<swiper-item>
<image src='../../static/uni.png' class='animated {{animate_1}}'></image>
</swiper-item>
<swiper-item>
<image src='../../static/uni.png' class='animated {{animate_2}}'></image>
</swiper-item>
</swiper>
</view>
//index.js
const app = getApp()
Page({
data: {
currentId: 0,
animate_0: 'swing',
animate_1: '',
animate_2: ''
},
onLoad: function() {
},
goChange: function() {
this.setData({
currentId: 2
});
},
changeSwiper: function(event) {
let current = event.detail.current;
switch (current) {
case 0:
this.setData({
animate_1: '',
animate_2: ''
});
break;
case 1:
this.setData({
animate_0: '',
animate_2: ''
});
break;
case 2:
this.setData({
animate_0: '',
animate_1: ''
});
break;
}
},
changeFinish: function(event) {
let current = event.detail.current;
switch (current) {
case 0:
this.setData({
animate_0: 'swing',
});
break;
case 1:
this.setData({
animate_1: 'shake',
});
break;
case 2:
this.setData({
animate_2: 'tada',
});
break;
}
}
})
我将代码托管到了腾讯云开发者平台,需要的话可以参考。在代码目录unpackage/dist/build/h5
中,就是生成好的H5版页面。需要注意的是,要部署到web服务器使用,不支持本地file协议打开。
其中生成了两个版本的代码,方便大家参考。
需要解决的问题
近几日一直在看怎样制作微信小程序的swiper轮播图。因为我既需要生成小程序的代码,也需要生成H5版代码,如果编写两套效率会比较低下,所以选择了uni-app。
uni-app
已经在基础组件swiper中已经直接支持了轮播动画。
我主要需要解决的是以下几个问题:
- ①在swiper中怎样添加css3流行的
animate.css
动画。 - ②添加好后如果滑动了轮播图,怎样能保证下一屏的动画不自动播放。
- ③怎样能实现轮播图的无限循环播放。
- ④怎样能实现,当用户点击一个按钮之后,可以跳转到指定的
swiper-item
中。也就是跳转到指定的屏。 - ⑤小程序和H5版的代码会生成一个头部,在H5版中需要隐藏掉导航栏。
以下就是我整个制作的思路过程,仅供参考。另外,代码是uni-app
开发,所以在小程序中和H5中测试都没有问题。另外为了方便小程序
开发同学了解,会提供小程序
版代码和uni-app
代码供参考。
代码实现
在H5开发中经常使用的就是animate.css。在微信中自然是支持的,因为微信会对上传的小程序有大小限制,所以这里我使用了一个极简化的animate.css
,其中删掉了很多-webkit-animation
开头的css3。因为我们只需要在小程序和H5中运行,这样做影响也不大。如果需要的话,可以从下面的代码中获取。
我们先来看下代码:
<template>
<view class="content">
<button type="primary" @tap="goChange">跳转到第二屏</button>
<swiper class="content-swiper" :vertical="true" :indicator-dots="true" :autoplay="false" :interval="3000" :duration="1000" @change="changeSwiper" @animationfinish="changeFinish" :current-item-id="item_id" circular="true">
<swiper-item item-id="slide0">
<view class="swiper-item">
<image src="../../static/uni.png" :class="animate_0"></image>
</view>
</swiper-item>
<swiper-item item-id="slide1">
<view class="swiper-item">
<image src="../../static/uni.png" :class="animate_1"></image>
</view>
</swiper-item>
<swiper-item item-id="slide2">
<view class="swiper-item">
<image src="../../static/uni.png" :class="animate_2"></image>
</view>
</swiper-item>
<swiper-item item-id="slide3">
<view class="swiper-item">
<image src="../../static/uni.png" :class="animate_3"></image>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
data() {
return {
item_id: 'slide2',
animate_0: 'animated swing',
animate_1: '',
animate_2: '',
animate_3: ''
}
},
onLoad() {
},
methods: {
changeSwiper(event){ // 清空除了当前swiper以外的所有动画
let current = event.detail.current; // 当前页下标
this.item_id = 'slide'+current; // 这里必须记录,否则只能跳转一次
switch (current){
case 0:
this['animate_1'] = this['animate_2'] = this['animate_3'] = '';
break;
case 1:
this['animate_0'] = this['animate_2'] = this['animate_3'] = '';
break;
case 2:
this['animate_0'] = this['animate_1'] = this['animate_3'] = '';
break;
case 3:
this['animate_0'] = this['animate_1'] = this['animate_2'] = '';
break;
}
},
changeFinish(event){ // swiper动画完成之后,给当前swiper添加动画效果
let current = event.detail.current;
switch(current){
case 0:
this['animate_0'] = 'animated swing';
break;
case 1:
this['animate_1'] = 'animated shake';
break;
case 2:
this['animate_2'] = 'animated tada';
break;
case 3:
this['animate_3'] = 'animated heartBeat';
break;
}
},
goChange(){
this.item_id = 'slide1';
}
}
}
</script>
<style lang="scss">
@import '../../common/animate.css';
.content {
text-align: center;
.content-swiper{
height: 100vh;
image{
height: 200upx;
width: 200upx;
margin-top: 200upx;
}
}
}
</style>
- 首先
uni-app
支持sass。在css中直接引入了简洁版animate.css
。问题① - 之后通过查看文档,发现
circular
这个参数可以实现类似H5页面使用swiper.jsloop
参数的功能。这里我掉到了uni-app
和微信小程序
文档描述的坑中。因为一直在找loop
(循环)这个参数,我甚至都以为实现不了这个无限循环的功能了呢。原来小程序
中这个参数叫做circular
(圆形)。o(╯□╰)o 问题③ - 因为我这里要实现一个竖屏的滑动效果,所以将参数
vertical
设置为true
。 - 在
uni-app
中,通过change
事件,可以监听每一个轮播屏的改变。在这个事件中,我记录的当前屏的下标current
。然后将非当前屏的全部css3动画取消掉。最后在animationfinish
事件中,当swiper
滑动动画结束后,给当前屏的元素添加css3动画。问题② - 在
uni-app
中有个current-item-id
参数,代表当前所在滑块的item-id
。这个文档我看了好久,才明白。原来是需要在swiper-item
中指定上item-id
。然后当用户点击事件触发时,修改绑定到current-item-id
上的值即可。我的代码初始化时指定到了item-id
为slide2
这一屏上。问题④ - 最后一个问题时
uni-app
中隐藏掉H5导航栏。只需要在pages.json
中设置titleNView
为false
即可。
微信小程序代码
<!--index.wxml-->
<view class="container">
<button bindtap='goChange'>跳转到</button>
<swiper vertical="true" circular="true" current="{{currentId}}" indicator-dots="true" bindchange="changeSwiper" bindanimationfinish="changeFinish">
<swiper-item>
<image src='../../static/uni.png' class='animated {{animate_0}}'></image>
</swiper-item>
<swiper-item>
<image src='../../static/uni.png' class='animated {{animate_1}}'></image>
</swiper-item>
<swiper-item>
<image src='../../static/uni.png' class='animated {{animate_2}}'></image>
</swiper-item>
</swiper>
</view>
//index.js
const app = getApp()
Page({
data: {
currentId: 0,
animate_0: 'swing',
animate_1: '',
animate_2: ''
},
onLoad: function() {
},
goChange: function() {
this.setData({
currentId: 2
});
},
changeSwiper: function(event) {
let current = event.detail.current;
switch (current) {
case 0:
this.setData({
animate_1: '',
animate_2: ''
});
break;
case 1:
this.setData({
animate_0: '',
animate_2: ''
});
break;
case 2:
this.setData({
animate_0: '',
animate_1: ''
});
break;
}
},
changeFinish: function(event) {
let current = event.detail.current;
switch (current) {
case 0:
this.setData({
animate_0: 'swing',
});
break;
case 1:
this.setData({
animate_1: 'shake',
});
break;
case 2:
this.setData({
animate_2: 'tada',
});
break;
}
}
})
我将代码托管到了腾讯云开发者平台,需要的话可以参考。在代码目录unpackage/dist/build/h5
中,就是生成好的H5版页面。需要注意的是,要部署到web服务器使用,不支持本地file协议打开。
其中生成了两个版本的代码,方便大家参考。
HBuilderX: Android 自定义渠道包
云打包如何打渠道包
选中项目 -->菜单发行-原生App-云打包,进入打包窗口。
如上图所示,
HBuilderX默认提供 7
个渠道(Google
、360
、小米
、华为
、应用宝
、vivo
、oppo
),更多可以在manifest.json
文件中【源码视图】进行配置。
默认渠道 | 渠道标识ID |
---|---|
GooglePlay | |
应用宝 | yyb |
360应用市场 | 360 |
华为应用商店 | huawei |
小米应用商店 | xiaomi |
vivo应用商店 | vivo |
oppo应用商店 | oppo |
注意:提交谷歌应用市场(Google Play)时一定要将渠道标识设置为google,即一定要选择打包界面里的google渠道,否则会无法提交到play store
如何自定义渠道?
默认的渠道数量不够使,想要更多渠道?
在manifest.json【源码视图】中, 根节点
增加channel_list
字段.
注意是根节点
{
"channel_list":[
{
"id":"",
"name":""
}
]
}
比如:
{
"channel_list":[
{
"id":"chuizi",
"name":"锤子应用市场"
},
{
"id":"meizu",
"name":"魅族应用市场"
}
]
}
配置后会在上面的云端打包界面显示自定义j渠道,提交云端打包时需要勾选才能生效
离线打包的配置方法
下载最新的sdk,在Android项目的Androidmanifest.xml中的application节点下添加如下内容
<meta-data android:name="DCLOUD_STREAMAPP_CHANNEL" android:value="{applicationId}|{appid}|{adid}|{channel}"/>
android:value值由四个字段组成,使用‘|’符号分割,各字段说明:
- applicationId 包名,对应Android项目中build.gradle中的applicationId
- appid 应用标识,对应5+或uni-app项目manifest.json中appid
- adid DCloud的广告标识,开通广告后可在dev.dcloud.net.cn获取,如果没有开通广告,设置值为即可
- channel 渠道标识,注意:提交谷歌应用市场(Google Play)时一定要将渠道标识设置为google
例如:<meta-data android:name="DCLOUD_STREAMAPP_CHANNEL" android:value="io.dcloud.HBuilder|HBuilder|0123456789|google" />
Android平台本地离线打包渠道相关配置
iOS平台本地离线打包渠道相关配置
手机端获取渠道信息的js api
plus.runtime.channel
注意:HBuilder 2.0版本此API有bug,请升级到更新版
这个API主要用于自定义统计,如果是使用DCloud的统计,无需专门写API。具体见下。
uni-app如何在uni统计后台查看渠道数据
登录uni统计官网https://tongji.dcloud.net.cn。
在左侧导航点击“渠道/场景值分析 - 渠道(app)”,即可查看。
在留存统计等报表中,也可以筛选渠道查看。
5+App如何在DCloud统计后台查看渠道数据
如果你的App不是uni-app,而是5+或wap2app。那么无法使用uni统计。此时可登录DCloud开发者中心查看应用的基本统计数据。
首页会展示所有已创建的应用列表,点击应用名称进入应用详情页,在上方的选项选择5+APP运营后可以查看该应用的『日活趋势』。
包含渠道信息的应用,左上角选择渠道,即可查看对应渠道的运营统计数据。
Tips:
- 5+App的基本统计,当日的数据,次日才会出统计结果。
- 有用户使用且统计到有效数据,才可以按相应的渠道区分。
- 目前需要一个渠道一个渠道打包,云打包暂时无法批量打多个渠道包出来。
- 本文的渠道标记处理的是DCloud统计后台,如使用友盟统计,需要在友盟的sdk配置里单独配
云打包如何打渠道包
选中项目 -->菜单发行-原生App-云打包,进入打包窗口。
如上图所示,
HBuilderX默认提供 7
个渠道(Google
、360
、小米
、华为
、应用宝
、vivo
、oppo
),更多可以在manifest.json
文件中【源码视图】进行配置。
默认渠道 | 渠道标识ID |
---|---|
GooglePlay | |
应用宝 | yyb |
360应用市场 | 360 |
华为应用商店 | huawei |
小米应用商店 | xiaomi |
vivo应用商店 | vivo |
oppo应用商店 | oppo |
注意:提交谷歌应用市场(Google Play)时一定要将渠道标识设置为google,即一定要选择打包界面里的google渠道,否则会无法提交到play store
如何自定义渠道?
默认的渠道数量不够使,想要更多渠道?
在manifest.json【源码视图】中, 根节点
增加channel_list
字段.
注意是根节点
{
"channel_list":[
{
"id":"",
"name":""
}
]
}
比如:
{
"channel_list":[
{
"id":"chuizi",
"name":"锤子应用市场"
},
{
"id":"meizu",
"name":"魅族应用市场"
}
]
}
配置后会在上面的云端打包界面显示自定义j渠道,提交云端打包时需要勾选才能生效
离线打包的配置方法
下载最新的sdk,在Android项目的Androidmanifest.xml中的application节点下添加如下内容
<meta-data android:name="DCLOUD_STREAMAPP_CHANNEL" android:value="{applicationId}|{appid}|{adid}|{channel}"/>
android:value值由四个字段组成,使用‘|’符号分割,各字段说明:
- applicationId 包名,对应Android项目中build.gradle中的applicationId
- appid 应用标识,对应5+或uni-app项目manifest.json中appid
- adid DCloud的广告标识,开通广告后可在dev.dcloud.net.cn获取,如果没有开通广告,设置值为即可
- channel 渠道标识,注意:提交谷歌应用市场(Google Play)时一定要将渠道标识设置为google
例如:<meta-data android:name="DCLOUD_STREAMAPP_CHANNEL" android:value="io.dcloud.HBuilder|HBuilder|0123456789|google" />
Android平台本地离线打包渠道相关配置
iOS平台本地离线打包渠道相关配置
手机端获取渠道信息的js api
plus.runtime.channel
注意:HBuilder 2.0版本此API有bug,请升级到更新版
这个API主要用于自定义统计,如果是使用DCloud的统计,无需专门写API。具体见下。
uni-app如何在uni统计后台查看渠道数据
登录uni统计官网https://tongji.dcloud.net.cn。
在左侧导航点击“渠道/场景值分析 - 渠道(app)”,即可查看。
在留存统计等报表中,也可以筛选渠道查看。
5+App如何在DCloud统计后台查看渠道数据
如果你的App不是uni-app,而是5+或wap2app。那么无法使用uni统计。此时可登录DCloud开发者中心查看应用的基本统计数据。
首页会展示所有已创建的应用列表,点击应用名称进入应用详情页,在上方的选项选择5+APP运营后可以查看该应用的『日活趋势』。
包含渠道信息的应用,左上角选择渠道,即可查看对应渠道的运营统计数据。
Tips:
- 5+App的基本统计,当日的数据,次日才会出统计结果。
- 有用户使用且统计到有效数据,才可以按相应的渠道区分。
- 目前需要一个渠道一个渠道打包,云打包暂时无法批量打多个渠道包出来。
- 本文的渠道标记处理的是DCloud统计后台,如使用友盟统计,需要在友盟的sdk配置里单独配
分布式链路追踪的利器——Zipkin
作者:个推应用平台基础架构高级研发工程师 阿飞
01业务背景
随着微服务架构的流行,系统变得越来越复杂,单体的系统被拆成很多个模块,各个模块通过轻量级的通信协议进行通讯,相互协作,共同实现系统功能。
单体架构时,一个请求的调用链路很清晰,一般由负载均衡器将用户请求转发到后端服务,由后端服务进行业务处理,需要的数据从外部的存储中获取,处理完请求后,再经由负载均衡器返回给用户。
而在微服务架构中,一个请求往往需要多个模块共同协作处理,不同模块可能还依赖于不同的外部存储,各个模块的实现技术还不尽相同,一个请求是如何在整个系统不同模块间进行流转,整个调用链上的各个模块之间的调用关系如何,每个微服务处理的时间长短,处理的结果是否正确,很难去进行追踪,而这些信息对于整个系统运维、性能分析、故障追踪都特别有帮助,也正因为此,才有了各种分布式链路追踪的技术。
02分布式链路追踪现状
分布式链路追踪的技术有很多,有开源的也有闭源的。开源的有Jaeger、PinPoint、Zipkin、SkyWalking、CAT等,闭源的有Google Dapper、淘宝的鹰眼Tracing、新浪的Watchman、美团的MTrace等。CNCF(Cloud Native Computing Foundation)为了解决业界分布式追踪系统跨平台兼容性问题,设计了trace的标准,提出了分布式跟踪系统产品的统一范式-OpenTracing,Zipkin也部分支持OpenTracing标准。
03选择Zipkin的原因
在实践的过程中,基于以下原因选择了Zipkin来进行链路追踪:
• 开源,社区活跃
• 支持多种语言,Nodejs,Lua,Java都有开源实现,而我们的服务主要是这三种语言实现的
• 提供查询API,方便二次开发
04Zipkin的架构介绍
Zipkin的整体架构如下图所示:
Zipkin的整体架构
(引用自Zipkin官网:https://zipkin.io/pages/architecture.html)
其中:
• Instrumented client和Instrumented server需要集成在分布式系统的具体服务中,采集跟踪信息,调用Transport,把跟踪信息发送给Zipkin的Server。
• Transport是Zipkin对外提供的接口,支持HTTP、Kafka、Scribe等通信方式。
• Zipkin即Zipkin server,主要包括四个模块:
Collector: 用于接收各个应用服务传输的追踪信息;
Storage:Zipkin的后端存储,支持In-Memory、MySql、Elasticsearch和Cassandra;
API:提供对外的查询接口;
UI:提供对外的Web界面。
Http Tracing的时序图
(引用自Zipkin官网:https://zipkin.io/pages/architecture.html)
以上是Http Tracing的时序图,用户的请求/foo首先被Trace Instrumentationlan拦截,记录下Tags,时间戳,同时在Header里增加Trace信息,然后再流转到后端服务进行处理,处理完成后,正常响应,Trace Instrumentationlan拦截响应,记录处理延时后,将Response正常返回给调用方,同时异步地将Trace的Span发送给Zipkin Server。Span中的traceId是在整个调用链路上唯一的ID,用于唯一标识一条调用链。
05个推的Zipkin实践
个推的微服务是基于Kubernetes和Docker进行部署的,每个微服务对应于Kubernetes中的一组Pod。
在整个微服务体系中,API网关是基于Openresty开发的,主要使用Lua进行开发;后端服务主要使用Node.js和Java进行开发实现。在对接Zipkin时,不同的微服务采用不同的方式进行实现。
API网关主要通过增加网关插件(主要参考了Kong的Zipkin插件实现)来实现与Zipkin的对接;Node.js实现的服务主要使用了中间件实现与Zipkin的对接;Java服务使用了spring-cloud-sleuth来与Zipkin对接。 整体的架构如下图所示:
个推基于Zipkin的分布式链路追踪系统的整体架构
其中,Zipkin也容器化部署在Kubernetes集群中,简化了Zipkin的搭建和部署。如下图所示,通过Zipkin可以很方便地追踪请求的调用链路,整个调用链上各个服务的处理耗时,响应状态,服务间的调用关系都可以方便地在Zipkin中进行查询。Zipkin对于分析整个系统的性能瓶颈,定位故障也都有很大的帮助。
Zipkin的Web界面
06总结
Zipkin作为一个分布式链路追踪系统,有着应用侵入较小、社区活跃度较高、支持多种语言等优势,一般基于开源的实现稍做修改就可以实现与Zipkin的对接。因此个推在微服务架构中也引入了Zipkin,用Zipkin来追踪微服务的调用关系,对微服务进行性能分析和故障诊断。未来,个推会基于Zipkin做二次开发,提供更为友好的界面。
作者:个推应用平台基础架构高级研发工程师 阿飞
01业务背景
随着微服务架构的流行,系统变得越来越复杂,单体的系统被拆成很多个模块,各个模块通过轻量级的通信协议进行通讯,相互协作,共同实现系统功能。
单体架构时,一个请求的调用链路很清晰,一般由负载均衡器将用户请求转发到后端服务,由后端服务进行业务处理,需要的数据从外部的存储中获取,处理完请求后,再经由负载均衡器返回给用户。
而在微服务架构中,一个请求往往需要多个模块共同协作处理,不同模块可能还依赖于不同的外部存储,各个模块的实现技术还不尽相同,一个请求是如何在整个系统不同模块间进行流转,整个调用链上的各个模块之间的调用关系如何,每个微服务处理的时间长短,处理的结果是否正确,很难去进行追踪,而这些信息对于整个系统运维、性能分析、故障追踪都特别有帮助,也正因为此,才有了各种分布式链路追踪的技术。
02分布式链路追踪现状
分布式链路追踪的技术有很多,有开源的也有闭源的。开源的有Jaeger、PinPoint、Zipkin、SkyWalking、CAT等,闭源的有Google Dapper、淘宝的鹰眼Tracing、新浪的Watchman、美团的MTrace等。CNCF(Cloud Native Computing Foundation)为了解决业界分布式追踪系统跨平台兼容性问题,设计了trace的标准,提出了分布式跟踪系统产品的统一范式-OpenTracing,Zipkin也部分支持OpenTracing标准。
03选择Zipkin的原因
在实践的过程中,基于以下原因选择了Zipkin来进行链路追踪:
• 开源,社区活跃
• 支持多种语言,Nodejs,Lua,Java都有开源实现,而我们的服务主要是这三种语言实现的
• 提供查询API,方便二次开发
04Zipkin的架构介绍
Zipkin的整体架构如下图所示:
Zipkin的整体架构
(引用自Zipkin官网:https://zipkin.io/pages/architecture.html)
其中:
• Instrumented client和Instrumented server需要集成在分布式系统的具体服务中,采集跟踪信息,调用Transport,把跟踪信息发送给Zipkin的Server。
• Transport是Zipkin对外提供的接口,支持HTTP、Kafka、Scribe等通信方式。
• Zipkin即Zipkin server,主要包括四个模块:
Collector: 用于接收各个应用服务传输的追踪信息;
Storage:Zipkin的后端存储,支持In-Memory、MySql、Elasticsearch和Cassandra;
API:提供对外的查询接口;
UI:提供对外的Web界面。
Http Tracing的时序图
(引用自Zipkin官网:https://zipkin.io/pages/architecture.html)
以上是Http Tracing的时序图,用户的请求/foo首先被Trace Instrumentationlan拦截,记录下Tags,时间戳,同时在Header里增加Trace信息,然后再流转到后端服务进行处理,处理完成后,正常响应,Trace Instrumentationlan拦截响应,记录处理延时后,将Response正常返回给调用方,同时异步地将Trace的Span发送给Zipkin Server。Span中的traceId是在整个调用链路上唯一的ID,用于唯一标识一条调用链。
05个推的Zipkin实践
个推的微服务是基于Kubernetes和Docker进行部署的,每个微服务对应于Kubernetes中的一组Pod。
在整个微服务体系中,API网关是基于Openresty开发的,主要使用Lua进行开发;后端服务主要使用Node.js和Java进行开发实现。在对接Zipkin时,不同的微服务采用不同的方式进行实现。
API网关主要通过增加网关插件(主要参考了Kong的Zipkin插件实现)来实现与Zipkin的对接;Node.js实现的服务主要使用了中间件实现与Zipkin的对接;Java服务使用了spring-cloud-sleuth来与Zipkin对接。 整体的架构如下图所示:
个推基于Zipkin的分布式链路追踪系统的整体架构
其中,Zipkin也容器化部署在Kubernetes集群中,简化了Zipkin的搭建和部署。如下图所示,通过Zipkin可以很方便地追踪请求的调用链路,整个调用链上各个服务的处理耗时,响应状态,服务间的调用关系都可以方便地在Zipkin中进行查询。Zipkin对于分析整个系统的性能瓶颈,定位故障也都有很大的帮助。
Zipkin的Web界面
06总结
Zipkin作为一个分布式链路追踪系统,有着应用侵入较小、社区活跃度较高、支持多种语言等优势,一般基于开源的实现稍做修改就可以实现与Zipkin的对接。因此个推在微服务架构中也引入了Zipkin,用Zipkin来追踪微服务的调用关系,对微服务进行性能分析和故障诊断。未来,个推会基于Zipkin做二次开发,提供更为友好的界面。
收起阅读 »小程序web-view关闭后,页面音频没有关闭
问题描述:
在web-view
的src中,引入了一个HTML5页面,这个页面有个自动播放的音频。
在小程序中,点击右上角关闭小程序后,web-view
页面中的音频依然会播放。
期待现象
期待关闭小程序之后,音频也停止。
通过查找文档,发现没有直接提供方法,网上找了一圈之后,尝试的方案也都无法实现。
所以我这里想到的思路是,当用户关闭小程序时,应该销毁掉web-view
。可惜,目前没有这个接口。
所以我就利用了模拟的方式来实现,当前小程序页面onHide
时,就将web-view
的页面src
属性清空。
后来经过测试发现,在ios
平台下,需要制定一个url,在android
平台下只需要清空。另外为了防止造成缓存,给url
后面添加了一个随机的参数。
以下是代码片段。
<template>
<view>
<web-view :src="webUrl"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
webUrl: 'https://demo.com/weixin/index.html'
}
},
onLoad() {
},
onHide(){
// webview关闭后,刷新url。否则会造成音乐在后台继续播放的bug
if (uni.getSystemInfoSync().platform == "ios") {
this.webUrl = 'https://demo.com/weixin/index.html?redirect=true';
}else{
// android系统下只能给空值
this.webUrl = ';'
}
},
onBackPress(){
},
methods: {
}
}
</script>
<style>
</style>
问题描述:
在web-view
的src中,引入了一个HTML5页面,这个页面有个自动播放的音频。
在小程序中,点击右上角关闭小程序后,web-view
页面中的音频依然会播放。
期待现象
期待关闭小程序之后,音频也停止。
通过查找文档,发现没有直接提供方法,网上找了一圈之后,尝试的方案也都无法实现。
所以我这里想到的思路是,当用户关闭小程序时,应该销毁掉web-view
。可惜,目前没有这个接口。
所以我就利用了模拟的方式来实现,当前小程序页面onHide
时,就将web-view
的页面src
属性清空。
后来经过测试发现,在ios
平台下,需要制定一个url,在android
平台下只需要清空。另外为了防止造成缓存,给url
后面添加了一个随机的参数。
以下是代码片段。
<template>
<view>
<web-view :src="webUrl"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
webUrl: 'https://demo.com/weixin/index.html'
}
},
onLoad() {
},
onHide(){
// webview关闭后,刷新url。否则会造成音乐在后台继续播放的bug
if (uni.getSystemInfoSync().platform == "ios") {
this.webUrl = 'https://demo.com/weixin/index.html?redirect=true';
}else{
// android系统下只能给空值
this.webUrl = ';'
}
},
onBackPress(){
},
methods: {
}
}
</script>
<style>
</style>
收起阅读 »