提交 d3dc740d 编写于 作者: 杜庆泉's avatar 杜庆泉

Merge branch 'dev' of https://gitcode.net/dcloud/hello-uni-app-x into dev

......@@ -66,7 +66,7 @@
mounted() {
uni.setNavigationBarColor({
frontColor: "#000000",
backgroundColor: "#ffffff",
backgroundColor: "#007aff",
});
},
methods: {
......
// 自动化测试
module.exports = {
"is-custom-runtime": false,
"compile": true,
......@@ -35,4 +36,4 @@ module.exports = {
}
}
}
}
\ No newline at end of file
}
// 自动化测试
const path = require('path');
const {
configureToMatchImageSnapshot
......
// 自动化测试
module.exports = {
testTimeout: 30000,
reporters: ['default'],
......
{
"name": "hello-uniapp x",
"appid": "__UNI__3584C99",
"description": "",
"versionName": "1.0.18",
"versionCode": "10018",
"uni-app-x": {},
/* 快应用特有相关 */
"quickapp": {},
/* 小程序特有相关 */
"mp-weixin": {
"appid": "",
"setting": {
"urlCheck": false
},
"usingComponents": true
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"uniStatistics": {
"enable": false
},
"app": {},
"vueVersion": "3",
"h5": {
"router": {
"base": "/web/"
}
}
{
"name" : "hello-uniapp x",
"appid" : "__UNI__3584C99",
"description" : "",
"versionName" : "1.0.21",
"versionCode" : 10021,
"uni-app-x" : {},
/* 快应用特有相关 */
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"app" : {},
"vueVersion" : "3",
"h5" : {
"router" : {
"base" : "/web/"
}
}
}
此差异已折叠。
const PAGE_PATH =
"/pages/API/request-payment/request-payment";
describe("payment", () => {
if (process.env.uniTestPlatformInfo.indexOf('web') > -1) {
it('web', () => {
expect(1).toBe(1)
})
return
}
beforeAll(async () => {
page = await program.reLaunch(PAGE_PATH)
await page.waitFor(600)
});
//支付失败700711
it("errorcode700711", async () => {
let orderInfo =
"service=\"mobile.securitypay.pay\"&partner=\"2088801273866834\"&_input_charset=\"UTF-8\"&out_trade_no=\"20240229115452\"&subject=\"DCloud项目捐赠\"&payment_type=\"1\"&seller_id=\"payservice@dcloud.io\"&total_fee=\"0.01\"&body=\"DCloud致力于打造HTML5最好的移动开发工具,包括终端的Runtime、云端的服务和IDE,同时提供各项配套的开发者服务。\"&it_b_pay=\"1d\"&notify_url=\"http%3A%2F%2Fdemo.dcloud.net.cn%2Fpayment%2Falipay%2Fnotify.php\"&show_url=\"http%3A%2F%2Fwww.dcloud.io%2Fhelloh5%2F\"&sign=\"diZdkTX2iIP1oZh25UCGqx%2BpkViqAN8xdvMNSJF79aq0JiunX2mtr%2BbNlDsP0YL5x85KjULsqx%2Fq%2B5wij6eMoBVeJ%2BHhyjkwt0PYuwntroJ2Ho8bdUVEybBgOjy240NbCUtKmZzNRQAGsmLztKWzsg1srsQ8Se3Qi8KGDaOhqBs%3D\"&sign_type=\"RSA\"";
await page.setData({
orderinfo: orderInfo,
})
await page.callMethod('jest_pay')
await page.waitFor(async () => {
return await page.data('complete') === true;
});
expect((await page.data())['errorCode']).toEqual(700711)
});
});
<template>
<page-head title="支付宝支付"></page-head>
<button :type="btnType" style="margin: 10px;" @click="pay()">{{btnText}}</button>
</template>
<script>
export default {
data() {
return {
btnText: "支付宝支付",
btnType: "primary",
orderInfo: "",
errorCode: 0,
errorMsg: "",
complete: false
}
},
methods: {
pay() {
uni.showLoading({
title: "请求中..."
})
uni.request({
url: 'https://demo.dcloud.net.cn/payment/alipay/?total=0.01',
method: 'GET',
timeout: 6000,
success: (res) => {
uni.hideLoading()
uni.requestPayment({
provider: "alipay",
orderInfo: res.data as string,
fail: (res : RequestPaymentFail) => {
console.log(JSON.stringify(res))
this.errorCode = res.errCode
uni.showToast({
icon: 'error',
title: 'errorCode:' + this.errorCode
});
},
success: (res : RequestPaymentSuccess) => {
console.log(JSON.stringify(res))
uni.showToast({
icon: 'success',
title: '支付成功'
});
}
} as RequestPaymentOptions)
},
fail: () => {
uni.hideLoading()
},
});
},
//自动化测试使用
jest_pay() {
uni.requestPayment({
provider: "alipay",
orderInfo: this.orderInfo,
fail: (res : RequestPaymentFail) => {
this.errorCode = res.errCode
this.complete = true
},
success: (res : RequestPaymentSuccess) => {
console.log(JSON.stringify(res))
this.complete = true
}
} as RequestPaymentOptions)
}
}
}
</script>
<style>
</style>
......@@ -78,6 +78,12 @@ describe('ExtApi-Request', () => {
it('Check HEAD', async () => {
await request(page, 'HEAD');
});
it('Request with timeout null', async () => {
res = await page.callMethod('jest_timeout_null')
await page.waitFor(2000);
res = await page.data('jest_result');
expect(res).toBe(true)
});
let shouldTestCookie = false
if (process.env.uniTestPlatformInfo.startsWith('android')) {
......
......@@ -285,6 +285,22 @@
},
});
},
jest_timeout_null() {
uni.request({
url: this.host + (methodMap['GET'] as string),
method: "GET",
timeout: null,
sslVerify: false,
withCredentials: false,
firstIpv4: false,
success: () => {
this.jest_result = true;
},
fail: () => {
this.jest_result = false;
},
});
},
}
}
</script>
const PAGE_PATH = '/pages/API/rpx2px/rpx2px'
describe('API-rpx2px', () => {
beforeAll(async () => {
page = await program.reLaunch(PAGE_PATH)
await page.waitFor(600);
});
it('rpx2px', async () => {
const btnConvert = await page.$('.convert')
await btnConvert.tap()
await page.waitFor(100)
const data = await page.data()
expect(data.result).toBe(true)
});
});
<template>
<!-- #ifdef APP -->
<scroll-view class="page-scroll-view">
<!-- #endif -->
<view class="page">
<page-head :title="title"></page-head>
<view>
<view class="item">
<text class="item-k">输入:</text>
<text class="item-v">{{rpxValue}}rpx</text>
</view>
<view class="item">
<text class="item-k">返回:</text>
<text class="item-v">{{pxValue}}px</text>
</view>
</view>
<view>
<button class="convert" type="primary" @click="rpx2px">转换</button>
</view>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script>
export default {
data() {
return {
title: 'rpx2px',
rpxValue: 750,
pxValue: 0,
result: false
}
},
methods: {
rpx2px: function () {
this.pxValue = uni.rpx2px(this.rpxValue);
// 仅限自动化测试
const windowInfo = uni.getWindowInfo();
if (windowInfo.windowWidth == this.pxValue) {
this.result = true
}
}
}
}
</script>
<style>
.page {
padding: 15px;
}
.item {
flex-direction: row;
}
.item-k {
width: 72px;
line-height: 2;
}
.item-v {
font-weight: bold;
line-height: 2;
}
</style>
const CURRENT_PAGE_PATH =
'/pages/API/set-navigation-bar-color/set-navigation-bar-color-custom-navigation'
describe('set statusBar color', () => {
if (process.env.uniTestPlatformInfo.startsWith('web')) {
it('dummyTest', async () => {
expect(1).toBe(1)
})
return
}
let page
const adbScreenShotArea = {
x: 880,
y: 0,
width: 60,
height: 60
};
if (process.env.uniTestPlatformInfo.startsWith('android 6')) {
adbScreenShotArea.x = 535
adbScreenShotArea.width = 90
adbScreenShotArea.height = 50
} else if (process.env.uniTestPlatformInfo.startsWith('android 12')) {
adbScreenShotArea.x = 1160
adbScreenShotArea.width = 70
adbScreenShotArea.height = 80
}
beforeAll(async () => {
page = await program.navigateTo(CURRENT_PAGE_PATH)
await page.waitFor(1000)
})
it("setNavigationBarColor1", async () => {
await page.callMethod("setNavigationBarColor1");
const image = await program.screenshot({
adb: true,
area: adbScreenShotArea
});
expect(image).toMatchImageSnapshot();
});
it("setNavigationBarColor2", async () => {
await page.callMethod("setNavigationBarColor2");
const image = await program.screenshot({
adb: true,
area: adbScreenShotArea
});
expect(image).toMatchImageSnapshot();
});
})
<template>
<page-head title="setNavigationBarColor"></page-head>
<view class="uni-padding-wrap uni-common-mt">
<button @tap="setNavigationBarColor1" class="uni-btn">
设置状态栏背景绿色,文字白色
</button>
<button @tap="setNavigationBarColor2" class="uni-btn">
设置状态栏背景红色,文字黑色
</button>
</view>
</template>
<script>
export default {
methods: {
setNavigationBarColor1() {
uni.setNavigationBarColor({
frontColor: "#ffffff",
backgroundColor: "#00ff00",
success: () => {
console.log("setNavigationBarColor success");
},
fail: () => {
console.log("setNavigationBarColor fail");
},
complete: () => {
console.log("setNavigationBarColor complete");
},
});
},
setNavigationBarColor2() {
uni.setNavigationBarColor({
frontColor: "#000000",
backgroundColor: "#ff0000",
success: () => {
console.log("setNavigationBarColor success");
},
fail: () => {
console.log("setNavigationBarColor fail");
},
complete: () => {
console.log("setNavigationBarColor complete");
},
});
},
},
};
</script>
<template>
<page-head title="setNavigationBarColor"></page-head>
<view class="uni-padding-wrap uni-common-mt">
<button @tap="setNavigationBarColor1" class="uni-btn">
设置导航条背景绿色,标题白色
</button>
<button @tap="setNavigationBarColor2" class="uni-btn">
设置导航条背景红色,标题黑色
</button>
<button @tap="goCustomNavigation" class="uni-btn">
跳转自定义导航栏页面
</button>
</view>
</template>
<script>
import { state, setLifeCycleNum } from '@/store/index.uts'
export default {
methods: {
setNavigationBarColor1() {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#00ff00',
success: () => {
console.log('setNavigationBarColor success')
this.setLifeCycleNum(state.lifeCycleNum + 1)
},
fail: () => {
console.log('setNavigationBarColor fail')
this.setLifeCycleNum(state.lifeCycleNum - 1)
},
complete: () => {
console.log('setNavigationBarColor complete')
this.setLifeCycleNum(state.lifeCycleNum + 1)
}
})
},
setNavigationBarColor2() {
uni.setNavigationBarColor({
frontColor: '#000000',
backgroundColor: '#ff0000',
success: () => {
console.log('setNavigationBarColor success')
this.setLifeCycleNum(state.lifeCycleNum + 1)
},
fail: () => {
console.log('setNavigationBarColor fail')
this.setLifeCycleNum(state.lifeCycleNum - 1)
},
complete: () => {
console.log('setNavigationBarColor complete')
this.setLifeCycleNum(state.lifeCycleNum + 1)
}
})
},
// 自动化测试
getLifeCycleNum() : number {
return state.lifeCycleNum
},
// 自动化测试
setLifeCycleNum(num : number) {
setLifeCycleNum(num)
},
goCustomNavigation() {
uni.navigateTo({
url: '/pages/template/navbar-lite/navbar-lite'
})
}
},
}
<template>
<page-head title="setNavigationBarColor"></page-head>
<view class="uni-padding-wrap uni-common-mt">
<button @tap="setNavigationBarColor1" class="uni-btn">
设置导航条背景绿色,标题白色
</button>
<button @tap="setNavigationBarColor2" class="uni-btn">
设置导航条背景红色,标题黑色
</button>
<!-- #ifdef WEB -->
<button @tap="goNavbarLite" class="uni-btn">
跳转自定义导航栏页面
</button>
<!-- #endif -->
<!-- #ifdef APP -->
<button @tap="goCustomNavigation" class="uni-btn">
跳转设置状态栏页面
</button>
<!-- #endif -->
</view>
</template>
<script>
import { state, setLifeCycleNum } from '@/store/index.uts'
export default {
methods: {
setNavigationBarColor1() {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#00ff00',
success: () => {
console.log('setNavigationBarColor success')
this.setLifeCycleNum(state.lifeCycleNum + 1)
},
fail: () => {
console.log('setNavigationBarColor fail')
this.setLifeCycleNum(state.lifeCycleNum - 1)
},
complete: () => {
console.log('setNavigationBarColor complete')
this.setLifeCycleNum(state.lifeCycleNum + 1)
}
})
},
setNavigationBarColor2() {
uni.setNavigationBarColor({
frontColor: '#000000',
backgroundColor: '#ff0000',
success: () => {
console.log('setNavigationBarColor success')
this.setLifeCycleNum(state.lifeCycleNum + 1)
},
fail: () => {
console.log('setNavigationBarColor fail')
this.setLifeCycleNum(state.lifeCycleNum - 1)
},
complete: () => {
console.log('setNavigationBarColor complete')
this.setLifeCycleNum(state.lifeCycleNum + 1)
}
})
},
// 自动化测试
getLifeCycleNum() : number {
return state.lifeCycleNum
},
// 自动化测试
setLifeCycleNum(num : number) {
setLifeCycleNum(num)
},
goNavbarLite() {
uni.navigateTo({
url: '/pages/template/navbar-lite/navbar-lite'
})
},
goCustomNavigation() {
uni.navigateTo({
url: '/pages/API/set-navigation-bar-color/set-navigation-bar-color-custom-navigation'
})
}
},
}
</script>
......@@ -136,7 +136,7 @@ describe('API-toast', () => {
const btnToastHideButton = await page.$('#btn-toast-hide')
await btnToastHideButton.tap()
await page.waitFor(200)
await page.waitFor(1000)
if (isAndroid) {
const res = await page.callMethod('jest_getWindowInfo')
......
// uni-app自动化测试教程: uni-app自动化测试教程: https://uniapp.dcloud.net.cn/worktile/auto/hbuilderx-extension/
describe('transition event', () => {
if (process.env.uniTestPlatformInfo.indexOf('web') > -1) {
it('dummyTest', () => {
expect(1).toBe(1)
})
return
}
let page;
beforeAll(async () => {
page = await program.reLaunch('/pages/component/general-event/transition-event')
......
......@@ -30,6 +30,23 @@ describe('component-native-image', () => {
expect(await page.data('loadError')).toBe(true)
})
it('check-cookie', async () => {
await page.setData({
autoTest: true,
setCookieImage: 'https://cdn.dcloud.net.cn/img/shadow-grey.png'
});
await page.waitFor(1000);
await page.setData({
loadError: false,
verifyCookieImage: 'https://request.dcloud.net.cn/img/shadow-grey.png'
});
await page.waitFor(1000);
expect(await page.data('loadError')).toBe(false);
await page.setData({
autoTest: false
});
})
it('path-screenshot', async () => {
const page = await program.navigateTo('/pages/component/image/image-path');
await page.waitFor(3000);
......
......@@ -17,6 +17,10 @@
<view class="uni-btn-v">
<button type="primary" @tap="imageLarge">大图示例</button>
</view>
</view>
<view v-if="autoTest">
<image :src="setCookieImage"></image>
<image :src="verifyCookieImage" @error="error"></image>
</view>
</view>
</template>
......@@ -26,7 +30,11 @@
return {
title: 'image',
imageSrc: "/static/test-image/logo.png" as string.ImageURIString,
loadError: false
loadError: false,
// 自动化测试
autoTest: false,
setCookieImage: "",
verifyCookieImage: ""
}
},
methods: {
......
<template>
<list-view>
<slot></slot>
<list-item>start</list-item>
<slot name="default"></slot>
<list-item>middle</list-item>
<slot name="second"></slot>
<list-item>end</list-item>
</list-view>
</template>
describe('list-view-children-in-slot', () => {
if (process.env.uniTestPlatformInfo.startsWith('web')) {
describe('list-view-children-in-slot', () => {
if (process.env.uniTestPlatformInfo.startsWith('web')) {
it('dummyTest', async () => {
expect(1).toBe(1)
})
return
})
return
}
let page
beforeAll(async () => {
......@@ -12,39 +12,39 @@ describe('list-view-children-in-slot', () => {
})
it('basic', async () => {
let listItems = await page.$$('list-item')
expect(listItems.length).toBe(3)
let texts = await page.$$('.text-in-list-item')
for(let i = 0;i<texts.length;i++){
expect(await texts[i].text()).toBe(`${i}`)
}
const addBtn = await page.$('#add-btn')
await addBtn.tap()
listItems = await page.$$('list-item')
expect(listItems.length).toBe(4)
texts = await page.$$('.text-in-list-item')
for(let i = 0;i<texts.length;i++){
expect(await texts[i].text()).toBe(`${i}`)
}
const emptyBtn = await page.$('#empty-btn')
await emptyBtn.tap()
listItems = await page.$$('list-item')
expect(listItems.length).toBe(0)
await addBtn.tap()
listItems = await page.$$('list-item')
expect(listItems.length).toBe(1)
texts = await page.$$('.text-in-list-item')
for(let i = 0;i<texts.length;i++){
expect(await texts[i].text()).toBe(`${i}`)
let listItems = await page.$$('list-item')
expect(listItems.length).toBe(9)
let texts = await page.$$('.text-in-list-item')
for (let i = 0; i < texts.length; i++) {
expect(await texts[i].text()).toBe(`${i > (texts.length / 2 - 1)? i - texts.length / 2 : i}`)
}
const addBtn = await page.$('#add-btn')
await addBtn.tap()
listItems = await page.$$('list-item')
expect(listItems.length).toBe(11)
texts = await page.$$('.text-in-list-item')
for (let i = 0; i < texts.length; i++) {
expect(await texts[i].text()).toBe(`${i > (texts.length / 2 - 1)? i - texts.length / 2 : i}`)
}
const emptyBtn = await page.$('#empty-btn')
await emptyBtn.tap()
listItems = await page.$$('list-item')
expect(listItems.length).toBe(3)
await addBtn.tap()
listItems = await page.$$('list-item')
expect(listItems.length).toBe(5)
texts = await page.$$('.text-in-list-item')
for (let i = 0; i < texts.length; i++) {
expect(await texts[i].text()).toBe(`0`)
}
})
})
})
......@@ -6,11 +6,18 @@
<page-head title="getApp"></page-head>
<view class="uni-padding-wrap">
<list-view-wrapper>
<list-item v-for="item in list" :key="item">
<text class="text-in-list-item">{{item}}</text>
</list-item>
</list-view-wrapper>
<button id="add-btn" class="uni-common-mt" @click="addItem">add item</button>
<template #default>
<list-item v-for="item in list" :key="item">
<text class="text-in-list-item">{{item}}</text>
</list-item>
</template>
<template #second>
<list-item v-for="item in list" :key="item">
<text class="text-in-list-item">{{item}}</text>
</list-item>
</template>
</list-view-wrapper>
<button id="add-btn" class="uni-common-mt" @click="addItem">add item</button>
<button id="empty-btn" class="uni-common-mt" @click="emptyList">empty list</button>
</view>
</view>
......@@ -29,13 +36,13 @@
list: [0, 1, 2]
}
},
methods: {
addItem(){
this.list.push(this.list.length)
},
emptyList(){
this.list = []
}
methods: {
addItem() {
this.list.push(this.list.length)
},
emptyList() {
this.list = []
}
}
}
</script>
......@@ -5,7 +5,7 @@
<list-view v-show="list_show" id="listview" style="flex: 1;" show-scrollbar=false @scrolltolower="onScrollTolower">
<list-item v-for="index in item_count" class="item" @click="itemClick(index)">
<text >item-------<text>{{index}}</text></text>
<input style="border-width: 1px; border-style: solid;" :placeholder="index" :value= "index ==1 ? `第一个` :index "/>
<input style="border-width: 1px; border-style: solid;" :placeholder="index + ''" :value= "index ==1 ? `第一个` :index "/>
</list-item>
</list-view>
</template>
......@@ -46,7 +46,7 @@
<style>
.item {
padding: 15px;
margin: 5px 0;
margin: 0 0 5px 0;
background-color: #fff;
border-radius: 5px;
}
......
describe('component-native-list-view', () => {
if (process.env.uniTestPlatformInfo.startsWith('web')) {
it('dummyTest', async () => {
expect(1).toBe(1)
})
return
}
describe('component-native-list-view', () => {
let page
beforeAll(async () => {
//打开list-view-multiplex测试页
......
......@@ -55,7 +55,7 @@
<style>
.item {
padding: 15px;
margin: 5px 0;
margin: 0 0 5px 0;
background-color: #fff;
border-radius: 5px;
}
......
describe('component-native-list-view-refresh', () => {
if (process.env.uniTestPlatformInfo.startsWith('web')) {
it('dummyTest', async () => {
expect(1).toBe(1)
})
return
}
let page
beforeAll(async () => {
//打开list-view测试页
page = await program.reLaunch('/pages/component/list-view/list-view-refresh')
await page.waitFor(600)
})
it('check_list_view_refresh', async () => {
await page.waitFor(async () => {
return await page.data('refresherTriggered') === false;
});
//等待下拉刷新结束
await page.waitFor(500)
const image = await program.screenshot();
expect(image).toMatchImageSnapshot();
})
})
<template>
<list-view v-if="list_show" id="listview" style="flex: 1;" show-scrollbar=false :refresher-enabled="true"
:refresher-triggered="refresherTriggered" @refresherrefresh="onRefresherrefresh">
<list-item class="item">
<text>向下滑动触发下拉刷新</text>
</list-item>
<list-item v-for="index in item_count" class="item">
<text>item-------{{index}}</text>
</list-item>
</list-view>
</template>
<script>
export default {
data() {
return {
item_count: 20,
list_show: false,
refresherTriggered: true
}
},
onLoad() {
//延迟显示list-view
setTimeout(() => {
this.list_show = true;
}, 500)
},
methods: {
onRefresherrefresh() {
this.refresherTriggered = true;
setTimeout(() => {
this.refresherTriggered = false;
}, 1000)
}
}
}
</script>
<style>
.item {
padding: 15px;
margin: 0 0 5px 0;
background-color: #fff;
border-radius: 5px;
}
.button_item {
width: 200px;
}
</style>
describe('component-native-list-view', () => {
if (process.env.uniTestPlatformInfo.startsWith('web')) {
it('dummyTest', async () => {
expect(1).toBe(1)
})
return
}
describe('component-native-list-view', () => {
let page
beforeAll(async () => {
//打开list-view测试页
......@@ -31,29 +25,33 @@ describe('component-native-list-view', () => {
expect(scrollTop-600).toBeGreaterThanOrEqual(0)
})
//检测竖向scroll_into_view属性赋值
it('check_scroll_into_view_top', async () => {
await page.callMethod('item_change_size_enum', 3)
//检测横向scrollLeft属性赋值
it('check_scroll_left', async () => {
if(await page.data('scroll_x_boolean') === false) {
await page.callMethod('change_scroll_x_boolean', true)
await page.callMethod('change_scroll_y_boolean', false)
await page.waitFor(600)
}
await page.callMethod('confirm_scroll_left_input', 600)
await page.waitFor(600)
const listElement = await page.$('#listview')
const scrollTop = await listElement.attribute("scrollTop")
console.log("check_scroll_into_view_top--"+scrollTop)
await page.callMethod('item_change_size_enum', 0)
expect(scrollTop-690).toBeGreaterThanOrEqual(0)
const scrollLeft = await listElement.attribute("scrollLeft")
console.log("check_scroll_left---"+scrollLeft)
expect(scrollLeft-600).toBeGreaterThanOrEqual(0)
})
//检测下拉刷新
it('check_refresher', async () => {
await page.setData({
refresher_enabled_boolean: true,
refresher_triggered_boolean: true
})
await page.waitFor(2000)
expect(await page.data('refresherrefresh')).toBe(true)
})
if (process.env.uniTestPlatformInfo.indexOf('web') > -1) {
return
}
//检测横向可滚动区域
it('check_scroll_width', async () => {
if(await page.data('scroll_x_boolean') === false) {
await page.callMethod('change_scroll_x_boolean', true)
await page.callMethod('change_scroll_y_boolean', false)
await page.waitFor(600)
}
await page.callMethod('change_scroll_y_boolean', false)
await page.callMethod('change_scroll_x_boolean', true)
await page.waitFor(600)
......@@ -61,18 +59,44 @@ describe('component-native-list-view', () => {
expect(value).toBe(true)
})
//检测横向scrollLeft属性赋值
it('check_scroll_left', async () => {
await page.callMethod('confirm_scroll_left_input', 600)
//检测下拉刷新
it('check_refresher', async () => {
if(await page.data('scroll_y_boolean') === false) {
await page.callMethod('change_scroll_y_boolean', true)
await page.callMethod('change_scroll_x_boolean', false)
await page.waitFor(600)
}
await page.setData({
refresher_enabled_boolean: true,
refresher_triggered_boolean: true
})
await page.waitFor(2000)
expect(await page.data('refresherrefresh')).toBe(true)
})
//检测竖向scroll_into_view属性赋值
it('check_scroll_into_view_top', async () => {
if(await page.data('scroll_y_boolean') === false) {
await page.callMethod('change_scroll_y_boolean', true)
await page.callMethod('change_scroll_x_boolean', false)
await page.waitFor(600)
}
await page.callMethod('item_change_size_enum', 3)
await page.waitFor(600)
const listElement = await page.$('#listview')
const scrollLeft = await listElement.attribute("scrollLeft")
console.log("check_scroll_left---"+scrollLeft)
expect(scrollLeft-600).toBeGreaterThanOrEqual(0)
const scrollTop = await listElement.attribute("scrollTop")
console.log("check_scroll_into_view_top--"+scrollTop)
await page.callMethod('item_change_size_enum', 0)
expect(scrollTop-690).toBeGreaterThanOrEqual(0)
})
//检测横向scroll_into_view属性赋值
it('check_scroll_into_view_left', async () => {
if(await page.data('scroll_x_boolean') === false) {
await page.callMethod('change_scroll_x_boolean', true)
await page.callMethod('change_scroll_y_boolean', false)
await page.waitFor(600)
}
await page.callMethod('item_change_size_enum', 3)
await page.waitFor(600)
const listElement = await page.$('#listview')
......
......@@ -154,35 +154,48 @@
@touchend="list_item_touchend" @tap="list_item_tap" @longpress="list_item_longpress" class="list-item">
<text>{{key}}</text>
</list-item>
<!-- #ifdef APP -->
<list-item slot="refresher" class="refresh-box">
<text class="tip-text">{{text[state]}}</text>
</list-item>
<!-- #endif -->
</list-view>
</view>
<scroll-view style="flex:1" direction="vertical">
<view class="content">
<!-- #ifdef APP -->
<boolean-data :defaultValue="false" title="设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发"
@change="change_refresher_triggered_boolean"></boolean-data>
<boolean-data :defaultValue="false" title="开启下拉刷新" @change="change_refresher_enabled_boolean"></boolean-data>
<boolean-data :defaultValue="false" title="开启自定义样式" @change="change_refresher_style_boolean"></boolean-data>
<!-- #endif -->
<boolean-data :defaultValue="false" title="是否在设置滚动条位置时使用滚动动画,设置false没有滚动动画"
@change="change_scroll_with_animation_boolean"></boolean-data>
<boolean-data :defaultValue="false" title="控制是否出现滚动条" @change="change_show_scrollbar_boolean"></boolean-data>
<!-- #ifdef APP -->
<boolean-data :defaultValue="true" title="控制是否回弹效果" @change="change_bounces_boolean"></boolean-data>
<!-- #endif -->
<boolean-data :defaultValue="true" title="允许纵向滚动" @change="change_scroll_y_boolean"></boolean-data>
<!-- #ifdef APP -->
<boolean-data :defaultValue="false" title="允许横向滚动" @change="change_scroll_x_boolean"></boolean-data>
<!-- #endif -->
<input-data defaultValue="50" title="距顶部/左边多远时(单位px),触发 scrolltoupper 事件" type="number"
@confirm="confirm_upper_threshold_input"></input-data>
<input-data defaultValue="50" title="距底部/右边多远时(单位px),触发 scrolltolower 事件" type="number"
@confirm="confirm_lower_threshold_input"></input-data>
<input-data defaultValue="0" title="设置竖向滚动条位置" type="number" @confirm="confirm_scroll_top_input"></input-data>
<!-- #ifdef APP -->
<input-data defaultValue="0" title="设置横向滚动条位置" type="number" @confirm="confirm_scroll_left_input"></input-data>
<input-data defaultValue="#FFF" title="设置下拉刷新区域背景颜色" type="text"
@confirm="confirm_refresher_background_input"></input-data>
<enum-data :items="size_enum" title="通过id位置跳转" @change="item_change_size_enum"></enum-data>
<navigator url="/pages/component/list-view/list-view-refresh" hover-class="none">
<button type="primary" class="button">
list-view 下拉刷新
</button>
</navigator>
<!-- #endif -->
<navigator url="/pages/component/list-view/list-view-multiplex" hover-class="none">
<button type="primary" class="button">
list-view 对list-item复用测试
......
<template>
<scroll-view class="page">
<page-head :title="title"></page-head>
<view class="flex-row">
<view class="flex-fill">
<slider ref="slider1" v-for="(_, index1) in 25" :key="index1" class="slider" @changing="sliderChanging"
@change="sliderChange" :value="sliderValue" :block-size="20" :show-value="true" />
</view>
<view class="flex-fill">
<slider ref="slider2" v-for="(_, index2) in 25" :key="index2" class="slider" @changing="sliderChanging"
@change="sliderChange" :value="sliderValue" :block-size="20" :show-value="true" />
</view>
<view class="flex-fill">
<slider ref="slider3" v-for="(_, index3) in 25" :key="index3" class="slider" @changing="sliderChanging"
@change="sliderChange" :value="sliderValue" :block-size="20" :show-value="true" />
</view>
<view class="flex-fill">
<slider ref="slider4" v-for="(_, index4) in 25" :key="index4" class="slider" @changing="sliderChanging"
@change="sliderChange" :value="sliderValue" :block-size="20" :show-value="true" />
</view>
<view class="grid-view">
<slider ref="slider" class="slider" v-for="(_, index) in 100" :key="index" @changing="sliderChanging"
@change="sliderChange" :value="sliderValue" :block-size="20" :show-value="true" />
</view>
</scroll-view>
</template>
......@@ -38,19 +24,8 @@
this.updateSliderValue(e.detail.value)
},
updateSliderValue(value : number) {
// this.sliderValue = value
// TODO 跳过vue框架,直接修改原生组件
(this.$refs["slider1"] as UniSliderElement[]).forEach((item) => {
item.value = value
});
(this.$refs["slider2"] as UniSliderElement[]).forEach((item) => {
item.value = value
});
(this.$refs["slider3"] as UniSliderElement[]).forEach((item) => {
item.value = value
});
(this.$refs["slider4"] as UniSliderElement[]).forEach((item) => {
(this.$refs["slider"] as UniSliderElement[]).forEach((item) => {
item.value = value
});
}
......@@ -63,15 +38,14 @@
flex: 1;
}
.flex-row {
.grid-view {
flex-direction: row;
}
.flex-fill {
flex: 1;
flex-wrap: wrap;
}
.slider {
margin: 1px 0.5px;
width: 25%;
margin-top: 1px;
margin-bottom: 1px;
}
</style>
const PAGE_PATH = '/pages/component/text/text-props'
describe('text-props', () => {
let page
beforeAll(async () => {
const page = await program.navigateTo(PAGE_PATH)
page = await program.navigateTo(PAGE_PATH)
await page.waitFor(1000)
})
it('screenshot', async () => {
const image = await program.screenshot({ fullPage: true })
expect(image).toMatchImageSnapshot()
})
it('empty text', async () => {
const element = await page.$('#empty-text')
if (element != null) {
const { width, height } = await element.size()
expect(width).toBe(0)
expect(height).toBe(0)
}
})
if (process.env.uniTestPlatformInfo.indexOf('web') > -1) {
return
}
it('text nested', async () => {
page.callMethod("setTextNested")
const element = await page.$('#text-nested')
if (element != null) {
expect(await element.text()).toBe("二级节点文字红色且背景色黄色")
}
})
})
......@@ -27,8 +27,8 @@
<view class="uni-title">
<text class="uni-subtitle-text">截断(clip)</text>
</view>
<view class="text-box" style="height: 100px">
<text class="uni-flex-item" style="text-overflow: clip">{{
<view class="text-box">
<text class="uni-flex-item" style="text-overflow: clip;white-space: nowrap;">{{
multiLineText
}}</text>
</view>
......@@ -36,8 +36,8 @@
<view class="uni-title">
<text class="uni-subtitle-text">截断(ellipsis)</text>
</view>
<view class="text-box" style="height: 100px">
<text class="uni-flex-item" style="text-overflow: ellipsis">{{
<view class="text-box">
<text class="uni-flex-item" style="text-overflow: ellipsis;white-space: nowrap;">{{
multiLineText
}}</text>
</view>
......@@ -78,8 +78,8 @@
<view class="text-box">
<text
>一级节点黑色
<text style="color: red"
>二级节点红色
<text id="text-nested" ref="text-nested" style="color: red;background-color: yellow;"
>二级节点红色且背景色黄色
<text>三级节点不继承二级的颜色</text>
</text>
<text style="font-size: 50px">二级节点大字体</text>
......@@ -96,6 +96,10 @@
<text class="text-padding" style="width: 200px;height: 100px;">hello uni-app x</text>
</view>
<view class="uni-row">
<text id="empty-text"></text>
</view>
</view>
</scroll-view>
</template>
......@@ -110,7 +114,12 @@ export default {
singleLineText: 'uni-app x,终极跨平台方案',
}
},
methods: {},
methods: {
// 自动化测试
setTextNested() {
(this.$refs["text-nested"] as UniTextElement).value = "二级节点文字红色且背景色黄色";
}
}
}
</script>
......
......@@ -168,6 +168,10 @@
{
name: '动态加载字体',
url: 'load-font-face',
},
{
name: 'rpx2px',
url: 'rpx2px'
},
{
name: 'actionSheet操作菜单',
......@@ -463,24 +467,28 @@
}
] as Page[],
},
{
id: 'permission-listener',
name: '权限申请监听',
pages: [
{
name: '权限申请监听',
url: 'create-request-permission-listener',
}
] as Page[]
{
id: "payment",
name: "支付",
pages: [
{
name: "发起支付",
url: "request-payment",
},
] as Page[],
},
{
id: 'permission-listener',
name: '权限申请监听',
pages: [
{
name: '权限申请监听',
url: 'create-request-permission-listener',
}
] as Page[]
},
// #endif
/* {
id: "rewarded-video-ad",
url: "rewarded-video-ad",
name: "激励视频广告",
enable: false,
pages: [] as Page[]
},
/*
{
id: "full-screen-video-ad",
url: "full-screen-video-ad",
......@@ -512,16 +520,6 @@
},
] as Page[],
},
{
id: "payment",
name: "支付",
pages: [
{
name: "发起支付",
url: "request-payment",
},
] as Page[],
},
*/
] as ListItem[],
arrowUpIcon: '/static/icons/arrow-up.png',
......
......@@ -77,11 +77,10 @@
enable: false
},
*/
// #ifdef APP
// TODO web 实现list-view
{
name: 'list-view',
},
// #ifdef APP
{
name: 'sticky-header',
},
......
......@@ -54,8 +54,7 @@
export default {
data() {
return {
list: [
// #ifdef APP
list: [
{
id: 'long-list',
url: 'long-list',
......@@ -79,8 +78,7 @@
name: '列表到详情',
open: false,
pages: [] as Page[],
},
// #endif
},
{
id: 'scroll-fold-nav',
url: 'scroll-fold-nav',
......
// uni-app自动化测试教程: https://uniapp.dcloud.net.cn/worktile/auto/hbuilderx-extension/
describe('template-list-news', () => {
if (process.env.uniTestPlatformInfo.startsWith('web')) {
it('dummyTest', async () => {
expect(1).toBe(1)
})
return
}
let page;
beforeAll(async () => {
page = await program.reLaunch('/pages/template/list-news/list-news');
......
......@@ -4,7 +4,8 @@
<list-item class="banner" @click="bannerClick(banner)" type=1>
<image class="banner-img" :src="banner.cover"></image>
<text class="banner-title">{{ banner.title }}</text>
</list-item>
</list-item>
<!-- #ifdef APP -->
<sticky-header>
<view
style="width: 100%;height:44px;background-color: #f5f5f5;flex-direction: row;justify-content:center;align-items:center;">
......@@ -12,7 +13,8 @@
{{name}}
</text>
</view>
</sticky-header>
</sticky-header>
<!-- #endif -->
<list-item v-for="(value, index) in listData" :key="index" type=2>
<view class="uni-list-cell" hover-class="uni-list-cell-hover" @click="goDetail(value)">
<view class="uni-media-list">
......
......@@ -30,7 +30,7 @@
</template>
<script>
const SERVER_URL = "https://ext.dcloud.net.cn/plugin/uniappx-plugin-list"
const SERVER_URL = "https://unidemo.dcloud.net.cn/plugin/uniappx-plugin-list"
const PAGE_SIZE = 10; // 最大值 10
type ListItem = {
......@@ -70,7 +70,7 @@
dataList: [] as ListItem[],
isEnded: false,
loadingError: '',
$currentPage: 1
currentPage: 1
}
},
computed: {
......@@ -94,7 +94,7 @@
methods: {
refreshData(loadComplete : (() => void) | null) {
this.dataList.length = 0
this.$currentPage = 1
this.currentPage = 1
this.loadData(loadComplete)
},
loadData(loadComplete : (() => void) | null) {
......@@ -107,7 +107,7 @@
url: SERVER_URL,
data: {
type: this.type,
page: this.$currentPage,
page: this.currentPage,
page_size: PAGE_SIZE
},
success: (res) => {
......@@ -121,7 +121,7 @@
if (responseData.data.length == 0) {
this.isEnded = true
} else {
this.$currentPage++
this.currentPage++
}
},
fail: (err) => {
......@@ -241,4 +241,7 @@
align-items: center;
}
.flex-row {
flex-direction: row;
}
</style>
......@@ -7,7 +7,7 @@
<view class="swiper-list">
<scroll-view ref="tabScroll" class="swiper-tabs" direction="horizontal" :show-scrollbar="false">
<view class="flex-row" style="align-self: flex-start;">
<text ref="swipertab" class="swiper-tabs-item" :class="swiperIndex==index ? 'swiper-tabs-item-active' : ''"
<text ref="swipertab" space="nbsp" class="swiper-tabs-item" :class="swiperIndex==index ? 'swiper-tabs-item-active' : ''"
v-for="(item, index) in swiperList" :key="index" @click="onTabClick(index)">
{{item.name}}
</text>
......@@ -78,24 +78,24 @@
preload: false
} as SwiperViewItem
] as SwiperViewItem[],
swiperIndex: -1,
$pageScrollView: null as null | UniElement,
$headerHeight: 0,
$animationFinishIndex: 0,
$tabScrollView: null as null | UniElement,
$indicatorNode: null as null | UniElement,
$swiperWidth: 0,
$swiperTabsRect: [] as SwiperTabsItem[]
swiperIndex: 0,
pageScrollView: null as null | UniElement,
headerHeight: 0,
animationFinishIndex: 0,
tabScrollView: null as null | UniElement,
indicatorNode: null as null | UniElement,
swiperWidth: 0,
swiperTabsRect: [] as SwiperTabsItem[]
}
},
onReady() {
this.$pageScrollView = this.$refs['pageScrollView'] as UniElement;
this.$headerHeight = (this.$refs['header'] as UniElement).offsetHeight
this.$swiperWidth = (this.$refs['swiper'] as UniElement).getBoundingClientRect().width
this.$tabScrollView = this.$refs['tabScroll'] as UniElement
this.$indicatorNode = this.$refs['indicator'] as UniElement
this.pageScrollView = this.$refs['pageScrollView'] as UniElement;
this.headerHeight = (this.$refs['header'] as UniElement).offsetHeight
this.swiperWidth = (this.$refs['swiper'] as UniElement).getBoundingClientRect().width
this.tabScrollView = this.$refs['tabScroll'] as UniElement
this.indicatorNode = this.$refs['indicator'] as UniElement
this.cacheTabItemsSize()
this.setSwiperIndex(0, true)
this.updateTabIndicator(this.swiperIndex, this.swiperIndex, 1)
},
onPullDownRefresh() {
(this.$refs["longPage"]! as ComponentPublicInstance[])[this.swiperIndex].$callMethod('refreshData', () => {
......@@ -109,28 +109,28 @@
},
onNestedPreScroll(event : NestedPreScrollEvent) {
const deltaY = event.deltaY
const scrollTop = this.$pageScrollView!.scrollTop
const scrollTop = this.pageScrollView!.scrollTop
// 优先处理父容器滚动,父容器不能滚动时滚动子
if (deltaY > 0) {
// 向上滚动,如果父容器 header scrollTop < offsetHeight,先滚动父容器
if (scrollTop < this.$headerHeight) {
const difference = this.$headerHeight - scrollTop - deltaY
if (scrollTop < this.headerHeight) {
const difference = this.headerHeight - scrollTop - deltaY
if (difference > 0) {
this.$pageScrollView!.scrollBy(event.deltaX, deltaY)
this.pageScrollView!.scrollBy(event.deltaX, deltaY)
event.consumed(event.deltaX, deltaY)
} else {
const top : number = deltaY + difference
event.consumed(event.deltaX, top.toFloat())
this.$pageScrollView!.scrollBy(event.deltaX, top.toFloat())
this.pageScrollView!.scrollBy(event.deltaX, top.toFloat())
}
}
} else if (deltaY < 0) {
// 向下滚动,如果父容器 scrollTop > 0,通知子被父容器消耗,然后滚动到 0
if (scrollTop > 0) {
event.consumed(event.deltaX, deltaY)
this.$pageScrollView!.scrollBy(event.deltaX, deltaY)
this.pageScrollView!.scrollBy(event.deltaX, deltaY)
}
}
},
......@@ -146,9 +146,9 @@
const offset_x = e.detail.dx
// 计算当前索引并重置差异
const current_offset_x = offset_x % this.$swiperWidth
const current_offset_i = offset_x / this.$swiperWidth
const current_index = this.$animationFinishIndex + parseInt(current_offset_i + '')
const current_offset_x = offset_x % this.swiperWidth
const current_offset_i = offset_x / this.swiperWidth
const current_index = this.animationFinishIndex + parseInt(current_offset_i + '')
// 计算目标索引及边界检查
let move_to_index = current_index
......@@ -159,7 +159,7 @@
}
// 计算偏移百分比
const percentage = Math.abs(current_offset_x) / this.$swiperWidth
const percentage = Math.abs(current_offset_x) / this.swiperWidth
// 通知更新指示线
this.updateTabIndicator(current_index, move_to_index, percentage)
......@@ -169,14 +169,14 @@
},
onSwiperAnimationfinish(e : SwiperAnimationFinishEvent) {
this.setSwiperIndex(e.detail.current, true)
this.$animationFinishIndex = e.detail.current
console.log('this.$animationFinishIndex', e.detail.current);
this.animationFinishIndex = e.detail.current
console.log('this.animationFinishIndex', e.detail.current);
},
cacheTabItemsSize() {
this.$swiperTabsRect.length = 0
this.swiperTabsRect.length = 0
const tabs = this.$refs["swipertab"] as UniElement[]
tabs.forEach((node) => {
this.$swiperTabsRect.push({
this.swiperTabsRect.push({
x: node.offsetLeft,
w: node.offsetWidth
} as SwiperTabsItem)
......@@ -196,21 +196,29 @@
}
},
updateTabIndicator(current_index : number, move_to_index : number, percentage : number) {
const current_size = this.$swiperTabsRect[current_index]
const move_to_size = this.$swiperTabsRect[move_to_index]
const current_size = this.swiperTabsRect[current_index]
const move_to_size = this.swiperTabsRect[move_to_index]
// 计算指示线 左边距 和 宽度 在移动过程中的线性值
const indicator_line_x = lerpNumber(current_size.x, move_to_size.x, percentage)
const indicator_line_w = lerpNumber(current_size.w, move_to_size.w, percentage)
// 更新指示线
// #ifdef APP
const x = indicator_line_x + indicator_line_w / 2
this.$indicatorNode?.style?.setProperty('transform', `translateX(${x}px) scaleX(${indicator_line_w})`)
this.indicatorNode?.style?.setProperty('transform', `translateX(${x}px) scaleX(${indicator_line_w})`)
// #endif
// #ifdef WEB
// TODO chrome windows系统 transform scaleX渲染bug
const x = indicator_line_x
this.indicatorNode?.style?.setProperty('width', `${indicator_line_w}px`)
this.indicatorNode?.style?.setProperty('transform', `translateX(${x}px)`)
// #endif
// 滚动到水平中心位置
const scroll_x = x - this.$swiperWidth / 2
if(this.$tabScrollView !== null){
this.$tabScrollView!.scrollLeft = scroll_x
const scroll_x = x - this.swiperWidth / 2
if(this.tabScrollView != null){
this.tabScrollView!.scrollLeft = scroll_x
}
},
initSwiperItemData(index : number) {
......@@ -238,6 +246,9 @@
.swiper-list {
height: 100%;
/* #ifdef WEB */
flex: 1;
/* #endif */
}
.swiper-tabs {
......@@ -249,6 +260,7 @@
color: #555;
font-size: 16px;
padding: 12px 25px;
white-space: nowrap;
}
.swiper-tabs-item-active {
......
......@@ -88,25 +88,25 @@
preload: false
} as SwiperViewItem
] as SwiperViewItem[],
swiperIndex: -1,
$pageScrollView: null as null | UniElement,
$headerHeight: 0,
$animationFinishIndex: 0,
$tabScrollView: null as null | UniElement,
$indicatorNode: null as null | UniElement,
$swiperWidth: 0,
$swiperTabsRect: [] as SwiperTabsItem[],
swiperIndex: 0,
pageScrollView: null as null | UniElement,
headerHeight: 0,
animationFinishIndex: 0,
tabScrollView: null as null | UniElement,
indicatorNode: null as null | UniElement,
swiperWidth: 0,
swiperTabsRect: [] as SwiperTabsItem[],
nestedScrollChildId: ""
}
},
onReady() {
this.$pageScrollView = this.$refs['pageScrollView'] as UniElement;
this.$headerHeight = (this.$refs['header'] as UniElement).offsetHeight
this.$swiperWidth = (this.$refs['swiper'] as UniElement).getBoundingClientRect().width
this.$tabScrollView = this.$refs['tabScroll'] as UniElement
this.$indicatorNode = this.$refs['indicator'] as UniElement
this.pageScrollView = this.$refs['pageScrollView'] as UniElement;
this.headerHeight = (this.$refs['header'] as UniElement).offsetHeight
this.swiperWidth = (this.$refs['swiper'] as UniElement).getBoundingClientRect().width
this.tabScrollView = this.$refs['tabScroll'] as UniElement
this.indicatorNode = this.$refs['indicator'] as UniElement
this.cacheTabItemsSize()
this.setSwiperIndex(0, true)
this.updateTabIndicator(this.swiperIndex, this.swiperIndex, 1)
},
onPullDownRefresh() {
(this.$refs["longPage"]! as ComponentPublicInstance[])[this.swiperIndex].$callMethod('refreshData', () => {
......@@ -120,19 +120,19 @@
},
onNestedPreScroll(event : NestedPreScrollEvent) {
const deltaY = event.deltaY
const scrollTop = this.$pageScrollView!.scrollTop
const scrollTop = this.pageScrollView!.scrollTop
if (deltaY > 0) {
// 向上滚动,如果父容器 header scrollTop < offsetHeight,先滚动父容器
if (scrollTop < this.$headerHeight) {
const difference = this.$headerHeight - scrollTop - deltaY
if (scrollTop < this.headerHeight) {
const difference = this.headerHeight - scrollTop - deltaY
if (difference > 0) {
this.$pageScrollView!.scrollBy(event.deltaX, deltaY)
this.pageScrollView!.scrollBy(event.deltaX, deltaY)
event.consumed(event.deltaX, deltaY)
} else {
const top : number = deltaY + difference
event.consumed(event.deltaX, top.toFloat())
this.$pageScrollView!.scrollBy(event.deltaX, top.toFloat())
this.pageScrollView!.scrollBy(event.deltaX, top.toFloat())
}
}
}
......@@ -149,9 +149,9 @@
const offset_x = e.detail.dx
// 计算当前索引并重置差异
const current_offset_x = offset_x % this.$swiperWidth
const current_offset_i = offset_x / this.$swiperWidth
const current_index = this.$animationFinishIndex + parseInt(current_offset_i + '')
const current_offset_x = offset_x % this.swiperWidth
const current_offset_i = offset_x / this.swiperWidth
const current_index = this.animationFinishIndex + parseInt(current_offset_i + '')
// 计算目标索引及边界检查
let move_to_index = current_index
......@@ -162,23 +162,25 @@
}
// 计算偏移百分比
const percentage = Math.abs(current_offset_x) / this.$swiperWidth
const percentage = Math.abs(current_offset_x) / this.swiperWidth
// 通知更新指示线
this.updateTabIndicator(current_index, move_to_index, percentage)
if (current_index != move_to_index) {
this.updateTabIndicator(current_index, move_to_index, percentage)
}
// 首次可见时初始化数据
this.initSwiperItemData(move_to_index)
},
onSwiperAnimationfinish(e : SwiperAnimationFinishEvent) {
this.setSwiperIndex(e.detail.current, true)
this.$animationFinishIndex = e.detail.current
this.animationFinishIndex = e.detail.current
},
cacheTabItemsSize() {
this.$swiperTabsRect.length = 0
this.swiperTabsRect.length = 0
const tabs = this.$refs["swipertab"] as UniElement[]
tabs.forEach((node) => {
this.$swiperTabsRect.push({
this.swiperTabsRect.push({
x: node.offsetLeft,
w: node.offsetWidth
} as SwiperTabsItem)
......@@ -198,21 +200,29 @@
}
},
updateTabIndicator(current_index : number, move_to_index : number, percentage : number) {
const current_size = this.$swiperTabsRect[current_index]
const move_to_size = this.$swiperTabsRect[move_to_index]
const current_size = this.swiperTabsRect[current_index]
const move_to_size = this.swiperTabsRect[move_to_index]
// 计算指示线 左边距 和 宽度 在移动过程中的线性值
const indicator_line_x = lerpNumber(current_size.x, move_to_size.x, percentage)
const indicator_line_w = lerpNumber(current_size.w, move_to_size.w, percentage)
// 更新指示线
// #ifdef APP
const x = indicator_line_x + indicator_line_w / 2
this.$indicatorNode?.style?.setProperty('transform', `translateX(${x}px) scaleX(${indicator_line_w})`)
this.indicatorNode?.style?.setProperty('transform', `translateX(${x}px) scaleX(${indicator_line_w})`)
// #endif
// #ifdef WEB
// TODO chrome windows系统 transform scaleX渲染bug
const x = indicator_line_x
this.indicatorNode?.style?.setProperty('width', `${indicator_line_w}px`)
this.indicatorNode?.style?.setProperty('transform', `translateX(${x}px)`)
// #endif
// 滚动到水平中心位置
const scroll_x = x - this.$swiperWidth / 2
if(this.$tabScrollView !== null){
this.$tabScrollView!.scrollLeft = scroll_x
const scroll_x = x - this.swiperWidth / 2
if(this.tabScrollView !== null){
this.tabScrollView!.scrollLeft = scroll_x
}
},
initSwiperItemData(index : number) {
......@@ -242,6 +252,9 @@
.swiper-list {
height: 100%;
/* #ifdef WEB */
flex: 1;
/* #endif */
}
.swiper-tabs {
......@@ -253,6 +266,7 @@
color: #555;
font-size: 16px;
padding: 12px 25px;
white-space: nowrap;
}
.swiper-tabs-item-active {
......
......@@ -162,8 +162,16 @@
const indicator_line_w = lerpNumber(current_size.w, move_to_size.w, percentage)
// 通过 transform 更新指示线,避免重排版
// #ifdef APP
const x = indicator_line_x + indicator_line_w / 2
this.indicatorNode!.style.setProperty('transform', `translateX(${x}px) scaleX(${indicator_line_w})`)
this.indicatorNode?.style?.setProperty('transform', `translateX(${x}px) scaleX(${indicator_line_w})`)
// #endif
// #ifdef WEB
// TODO chrome windows系统 transform scaleX渲染bug
const x = indicator_line_x
this.indicatorNode?.style?.setProperty('width', `${indicator_line_w}px`)
this.indicatorNode?.style?.setProperty('transform', `translateX(${x}px)`)
// #endif
// 滚动到水平中心位置
const scroll_x = x - this.swiperWidth / 2
......@@ -191,6 +199,7 @@
color: #555;
font-size: 16px;
padding: 12px 25px;
white-space: nowrap;
}
.swiper-tabs-item-active {
......
......@@ -143,6 +143,7 @@
color: #555;
font-size: 16px;
margin: 15px 25px 5px 25px;
white-space: nowrap;
}
.swiper-tabs-item-active {
......
## 1.0.6(2024-02-28)
- 更新 Circle 组件名称,防止与内置组件名冲突
## 1.0.5(2024-01-12)
- 优化 删除组件内无用日志输出
## 1.0.4(2024-01-10)
- 优化 兼容 uvue h5 项目
## 1.0.3(2023-12-22)
......
<template>
<uni-icons :id="elId" class='load-ani' :style="aniStyle" @transitionend="onEnd" :type="iconType" :size="size" :color="color"></uni-icons>
</template>
<script>
<template>
<uni-icons :id="elId" class='load-ani' :style="aniStyle" @transitionend="onEnd" :type="iconType" :size="size" :color="color"></uni-icons>
</template>
<script>
export default {
name:'icon',
props: {
iconType: {
type: String,
default: 'loop'
},
size: {
type: Number,
default: 0
},
color: {
type: String,
default: '#333'
}
},
data() {
const elId = `Uni_${(Math.random() * 10e5).toInt().toString(36)}`
return {
elId: elId,
element: null as UniElement | null,
times: 0,
aniStyle: '',
deg: 3600000
}
},
created() {
this.times = 0
// 需要延迟一些时间,否则动画不生效
setTimeout(() => {
this.aniStyle = 'transform:rotate(1deg);'
}, 300)
},
mounted() {
this.element = uni.getElementById(this.elId as string)
},
methods: {
onEnd() {
// 因为循环角度是不断增加,在增加10次以后需要重置,防止无限增加下去
if (this.times == 10) {
this.element!.style.setProperty('transform', 'rotate(0deg)')
this.element!.style.setProperty('transition-duration', '1')
this.times = 0
return
}
this.times = this.times + 1
const rotate = this.times * 360
this.element!.style.setProperty('transform', 'rotate(' + rotate + 'deg)')
this.element!.style.setProperty('transition-duration', '1000')
}
}
}
</script>
<style>
.load-ani {
transition-property: transform;
transition-duration: 0.1s;
transition-timing-function: linear;
transform: rotate(0deg);
}
name:'icon',
props: {
iconType: {
type: String,
default: 'loop'
},
size: {
type: Number,
default: 0
},
color: {
type: String,
default: '#333'
}
},
data() {
const elId = `Uni_${(Math.random() * 10e5).toInt().toString(36)}`
return {
elId: elId,
element: null as UniElement | null,
times: 0,
aniStyle: '',
deg: 3600000
}
},
created() {
this.times = 0
// 需要延迟一些时间,否则动画不生效
setTimeout(() => {
this.aniStyle = 'transform:rotate(1deg);'
}, 300)
},
mounted() {
this.element = uni.getElementById(this.elId as string)
},
methods: {
onEnd() {
// 因为循环角度是不断增加,在增加10次以后需要重置,防止无限增加下去
if (this.times == 10) {
this.element!.style.setProperty('transform', 'rotate(0deg)')
this.element!.style.setProperty('transition-duration', '1')
this.times = 0
return
}
this.times = this.times + 1
const rotate = this.times * 360
this.element!.style.setProperty('transform', 'rotate(' + rotate + 'deg)')
this.element!.style.setProperty('transition-duration', '1000')
}
}
}
</script>
<style>
.load-ani {
transition-property: transform;
transition-duration: 0.1s;
transition-timing-function: linear;
transform: rotate(0deg);
}
</style>
<template>
<!-- #ifdef APP -->
<view :ref="elId" class="block" :style="{width:size+'px',height:size+'px'}"></view>
<!-- #endif -->
<!-- #ifdef WEB -->
<svg :width="size" :height="size" viewBox="25 25 50 50" :style="{width:size+'px',height:size+'px'}" class="uni-load__img uni-load__img--android-H5">
<circle cx="50" cy="50" r="20" fill="none" :style="{color:color}" :stroke-width="iconsSize"></circle>
</svg>
<!-- #endif -->
</template>
<script>
import { easeInOutCubic } from './util'
let elId = 0
export default {
name: "circle",
props: {
speed: {
type: Number,
default: 16,
},
size: {
type: Number,
default: 20,
},
color: {
type: String,
default: '#666',
}
},
data() {
// 防止多调用,随机元素id
elId += 1
const elID = `Uni_Load_Circle_${elId}`
return {
elId: elID,
timer: 0,
};
},
computed: {
iconsSize() : number {
console.log(this.size / 10);
return (this.size / 10) +1
}
},
mounted() {
// #ifdef APP
this.init()
// #endif
},
unmounted() {
// 组件卸载时,需要卸载定时器,优化性能,防止页面卡死
clearInterval(this.timer)
},
methods: {
/**
* 初始化圆环
*/
init() {
const refs = this.$refs[this.elId] as UniElement
let ctx = refs.getDrawableContext()!
this.build_circular(ctx)
},
/**
* 构建圆环动画
*/
build_circular(ctx : DrawableContext) {
let startAngle = 0;
let rotate = 0;
const ARC_LENGTH = 359;
const center = this.size / 2; // 圆心
const lineWidth = this.size / 10; // 圆环宽度
const duration = 1200; // 动画持续时间
const interval = this.speed; // 定时器间隔(大约 60 帧每秒)
// 使圆环过度更自然,不必运动到底
const ARC_MAX = 358
let startTime = 0;
let foreward_end = 0 // 正传
let reversal_end = ARC_MAX // 反转
function pogress_time() : number {
const currentTime = Date.now();
// 运动时间计算
const elapsedTime = currentTime - startTime;
const progress = elapsedTime / duration;
// 动画缓动
const easedProgress = easeInOutCubic(progress);
return easedProgress
}
const draw = () => {
ctx.reset();
ctx.beginPath();
if (reversal_end == ARC_MAX) {
foreward_end = Math.min(pogress_time() * ARC_LENGTH, ARC_LENGTH); // 限制 end 的最大值为 ARC_LENGTH
if (foreward_end >= ARC_MAX) {
reversal_end = 0
foreward_end = ARC_MAX
startTime = Date.now();
}
}
if (foreward_end == ARC_MAX) {
reversal_end = Math.min(pogress_time() * ARC_LENGTH, ARC_LENGTH);
if (reversal_end >= ARC_MAX) {
reversal_end = ARC_MAX
foreward_end = 0
startTime = Date.now();
}
}
ctx.arc(
center,
center,
center - lineWidth,
startAngle + rotate + (reversal_end * Math.PI / 180),
startAngle + rotate + (foreward_end * Math.PI / 180)
);
ctx.lineWidth = lineWidth;
const fillColor = (this.color !== '' ? this.color : '#666').toString();
ctx.strokeStyle = fillColor;
ctx.stroke();
ctx.update();
rotate += 0.05; // 旋转速度
}
this.timer = setInterval(() => draw(), interval);
}
}
}
</script>
<style scoped>
.block {
width: 50px;
height: 50px;
}
/* #ifdef WEB */
.uni-load__img {
width: 24px;
height: 24px;
}
.uni-load__img--android-H5 {
animation: loading-android-H5-rotate 2s linear infinite;
transform-origin: center center;
}
.uni-load__img--android-H5 circle {
display: inline-block;
animation: loading-android-H5-dash 1.5s ease-in-out infinite;
stroke: currentColor;
stroke-linecap: round;
}
@keyframes loading-android-H5-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-H5-dash {
0% {
stroke-dasharray: 1, 200;
/* stroke-dashoffset: 0; */
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -20;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -120;
}
}
/* #endif */
<template>
<!-- #ifdef APP -->
<view :ref="elId" class="block" :style="{width:size+'px',height:size+'px'}"></view>
<!-- #endif -->
<!-- #ifdef WEB -->
<svg :width="size" :height="size" viewBox="25 25 50 50" :style="{width:size+'px',height:size+'px'}" class="uni-load__img uni-load__img--android-H5">
<circle cx="50" cy="50" r="20" fill="none" :style="{color:color}" :stroke-width="iconsSize"></circle>
</svg>
<!-- #endif -->
</template>
<script>
import { easeInOutCubic } from './util'
let elId = 0
export default {
name: "circle",
props: {
speed: {
type: Number,
default: 16,
},
size: {
type: Number,
default: 20,
},
color: {
type: String,
default: '#666',
}
},
data() {
// 防止多调用,随机元素id
elId += 1
const elID = `Uni_Load_Circle_${elId}`
return {
elId: elID,
timer: 0,
};
},
computed: {
iconsSize() : number {
return (this.size / 10) +1
}
},
mounted() {
// #ifdef APP
this.init()
// #endif
},
unmounted() {
// 组件卸载时,需要卸载定时器,优化性能,防止页面卡死
clearInterval(this.timer)
},
methods: {
/**
* 初始化圆环
*/
init() {
const refs = this.$refs[this.elId] as UniElement
let ctx = refs.getDrawableContext()!
this.build_circular(ctx)
},
/**
* 构建圆环动画
*/
build_circular(ctx : DrawableContext) {
let startAngle = 0;
let rotate = 0;
const ARC_LENGTH = 359;
const center = this.size / 2; // 圆心
const lineWidth = this.size / 10; // 圆环宽度
const duration = 1200; // 动画持续时间
const interval = this.speed; // 定时器间隔(大约 60 帧每秒)
// 使圆环过度更自然,不必运动到底
const ARC_MAX = 358
let startTime = 0;
let foreward_end = 0 // 正传
let reversal_end = ARC_MAX // 反转
function pogress_time() : number {
const currentTime = Date.now();
// 运动时间计算
const elapsedTime = currentTime - startTime;
const progress = elapsedTime / duration;
// 动画缓动
const easedProgress = easeInOutCubic(progress);
return easedProgress
}
const draw = () => {
ctx.reset();
ctx.beginPath();
if (reversal_end == ARC_MAX) {
foreward_end = Math.min(pogress_time() * ARC_LENGTH, ARC_LENGTH); // 限制 end 的最大值为 ARC_LENGTH
if (foreward_end >= ARC_MAX) {
reversal_end = 0
foreward_end = ARC_MAX
startTime = Date.now();
}
}
if (foreward_end == ARC_MAX) {
reversal_end = Math.min(pogress_time() * ARC_LENGTH, ARC_LENGTH);
if (reversal_end >= ARC_MAX) {
reversal_end = ARC_MAX
foreward_end = 0
startTime = Date.now();
}
}
ctx.arc(
center,
center,
center - lineWidth,
startAngle + rotate + (reversal_end * Math.PI / 180),
startAngle + rotate + (foreward_end * Math.PI / 180)
);
ctx.lineWidth = lineWidth;
const fillColor = (this.color !== '' ? this.color : '#666').toString();
ctx.strokeStyle = fillColor;
ctx.stroke();
ctx.update();
rotate += 0.05; // 旋转速度
}
this.timer = setInterval(() => draw(), interval);
}
}
}
</script>
<style scoped>
.block {
width: 50px;
height: 50px;
}
/* #ifdef WEB */
.uni-load__img {
width: 24px;
height: 24px;
}
.uni-load__img--android-H5 {
animation: loading-android-H5-rotate 2s linear infinite;
transform-origin: center center;
}
.uni-load__img--android-H5 circle {
display: inline-block;
animation: loading-android-H5-dash 1.5s ease-in-out infinite;
stroke: currentColor;
stroke-linecap: round;
}
@keyframes loading-android-H5-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-H5-dash {
0% {
stroke-dasharray: 1, 200;
/* stroke-dashoffset: 0; */
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -20;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -120;
}
}
/* #endif */
</style>
<template>
<view :ref="elId" class="block" :style="{width:size+'px',height:size+'px'}"></view>
</template>
<script>
import { hexToRgba } from './util'
export default {
name: "uni-snow",
props: {
speed: {
type: Number,
default: 16,
},
size: {
type: Number,
default: 20,
},
color: {
type: String,
default: '',
}
},
data() {
const elId = `Uni_${(Math.random() * 10e5).toInt().toString(36)}`
return {
elId: elId,
timer: 0,
};
},
mounted() {
const refs = this.$refs[this.elId] as UniElement
let ctx = refs.getDrawableContext()!
this.spinner(ctx)
},
unmounted() {
clearInterval(this.timer)
},
methods: {
spinner(ctx : DrawableContext) {
const steps = 12;
let step = 0;
const width = this.size;
const lineWidth = width / 12;
// 线长度和距离圆心距离
const length = width / 4 - lineWidth;
const offset = width / 4;
function draw() {
ctx.reset();
for (let i = 0; i < steps; i++) {
const stepAngle = 360 / steps;
const angle = stepAngle * i;
// 计算透明度
const opacity = ((steps - (step % steps)) * stepAngle + angle) % 360 + 30;
// 计算正余弦值
const sin = Math.sin((angle / 180) * Math.PI);
const cos = Math.cos((angle / 180) * Math.PI);
// 开始绘制线条
ctx.lineWidth = lineWidth;
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(width / 2 + offset * cos, width / 2 + offset * sin);
ctx.lineTo(
width / 2 + (offset + length) * cos,
width / 2 + (offset + length) * sin
);
// 获取填充颜色
const fillColor = this.color !== '' ? this.color : '#333333';
// 转换透明度并设置颜色
ctx.strokeStyle = hexToRgba(fillColor, Math.round((opacity / 360) * 255));
ctx.stroke();
}
step += 1;
ctx.update();
}
draw()
// 每隔一段时间执行绘制函数
this.timer = setInterval(() => draw(), this.speed + 76);
}
}
}
</script>
<style scoped>
.block {
width: 50px;
height: 50px;
}
</style>
<template>
<!-- 如果没有插槽,则使用 load-inline 样式 -->
<view class="uni-loading-main" :class="{'load-inline':$slots['default'] == null}">
<template v-if="loading">
<slot></slot>
<template v-if="$slots['default'] == null">
<Circle :speed="16" :size="loadWidth" :color="color"></Circle>
<text v-if="text" class="inline-text" :style=" { color: color }">{{text}}</text>
</template>
<template v-else>
<view class="uni-loading-mask" :style="{backgroundColor:background}">
<Circle :speed="16" :size="loadWidth" :color="color"></Circle>
<text v-if="text" class="block-text" :style=" { color: color }">{{text}}</text>
</view>
</template>
</template>
<template v-else>
<slot></slot>
</template>
</view>
</template>
<script>
import Circle from './circle.uvue'
// TODO 性能问题,其他类型暂时不对外开放
// import Icon from './icon.uvue'
// import UniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue'
// import { img_load_base } from './load-img.uts'
/**
* Loading-x 加载动画
* @description 用于数据加载场景,使用loading等待数据返回
* @tutorial https://ext.dcloud.net.cn/plugin?name=uni-loading-x
* @property {Boolean} loading 是否显示加载动画,默认:true
* @property {String} type = [snow|circle|icon] 加载图标显示,默认:circle
* @value snow 显示雪花加载动画,性能问题暂时不支持
* @value circle 显示圆形加载动画
* @value icon 自定义图标 ,暂时不支持
* @property {String} background 加载遮罩颜色,支持 rgba 色值,默认:rgba(255,255,255,0.6)
* @property {String} color 加载图标以及加载文字颜色,默认:#333333
* @property {String} size 加载图标大小,默认:20
* @property {String} text 加载文本,默认:不显示
* @property {String} iconType 自定义图标类型,参考 uni-icons ,当前版本暂不支持
*/
export default {
name: "uni-loading",
components: { Circle },
props: {
loading: {
type: Boolean,
default: true,
},
type: {
type: String,
default: ''
},
iconType: {
type: String,
default: 'gear-filled'
},
size: {
type: Number,
default: 0
},
text: {
type: String,
default: ''
},
background: {
type: String,
default: 'rgba(255,255,255,0.6)'
},
color: {
type: String,
default: '#333'
}
},
data() {
return {};
},
computed: {
loadWidth() : number {
let width = this.size
if (width == 0) {
return 20
}
return width
},
styles() : string {
return `width:${this.loadWidth}px;height:${this.loadWidth}px;`
}
},
created() {},
methods: {}
}
</script>
<style scoped>
.uni-loading-main {
position: relative;
}
.uni-loading-main.load-inline {
display: flex;
flex-direction: row;
align-items: center;
}
.block-text {
margin-top: 8px;
font-size: 14px;
}
.inline-text {
margin-left: 8px;
font-size: 14px;
}
.uni-loading-mask {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
justify-content: center;
}
.uni-loading-mask {
background-color: rgba(0, 0, 0, 0.3);
z-index: 2;
}
.uni-load {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.load-text {
font-size: 14px;
color: #fff;
margin-top: 12px;
}
.uni-load .image,
.load-image {
width: 100%;
height: 100%;
}
.load-ani {
transition-property: transform;
transition-duration: 0.1s;
transition-timing-function: linear;
transform: rotate(0deg);
}
<template>
<!-- 如果没有插槽,则使用 load-inline 样式 -->
<view class="uni-loading-main" :class="{'load-inline':$slots['default'] == null}">
<template v-if="loading">
<slot></slot>
<template v-if="$slots['default'] == null">
<LoadingCircle :speed="16" :size="loadWidth" :color="color"></LoadingCircle>
<text v-if="text" class="inline-text" :style=" { color: color }">{{text}}</text>
</template>
<template v-else>
<view class="uni-loading-mask" :style="{backgroundColor:background}">
<LoadingCircle :speed="16" :size="loadWidth" :color="color"></LoadingCircle>
<text v-if="text" class="block-text" :style=" { color: color }">{{text}}</text>
</view>
</template>
</template>
<template v-else>
<slot></slot>
</template>
</view>
</template>
<script>
import LoadingCircle from './loading-circle.uvue'
// TODO 性能问题,其他类型暂时不对外开放
// import Icon from './icon.uvue'
// import UniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue'
// import { img_load_base } from './load-img.uts'
/**
* Loading-x 加载动画
* @description 用于数据加载场景,使用loading等待数据返回
* @tutorial https://ext.dcloud.net.cn/plugin?name=uni-loading-x
* @property {Boolean} loading 是否显示加载动画,默认:true
* @property {String} type = [snow|circle|icon] 加载图标显示,默认:circle
* @value snow 显示雪花加载动画,性能问题暂时不支持
* @value circle 显示圆形加载动画
* @value icon 自定义图标 ,暂时不支持
* @property {String} background 加载遮罩颜色,支持 rgba 色值,默认:rgba(255,255,255,0.6)
* @property {String} color 加载图标以及加载文字颜色,默认:#333333
* @property {String} size 加载图标大小,默认:20
* @property {String} text 加载文本,默认:不显示
* @property {String} iconType 自定义图标类型,参考 uni-icons ,当前版本暂不支持
*/
export default {
name: "uni-loading",
components: { LoadingCircle },
props: {
loading: {
type: Boolean,
default: true,
},
type: {
type: String,
default: ''
},
iconType: {
type: String,
default: 'gear-filled'
},
size: {
type: Number,
default: 0
},
text: {
type: String,
default: ''
},
background: {
type: String,
default: 'rgba(255,255,255,0.6)'
},
color: {
type: String,
default: '#333'
}
},
data() {
return {};
},
computed: {
loadWidth() : number {
let width = this.size
if (width == 0) {
return 20
}
return width
},
styles() : string {
return `width:${this.loadWidth}px;height:${this.loadWidth}px;`
}
},
created() {},
methods: {}
}
</script>
<style scoped>
.uni-loading-main {
position: relative;
}
.uni-loading-main.load-inline {
display: flex;
flex-direction: row;
align-items: center;
}
.block-text {
margin-top: 8px;
font-size: 14px;
}
.inline-text {
margin-left: 8px;
font-size: 14px;
}
.uni-loading-mask {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
justify-content: center;
}
.uni-loading-mask {
background-color: rgba(0, 0, 0, 0.3);
z-index: 2;
}
.uni-load {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.load-text {
font-size: 14px;
color: #fff;
margin-top: 12px;
}
.uni-load .image,
.load-image {
width: 100%;
height: 100%;
}
.load-ani {
transition-property: transform;
transition-duration: 0.1s;
transition-timing-function: linear;
transform: rotate(0deg);
}
</style>
/**
* hex颜色转rgba
*/
export const hexToRgba = (hex : string, alpha : number) : string => {
// 去除 # 符号(如果有的话)
hex = hex.replace('#', '');
let hexArray = hex.split('');
// 检查颜色值长度,如果不符合预期则返回默认值或者抛出错误
if (hexArray.length != 3 && hexArray.length != 6) {
// 返回默认值或者抛出错误,这里使用默认值为黑色
return 'rgba(0,0,0,1)';
// 或者抛出错误
// throw new Error('Invalid hex color value');
}
let extendedHex : string[] = [];
if (hex.length == 3) {
for (let i = 0; i < hexArray.length; i++) {
extendedHex.push(hexArray[i]);
extendedHex.push(hexArray[i]);
}
hexArray = extendedHex;
}
hex = ''
for (let h = 0; h < hexArray.length; h++) {
hex += hexArray[h]
}
// // 拆分颜色值为 R、G、B
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
// // 返回 rgba 值
return `rgba(${r},${g},${b},${alpha})`;
}
export const easeInOutCubic = (t : number) : number => {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
/**
* hex颜色转rgba
*/
export const hexToRgba = (hex : string, alpha : number) : string => {
// 去除 # 符号(如果有的话)
hex = hex.replace('#', '');
let hexArray = hex.split('');
// 检查颜色值长度,如果不符合预期则返回默认值或者抛出错误
if (hexArray.length != 3 && hexArray.length != 6) {
// 返回默认值或者抛出错误,这里使用默认值为黑色
return 'rgba(0,0,0,1)';
// 或者抛出错误
// throw new Error('Invalid hex color value');
}
let extendedHex : string[] = [];
if (hex.length == 3) {
for (let i = 0; i < hexArray.length; i++) {
extendedHex.push(hexArray[i]);
extendedHex.push(hexArray[i]);
}
hexArray = extendedHex;
}
hex = ''
for (let h = 0; h < hexArray.length; h++) {
hex += hexArray[h]
}
// // 拆分颜色值为 R、G、B
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
// // 返回 rgba 值
return `rgba(${r},${g},${b},${alpha})`;
}
export const easeInOutCubic = (t : number) : number => {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
}
......@@ -19,7 +19,7 @@
<!-- 修改加载图标大小 -->
<uni-loading :size="30"></uni-loading>
<!-- 修改加载图标类型 : 当前只支持 circle-->
<uni-loading type="circle"></uni-loading>
<uni-loading type="circle"></uni-loading>
```
......
## 1.0.9(2024-02-29)
去除代码过时警告
## 1.0.8(2023-12-21)
去除app-ios目录
## 1.0.7(2023-12-11)
......
export const ACTION_DOWNLOAD_FINISH = "ACTION_DOWNLOAD_FINISH"
export const ACTION_DOWNLOAD_FINISH = "ACTION_DOWNLOAD_FINISH"
export const ACTION_DOWNLOAD_PROGRESS = "ACTION_DOWNLOAD_PROGRESS"
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册