提交 434c65f8 编写于 作者: DCloud-yyl's avatar DCloud-yyl

Merge branch 'alpha'

# Conflicts:
#	package.json
{
"id": "hello-uniapp-x",
"displayName": "hello-uniapp-x",
"description": "演示 uni-app x 框架的组件、接口、模板",
"keywords": [
"uni-app-x",
"uni-app2.0",
"示例工程"
],
"version": "1.0.6"
}
"id": "hello-uniapp-x",
"name": "hello-uniapp-x",
"displayName": "hello-uniapp-x",
"version": "1.0.8",
"description": "演示 uni-app x 框架的组件、接口、模板",
"repository": "https://gitcode.net/dcloud/hello-uni-app-x",
"keywords": [
"uni-app-x",
"uni-app2.0",
"示例工程"
],
"author": "",
"license": "MIT",
"dependencies": {},
"engines": {
"HBuilderX": "^3.98"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "不采集任何数据",
"permissions": "- android.permission.INTERNET \n- android.permission.READ_EXTERNAL_STORAGE \n- android.permission.WRITE_EXTERNAL_STORAGE \n- android.permission.ACCESS_FINE_LOCATION \n- android.permission.ACCESS_COARSE_LOCATION \n- android.permission.ACCESS_NETWORK_STATE \n- android.permission.READ_MEDIA_IMAGES \n- android.permission.READ_MEDIA_VIDEO \n- android.permission.READ_MEDIA_VISUAL_USER_SELECTED \n- android.permission.CAMERA \n- android.permission.READ_PHONE_STATE \n- android.permission.REQUEST_INSTALL_PACKAGES"
},
"npmurl": "",
"type": "uniapp-template-project"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "n",
"app-nvue": "n",
"app-uvue": "y"
},
"H5-mobile": {
"Safari": "n",
"Android Browser": "n",
"微信浏览器(Android)": "n",
"QQ浏览器(Android)": "n"
},
"H5-pc": {
"Chrome": "n",
"IE": "n",
"Edge": "n",
"Firefox": "n",
"Safari": "n"
},
"小程序": {
"微信": "n",
"阿里": "n",
"百度": "n",
"字节跳动": "n",
"QQ": "n",
"京东": "n",
"钉钉": "n",
"快手": "n",
"飞书": "n"
},
"快应用": {
"华为": "n",
"联盟": "n"
},
"Vue": {
"vue2": "n",
"vue3": "y"
}
}
}
}
}
......@@ -154,14 +154,13 @@ export default {
open: false,
pages: [] as Page[],
},
// {
// id: 'half-screen',
// url: 'half-screen',
// name: '半屏弹窗',
// open: false,
// enable: false,
// pages: [] as Page[],
// },
{
id: 'half-screen',
url: 'half-screen',
name: '半屏弹窗',
open: false,
pages: [] as Page[],
},
{
id: 'drop-card',
url: 'drop-card',
......
<template>
<view class="page">
<text>TouchEvent还有细节需要优化,需支持拦截事件分发逻辑解决拖拽半屏窗口引起内容滚动的问题</text>
<button class="bottomButton" @click="switchHalfScreen(true)">打开弹窗</button>
<view ref="halfScreen" class="halfScreen" @touchstart="onHalfTouchStart" @touchmove="onHalfTouchMove" @touchend="onHalfTouchEnd">
<view class="halfTitle" >半屏弹窗标题</view>
<scroll-view ref="halfScroll" class="halfScroll" @scroll="onScroll" bounce="true">
<view v-for="(item,index) in list" :key="index" class="item">
half screen content-{{item}}
</view>
</scroll-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
list: ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15'],
totalHeight: 0, //总高度
halfMove: false, //是否Move,响应TouchMove
halfScreenY: 0, //响应TouchMove的起始点Y坐标
halfOffset: 0, //偏移的位置,translateY
halfHeight: 0, //高度
lastY: 0, //上次
lastY2: 0, //
bAnimation: false, //是否动画
halfNode: null as Element | null,
scrollNode: null as Element | null
}
},
methods: {
onHalfTouchStart(_:TouchEvent) {
this.halfNode?.style?.setProperty('transitionDuration', 0);
//console.log('Title TouchStart: ', e);
},
onHalfTouchMove(e:TouchEvent) {
if(this.bAnimation){//容错处理
return;
}
let top:number = this.scrollNode?.getAttribute('scrollTop') as number
let p = e.touches[0];
this.lastY2 = this.lastY;
this.lastY = p.screenY;
if(top <= 0.01 || this.halfMove){
if(this.halfScreenY == 0){
this.halfScreenY = p.screenY;
}
let offset = p.screenY-this.halfScreenY;
if(offset > 0){
this.halfMove = true;
this.halfNode?.style?.setProperty('transform','translateY('+offset+'px)');
this.halfOffset = offset;
}else if(this.lastY2>this.lastY && this.halfOffset>0){//容错触发向下滚动的误差
offset = this.halfScreenY-p.screenY;
if(offset>this.halfOffset){
offset = this.halfOffset;
}
this.halfNode?.style?.setProperty('transform','translateY('+offset+'px)');
this.halfOffset = offset;
}
}
//console.log('TouchMove', e.target);
},
onHalfTouchEnd(_:TouchEvent) {
if(this.bAnimation){//容错处理
return;
}
let top:number = this.scrollNode?.getAttribute('scrollTop') as number
let bHide = (this.halfHeight-this.halfOffset)<this.halfHeight/4;
if(bHide){
bHide = this.lastY2>0&&this.lastY2<=this.lastY;
}else if(top <= 0.01){
bHide = (this.lastY-this.lastY2)>3; //向下滑动计算加速度判断是否关闭,简单处理未考虑时间
}
if(bHide){
this.switchHalfScreen(false);
}else{
this.resumeHalfScreen();
}
},
onScroll(_: ScrollEvent) {
//console.log('onScroll: ', e);
},
switchHalfScreen(show:boolean) {
if(show&&('visible'==this.halfNode?.style?.getPropertyValue('visibility'))){//容错处理
console.log('qucik click button!!!');
return;
}
this.halfMove = false;
this.halfScreenY = 0;
this.halfOffset = 0;
let top = this.totalHeight;
let time = 300;
if(show){
top = this.totalHeight*30/100; //计算显示的位置
this.halfNode?.style?.setProperty('visibility','visible');
this.halfNode?.style?.setProperty('transitionTimingFunction','ease-in-out');
}else{
this.halfNode?.style?.setProperty('transitionTimingFunction','linear');
time *= (this.halfHeight/this.totalHeight); //计算关闭动画时间
}
this.halfNode?.style?.setProperty('transitionDuration', time.toFixed(0));
this.halfNode?.style?.setProperty('transitionProperty','top');
this.halfNode?.style?.setProperty('top', top.toFixed(0));
setTimeout(()=>{
if(!show){
this.halfNode?.style?.setProperty('visibility','hidden');
this.halfNode?.style?.setProperty('transitionDuration', 0);
this.halfNode?.style?.setProperty('transform','');
}
this.halfNode?.style?.setProperty('transitionProperty','');
this.bAnimation = false;
}, time)
this.bAnimation = true;
},
resumeHalfScreen() {
let time = 300;//(500*this.halfOffset/this.halfHeight).toFixed(0); //回弹动画时间
this.halfNode?.style?.setProperty('transitionDuration',time.toFixed(0));
this.halfNode?.style?.setProperty('transitionTimingFunction','ease-in-out');
this.halfNode?.style?.setProperty('transitionProperty','transform');
this.halfNode?.style?.setProperty('transform','translateY(0px)');
this.halfMove = false;
this.halfScreenY = 0;
this.halfOffset = 0;
setTimeout(()=>{
this.bAnimation = false;
}, time)
this.bAnimation = true;
}
},
onReady() {
this.halfNode = this.$refs['halfScreen'] as Element;
this.halfHeight = this.halfNode!.getBoundingClientRect().height;
this.scrollNode = this.$refs['halfScroll'] as Element;
this.totalHeight = uni.getWindowInfo().windowHeight;
this.halfNode?.style?.setProperty('top', this.totalHeight.toString());
},
// onResize() {
// this.halfHeight = this.halfNode!.getBoundingClientRect().height;
// this.totalHeight = uni.getWindowInfo().windowHeight;
// }
}
</script>
<style>
.page {
flex: 1;
background-color: darkgrey;
}
.bottomButton {
position: absolute;
width: 100%;
bottom: 0px;
}
.halfScreen {
position: absolute;
top: 100%;
width: 100%;
height: 70%;
transition-timing-function: ease-in-out; /*ease ease-in ease-out ease-in-out linear step-start step-end*/
transition-property: top;
transition-duration: 0;
visibility: hidden;
}
.halfTitle {
align-items: center;
justify-content: center;
height: 48px;
background-color: cornflowerblue;
border-radius: 10px 10px 0 0;
}
.halfScroll {
background-color: ghostwhite;
}
.item {
height: 100px;
}
<template>
<view id="page" class="page">
<text
style="margin: 10px">半屏弹窗,演示了弹出层内scroll-view滚动到顶时由滚变拖。本效果是通过监听TouchEvent实现,当半屏窗口移动时禁用scroll-view的滚动,避免两者的冲突。</text>
<button class="bottomButton" @click="switchHalfScreen(true)">打开弹窗</button>
<view id="halfScreen" class="halfScreen" @touchstart="onHalfTouchStart" @touchmove="onHalfTouchMove"
@touchend="onHalfTouchEnd">
<view class="halfTitle">半屏弹窗标题</view>
<scroll-view id="halfScroll" class="halfScroll" rebound="true">
<view v-for="(item,index) in list" :key="index" class="item">
half screen content-{{item}}
</view>
</scroll-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
list: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15'],
totalHeight: 0, //总高度
halfMove: false, //是否Move,响应TouchMove
halfScreenY: 0, //响应TouchMove的起始点Y坐标
halfOffset: 0, //偏移的位置,translateY
halfHeight: 0, //高度
lastY: 0, //上次
lastY2: 0, //
bAnimation: false, //是否动画
halfNode: null as Element | null,
scrollNode: null as Element | null
}
},
methods: {
onHalfTouchStart(_ : TouchEvent) {
this.halfNode?.style?.setProperty('transitionDuration', 0);
},
onHalfTouchMove(e : TouchEvent) {
if (this.bAnimation) {//容错处理
return;
}
let top : number = this.scrollNode?.scrollTop ?? 0;
let p = e.touches[0];
this.lastY2 = this.lastY;
this.lastY = p.screenY;
if (top <= 0.01 || this.halfMove) {
if (this.halfScreenY == 0) {
this.halfScreenY = p.screenY;
}
let offset = p.screenY - this.halfScreenY;
if (offset > 0) {//向下滚动
this.halfMove = true;
this.scrollNode?.setAttribute('scroll-y', 'false');
this.halfNode?.style?.setProperty('transform', 'translateY(' + offset.toFixed(2) + 'px)');
this.halfOffset = offset;
} else if (this.halfOffset > 0) {//向上滚动
offset = this.halfScreenY - p.screenY;
if (offset > this.halfOffset) {
offset = 0;
this.halfMove = false;
this.scrollNode?.setAttribute('scroll-y', 'true');
}
this.halfNode?.style?.setProperty('transform', 'translateY(' + offset.toFixed(2) + 'px)');
this.halfOffset = offset;
}
}
},
onHalfTouchEnd(_ : TouchEvent) {
this.halfScreenY = 0;
if (this.bAnimation) {//容错处理
return;
}
let top : number = this.scrollNode?.scrollTop ?? 0;
let bHide = (this.halfHeight - this.halfOffset) < this.halfHeight / 4;
if (bHide) {
bHide = this.lastY2 > 0 && this.lastY2 <= this.lastY;
} else if (top <= 0.01) {
bHide = (this.lastY - this.lastY2) > 3; //向下滑动计算加速度判断是否关闭,简单处理未考虑时间
}
if (bHide) {
this.switchHalfScreen(false);
} else if (this.halfOffset > 0) {
this.resumeHalfScreen();
}
},
switchHalfScreen(show : boolean) {
if (show && ('visible' == this.halfNode?.style?.getPropertyValue('visibility'))) {//容错处理
console.log('qucik click button!!!');
return;
}
this.halfMove = false;
this.scrollNode?.setAttribute('scroll-y', 'true');
this.halfScreenY = 0;
this.halfOffset = 0;
let top = this.totalHeight;
let time = 300;
if (show) {
top = this.totalHeight * 30 / 100; //计算显示的位置
this.halfNode?.style?.setProperty('visibility', 'visible');
this.halfNode?.style?.setProperty('transitionTimingFunction', 'ease-in-out');
} else {
this.halfNode?.style?.setProperty('transitionTimingFunction', 'linear');
time *= (this.halfHeight / this.totalHeight); //计算关闭动画时间
}
this.halfNode?.style?.setProperty('transitionDuration', time.toFixed(0));
this.halfNode?.style?.setProperty('transitionProperty', 'top');
this.halfNode?.style?.setProperty('top', top.toFixed(2));
setTimeout(() => {
if (!show) {
this.halfNode?.style?.setProperty('visibility', 'hidden');
this.halfNode?.style?.setProperty('transitionDuration', 0);
this.halfNode?.style?.setProperty('transform', '');
}
this.halfNode?.style?.setProperty('transitionProperty', '');
this.bAnimation = false;
}, time)
this.bAnimation = true;
},
resumeHalfScreen() {
let time = 300;//(500*this.halfOffset/this.halfHeight).toFixed(0); //回弹动画时间
this.halfNode?.style?.setProperty('transitionDuration', time.toFixed(0));
this.halfNode?.style?.setProperty('transitionTimingFunction', 'ease-in-out');
this.halfNode?.style?.setProperty('transitionProperty', 'transform');
this.halfNode?.style?.setProperty('transform', 'translateY(0px)');
this.halfMove = false;
this.scrollNode?.setAttribute('scroll-y', 'true');
this.halfScreenY = 0;
this.halfOffset = 0;
setTimeout(() => {
this.bAnimation = false;
this.halfNode?.style?.setProperty('transitionProperty', '');
}, time)
this.bAnimation = true;
}
},
onReady() {
this.halfNode = uni.getElementById('halfScreen');
this.scrollNode = uni.getElementById('halfScroll');
this.halfHeight = this.halfNode!.getBoundingClientRect().height;
this.totalHeight = uni.getElementById('page')?.getBoundingClientRect()?.height ?? 0;//uni.getWindowInfo().windowHeight
this.halfNode?.style?.setProperty('top', this.totalHeight.toFixed(2));
},
onResize() {
this.halfHeight = this.halfNode?.getBoundingClientRect()?.height ?? 0;
this.totalHeight = uni.getWindowInfo().windowHeight;
this.halfNode?.style?.setProperty('top', this.totalHeight.toFixed(2));
this.halfNode?.style?.setProperty('visibility', 'hidden');
}
}
</script>
<style>
.page {
flex: 1;
background-color: darkgrey;
}
.bottomButton {
position: absolute;
width: 100%;
bottom: 0px;
}
.halfScreen {
position: absolute;
top: 100%;
width: 100%;
height: 70%;
transition-timing-function: ease-in-out;
/*ease ease-in ease-out ease-in-out linear step-start step-end*/
transition-property: top;
transition-duration: 0;
visibility: hidden;
}
.halfTitle {
align-items: center;
justify-content: center;
height: 48px;
background-color: ghostwhite;
border-radius: 10px 10px 0 0;
}
.halfScroll {
background-color: white;
}
.item {
height: 100px;
}
</style>
## 0.7.4(2023-11-29)
- 修复 uni-app-x 项目中由上版引发的无法升级的Bug
## 0.7.3(2023-11-27)
- 修复 在 uni-app x 中无更新时报错的Bug
## 0.7.2(2023-11-20)
- 新增 插件根目录 utils 文件夹中新增 check-update-nvue.js 文件(vue2 的 nvue 页面请引用该文件)
## 0.7.1(2023-11-17)
- 修复 运行至浏览器 ts 语法报错
## 0.7.0(2023-11-10)
......
{
"id": "uni-upgrade-center-app",
"displayName": "升级中心 uni-upgrade-center - App",
"version": "0.7.1",
"version": "0.7.4",
"description": "uni升级中心 - 客户端检查更新",
"keywords": [
"uniCloud",
......
......@@ -78,14 +78,22 @@ export default function () : Promise<UniUpgradeCenterResult> {
data: data
}).then(res => {
const code = res.result['code']
if (['Int', 'Long', 'number'].includes(typeof code) && (code as number) < 0) {
reject({
code: res.result['code'],
message: res.result['message']
})
} else {
const result = JSON.parse<UniUpgradeCenterResult>(JSON.stringify(res.result)) as UniUpgradeCenterResult
resolve(result)
const codeIsNumber = ['Int', 'Long', 'number'].includes(typeof code)
if (codeIsNumber) {
if ((code as number) == 0) {
reject({
code: res.result['code'],
message: res.result['message']
})
} else if (code < 0) {
reject({
code: res.result['code'],
message: res.result['message']
})
} else {
const result = JSON.parse<UniUpgradeCenterResult>(JSON.stringify(res.result)) as UniUpgradeCenterResult
resolve(result)
}
}
}).catch<void>((err : any | null) => {
const error = err as UniCloudError
......
function callCheckVersion() {
// #ifdef APP-PLUS
return new Promise((resolve, reject) => {
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
let data = {
action: 'checkVersion',
appid: plus.runtime.appid,
appVersion: plus.runtime.version,
wgtVersion: widgetInfo.version
}
uniCloud.callFunction({
name: 'uni-upgrade-center',
data,
success: (e) => {
resolve(e)
},
fail: (error) => {
reject(error)
}
})
})
})
// #endif
// #ifndef APP-PLUS
return new Promise((resolve, reject) => {})
// #endif
}
// 推荐再App.vue中使用
const PACKAGE_INFO_KEY = '__package_info__'
export default function() {
// #ifdef APP-PLUS
return new Promise((resolve, reject) => {
callCheckVersion().then(async (e) => {
if (!e.result) return;
const {
code,
message,
is_silently, // 是否静默更新
url, // 安装包下载地址
platform, // 安装包平台
type // 安装包类型
} = e.result;
// 此处逻辑仅为实例,可自行编写
if (code > 0) {
// 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回
const {
fileList
} = await uniCloud.getTempFileURL({
fileList: [url]
});
if (fileList[0].tempFileURL)
e.result.url = fileList[0].tempFileURL;
resolve(e)
// 静默更新,只有wgt有
if (is_silently) {
uni.downloadFile({
url: e.result.url,
success: res => {
if (res.statusCode == 200) {
// 下载好直接安装,下次启动生效
plus.runtime.install(res.tempFilePath, {
force: false
});
}
}
});
return;
}
/**
* 提示升级一
* 使用 uni.showModal
*/
// return updateUseModal(e.result)
/**
* 提示升级二
* 官方适配的升级弹窗,可自行替换资源适配UI风格
*/
uni.setStorageSync(PACKAGE_INFO_KEY, e.result)
uni.navigateTo({
url: `/uni_modules/uni-upgrade-center-app/pages/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`,
fail: (err) => {
console.error('更新弹框跳转失败', err)
uni.removeStorageSync(PACKAGE_INFO_KEY)
}
})
return
} else if (code < 0) {
// TODO 云函数报错处理
console.error(message)
return reject(e)
}
return resolve(e)
}).catch(err => {
// TODO 云函数报错处理
console.error(err.message)
reject(err)
})
});
// #endif
}
/**
* 使用 uni.showModal 升级
*/
function updateUseModal(packageInfo) {
const {
title, // 标题
contents, // 升级内容
is_mandatory, // 是否强制更新
url, // 安装包下载地址
platform, // 安装包平台
type // 安装包类型
} = packageInfo;
let isWGT = type === 'wgt'
let isiOS = !isWGT ? platform.includes('iOS') : false;
let confirmText = isiOS ? '立即跳转更新' : '立即下载更新'
return uni.showModal({
title,
content: contents,
showCancel: !is_mandatory,
confirmText,
success: res => {
if (res.cancel) return;
// 安装包下载
if (isiOS) {
plus.runtime.openURL(url);
return;
}
uni.showToast({
title: '后台下载中……',
duration: 1000
});
// wgt 和 安卓下载更新
downloadTask = uni.downloadFile({
url,
success: res => {
if (res.statusCode !== 200) {
console.error('下载安装包失败', err);
return;
}
// 下载好直接安装,下次启动生效
plus.runtime.install(res.tempFilePath, {
force: false
}, () => {
if (is_mandatory) {
//更新完重启app
plus.runtime.restart();
return;
}
uni.showModal({
title: '安装成功是否重启?',
success: res => {
if (res.confirm) {
//更新完重启app
plus.runtime.restart();
}
}
});
}, err => {
uni.showModal({
title: '更新失败',
content: err
.message,
showCancel: false
});
});
}
});
}
});
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册