diff --git a/.env.development b/.env.development index 9db6bab1..94787982 100644 --- a/.env.development +++ b/.env.development @@ -12,9 +12,15 @@ ENV = 'development' VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001' app入口 +<<<<<<< HEAD # VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001' # VITE_APP_BASE_API_Url = 'http://25.16.122.65:7001' # VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786' +======= +# VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001' +# VITE_APP_BASE_API_Url = 'http://25.16.122.65:7001' +# VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786' +>>>>>>> cea58939be69e08335a0aaf3f8fef73c5fdb914a diff --git a/Android/HBuilder-Integrate-AS/simpleDemo/src/main/res/drawable/icon.png b/Android/HBuilder-Integrate-AS/simpleDemo/src/main/res/drawable/icon.png index 676789c7..44438b0f 100644 Binary files a/Android/HBuilder-Integrate-AS/simpleDemo/src/main/res/drawable/icon.png and b/Android/HBuilder-Integrate-AS/simpleDemo/src/main/res/drawable/icon.png differ diff --git a/Android/HBuilder-Integrate-AS/simpleDemo/src/main/res/drawable/push.png b/Android/HBuilder-Integrate-AS/simpleDemo/src/main/res/drawable/push.png index 676789c7..44438b0f 100644 Binary files a/Android/HBuilder-Integrate-AS/simpleDemo/src/main/res/drawable/push.png and b/Android/HBuilder-Integrate-AS/simpleDemo/src/main/res/drawable/push.png differ diff --git a/logo/logo.png b/logo/logo.png new file mode 100644 index 00000000..44438b0f Binary files /dev/null and b/logo/logo.png differ diff --git a/src/api/common.js b/src/api/common.js index a7e27a8f..f8bf7f6b 100644 --- a/src/api/common.js +++ b/src/api/common.js @@ -62,7 +62,54 @@ export function downloadFile(id) { }); }); } - +// 上传音频 翻译文本 +export const uploadVoiceFile = (file) => { + const url = '/trastudy/traStdyInfo/audioTranscriptions'; + const base_url = get_base_url(url); + const token = getToken(); + const header = { + "Content-Type": "multipart/form-data; charset=UTF-8", + }; + if (token) + header['summary'] = token + return new Promise((resolve, reject) => { + uni.uploadFile({ + url: `${base_url}${url}`, + header: header, + filePath: file, + name: 'voice', + success(result) { + resolve(result) + }, + fail(error) { + reject(new Error('Upload failed')); + } + }); + }); +}; +// 获取音频 通用 +export function downloadVoiceFile(url) { + const token = getToken(); + const header = { + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + }; + if (token) + header['summary'] = token + let baseUrl = get_base_url(); + let _params = new FormData() + return new Promise((resolve, reject) => { + uni.downloadFile({ + url: `${baseUrl}${url}`, + header, + success(result) { + resolve(result) + }, + fail(error) { + reject(new Error(error)); + } + }); + }); +} // 对象存储预览 /traoss/tras3/show/{文件ID} export function previewFile(id, responseType = 'arraybuffer') { const token = getToken(); diff --git a/src/api/study.js b/src/api/study.js index bb329ee5..119cbe23 100644 --- a/src/api/study.js +++ b/src/api/study.js @@ -2,11 +2,36 @@ import request from '@/api/request' const base_url = '/trastudy' -// 获取课程分类树接口 +// 获取课程学习信息接口 export const getCourseStudyInfoApi = (data) => { return request({ url: base_url + '/traStdyInfo/queryTraStdyProgressAndTeacher', method: 'post', data }); +}; + +// 获取课程学习 知识点 接口 +export const queryTraStdyBatchWaitParagraphInfoApi = (data) => { + return request({ + url: base_url + '/traStdyInfo/queryTraStdyBatchWaitParagraphInfo', + method: 'post', + data + }); +}; +// 学习段落完成 +export const studyParagraphOverApi = (data) => { + return request({ + url: base_url + '/traStdyInfo/studyParagraphOver', + method: 'post', + data + }); +}; +// 上传语音翻译i文本 /traStdyInfo/audioTranscriptions +export const audioTranscriptionsApi = (data) => { + return request({ + url: base_url + '/traStdyInfo/audioTranscriptions', + method: 'post', + data + }); }; \ No newline at end of file diff --git a/src/pages.json b/src/pages.json index d85cf603..3d78faa0 100644 --- a/src/pages.json +++ b/src/pages.json @@ -36,6 +36,15 @@ } } }, + { + "path": "pages/welcome/index", + "style": { + "navigationBarTitleText": "欢迎", + "app-plus": { + "titleNView": false + } + } + }, { "path": "pages/study/index", "style": { diff --git a/src/pages/course/components/chartFour.vue b/src/pages/course/components/chartFour.vue new file mode 100644 index 00000000..41bd8e4e --- /dev/null +++ b/src/pages/course/components/chartFour.vue @@ -0,0 +1,245 @@ + + + + + \ No newline at end of file diff --git a/src/pages/course/components/chartThree.vue b/src/pages/course/components/chartThree.vue new file mode 100644 index 00000000..426a16e4 --- /dev/null +++ b/src/pages/course/components/chartThree.vue @@ -0,0 +1,251 @@ + + + + + \ No newline at end of file diff --git a/src/pages/course/components/talkingItem.vue b/src/pages/course/components/talkingItem.vue index 0767cd92..2f52b8f5 100644 --- a/src/pages/course/components/talkingItem.vue +++ b/src/pages/course/components/talkingItem.vue @@ -2,39 +2,54 @@ - + - 梁安娜 - AI课程教练 + {{ dataInfo?.userInfo?.teacherName }} + {{dataInfo?.userInfo?.teacherDesc}} - + + + {{ dataInfo.pgrphContent }} + + + + + + + + - - - - 阿列克山大是快乐的你艾德卡省的mask安东拉森扣篮大赛了快递那里是啊克里斯蒂娜老师的阿萨是看, - - + --> - + - - + + - 继续学 - - - 继续 + + 继续 @@ -42,10 +57,11 @@ @@ -53,7 +69,7 @@ - 阿列克山大是快乐的你艾德卡省的mask安东拉森扣篮大赛了快递那里是啊克里斯蒂娜老师的阿萨是看, + {{ dataInfo.talkingContent }} @@ -67,18 +83,112 @@ + + + + + + + + {{ userInfo.userName }} + + + + + {{ dataInfo.talkingContent }} + + + diff --git a/src/pages/setting/index.vue b/src/pages/setting/index.vue index 336f9f69..8485fb0e 100644 --- a/src/pages/setting/index.vue +++ b/src/pages/setting/index.vue @@ -40,6 +40,7 @@ diff --git a/src/pagesOther.json b/src/pagesOther.json index bda555b2..a61cebed 100644 --- a/src/pagesOther.json +++ b/src/pagesOther.json @@ -1,41 +1,50 @@ { "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages - { - "path": "pages/index/index", - "style": { - "navigationBarTitleText": "首页", - "app-plus": { - "titleNView": false + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "首页", + "app-plus": { + "titleNView": false + } + } + }, + { + "path": "pages/courseDetail/index", + "style": { + "navigationBarTitleText": "课程详情", + "app-plus": { + "titleNView": false + } + } + }, + { + "path": "pages/courseDetail/submit", + "style": { + "navigationBarTitleText": "提交评价", + "app-plus": { + "titleNView": false + } + } + }, + { + "path": "pages/setting/index", + "style": { + "navigationBarTitleText": "设置", + "app-plus": { + "titleNView": false + } + } + }, + { + "path": "pages/welcome/index", + "style": { + "navigationBarTitleText": "欢迎", + "app-plus": { + "titleNView": false + } } } - }, - { - "path": "pages/courseDetail/index", - "style": { - "navigationBarTitleText": "课程详情", - "app-plus": { - "titleNView": false - } - } - }, - { - "path": "pages/courseDetail/submit", - "style": { - "navigationBarTitleText": "提交评价", - "app-plus": { - "titleNView": false - } - } - }, - { - "path": "pages/setting/index", - "style": { - "navigationBarTitleText": "设置", - "app-plus": { - "titleNView": false - } - } - } ], "tabBar": { "list": [{ diff --git a/src/static/images/course/edit.png b/src/static/images/course/edit.png new file mode 100644 index 00000000..9c008c2c Binary files /dev/null and b/src/static/images/course/edit.png differ diff --git a/src/static/images/welcome/01.png b/src/static/images/welcome/01.png new file mode 100644 index 00000000..6ac692ab Binary files /dev/null and b/src/static/images/welcome/01.png differ diff --git a/src/static/images/welcome/02.png b/src/static/images/welcome/02.png new file mode 100644 index 00000000..e1887551 Binary files /dev/null and b/src/static/images/welcome/02.png differ diff --git a/src/static/images/welcome/03.png b/src/static/images/welcome/03.png new file mode 100644 index 00000000..354fb941 Binary files /dev/null and b/src/static/images/welcome/03.png differ diff --git a/src/uni_modules/uv-swipe-action/changelog.md b/src/uni_modules/uv-swipe-action/changelog.md new file mode 100644 index 00000000..508543cd --- /dev/null +++ b/src/uni_modules/uv-swipe-action/changelog.md @@ -0,0 +1,11 @@ +## 1.0.4(2023-10-13) +1. 优化 +## 1.0.3(2023-10-13) +1. unmounted兼容vue3 +## 1.0.2(2023-05-27) +1. 不支持抖音小程序说明 +## 1.0.1(2023-05-16) +1. 优化组件依赖,修改后无需全局引入,组件导入即可使用 +2. 优化部分功能 +## 1.0.0(2023-05-10) +uv-swipe-action 滑动单元格 diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index - backup.wxs b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index - backup.wxs new file mode 100644 index 00000000..3d62784a --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index - backup.wxs @@ -0,0 +1,256 @@ +/** + * 此为wxs模块,只支持APP-VUE,微信和QQ小程序以及H5平台 + * wxs内部不支持es6语法,变量只能使用var定义,无法使用解构,箭头函数等特性 + */ + +// 开始触摸 +function touchstart(event, ownerInstance) { + // 触发事件的组件的ComponentDescriptor实例 + var instance = event.instance + // wxs内的局部变量快照,此快照是属于整个组件的,在touchstart和touchmove事件中都能获取到相同的结果 + var state = instance.getState() + if (state.disable) return + var touches = event.touches + // 如果进行的是多指触控,不允许进行操作 + if (touches && touches.length > 1) return + // 标识当前为滑动中状态 + state.moving = true + // 记录触摸开始点的坐标值 + state.startX = touches[0].pageX + state.startY = touches[0].pageY +} + +// 触摸滑动 +function touchmove(event, ownerInstance) { + // 触发事件的组件的ComponentDescriptor实例 + var instance = event.instance + // wxs内的局部变量快照 + var state = instance.getState() + if (state.disabled || !state.moving) return + + var touches = event.touches + var pageX = touches[0].pageX + var pageY = touches[0].pageY + var moveX = pageX - state.startX + var moveY = pageY - state.startY + var buttonsWidth = state.buttonsWidth + + // 移动的X轴距离大于Y轴距离,也即终点与起点位置连线,与X轴夹角小于45度时,禁止页面滚动 + if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > state.threshold) { + event.preventDefault() + event.stopPropagation() + } + // 如果移动的X轴距离小于Y轴距离,也即终点位置与起点位置连线,与Y轴夹角小于45度时,认为是页面上下滑动,而不是左右滑动单元格 + if (Math.abs(moveX) < Math.abs(moveY)) return + + // 限制右滑的距离,不允许内容部分往右偏移,右滑会导致X轴偏移值大于0,以此做判断 + // 此处不能直接return,因为滑动过程中会缺失某些关键点坐标,会导致错乱,最好的办法就是 + // 在超出后,设置为0 + if (state.status === 'open') { + // 在开启状态下,向左滑动,需忽略 + if (moveX < 0) moveX = 0 + // 想要收起菜单,最大能移动的距离为按钮的总宽度 + if (moveX > buttonsWidth) moveX = buttonsWidth + // 如果是已经打开了的状态,向左滑动时,移动收起菜单 + moveSwipeAction(-buttonsWidth + moveX, instance, ownerInstance) + } else { + // 关闭状态下,右滑动需忽略 + if (moveX > 0) moveX = 0 + // 滑动的距离不允许超过所有按钮的总宽度,此时只能是左滑,最终设置按钮的总宽度,同时为负数 + if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth + // 只要是在滑过程中,就不断移动菜单的内容部分,从而使隐藏的菜单显示出来 + moveSwipeAction(moveX, instance, ownerInstance) + } +} + +// 触摸结束 +function touchend(event, ownerInstance) { + // 触发事件的组件的ComponentDescriptor实例 + var instance = event.instance + // wxs内的局部变量快照 + var state = instance.getState() + if (!state.moving || state.disabled) return + var touches = event.changedTouches ? event.changedTouches[0] : {} + var pageX = touches.pageX + var pageY = touches.pageY + var moveX = pageX - state.startX + if (state.status === 'open') { + // 在展开的状态下,继续左滑,无需操作 + if (moveX < 0) return + // 在开启状态下,点击一下内容区域,moveX为0,也即没有进行移动,这时执行收起菜单逻辑 + if (moveX === 0) { + return closeSwipeAction(instance, ownerInstance) + } + // 在开启状态下,滑动距离小于阈值,则默认为不关闭,同时恢复原来的打开状态 + if (Math.abs(moveX) < state.threshold) { + openSwipeAction(instance, ownerInstance) + } else { + // 如果滑动距离大于阈值,则执行收起逻辑 + closeSwipeAction(instance, ownerInstance) + } + } else { + // 在关闭的状态下,右滑,无需操作 + if (moveX > 0) return + // 理由同上 + if (Math.abs(moveX) < state.threshold) { + closeSwipeAction(instance, ownerInstance) + } else { + openSwipeAction(instance, ownerInstance) + } + } +} + +// 获取过渡时间 +function getDuration(value) { + if (value.toString().indexOf('s') >= 0) return value + return value > 30 ? value + 'ms' : value + 's' +} + +// 滑动结束时判断滑动的方向 +function getMoveDirection(instance, ownerInstance) { + var state = instance.getState() +} + +// 移动滑动选择器内容区域,同时显示出其隐藏的菜单 +function moveSwipeAction(moveX, instance, ownerInstance) { + var state = instance.getState() + // 获取所有按钮的实例,需要通过它去设置按钮的位移 + var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button') + var len = buttons.length + var previewButtonsMoveX = 0 + + // 设置菜单内容部分的偏移 + instance.requestAnimationFrame(function() { + instance.setStyle({ + // 设置translateX的值 + 'transition': 'none', + transform: 'translateX(' + moveX + 'px)', + '-webkit-transform': 'translateX(' + moveX + 'px)' + }) + // 折叠按钮动画 + for (var i = len - 1; i >= 0; i--) { + // 通过比例,得出元素自身该移动的距离 + var translateX = state.buttons[i].width / state.buttonsWidth * moveX + // 最终移动的距离,是通过自身比例算出的距离,再加上在它之前所有按钮移动的距离之和 + var realTranslateX = translateX + previewButtonsMoveX + buttons[i].setStyle({ + // 在移动期间,不能使用过渡效果,否则会造成卡顿,本质原因是每次移动一点,就要花一定时间去过渡这个过程 + 'transition': 'none', + 'transform': 'translateX(' + realTranslateX + 'px)', + '-webkit-transform': 'translateX(' + realTranslateX + 'px)' + }) + // 记录本按钮之前的所有按钮的移动距离之和 + previewButtonsMoveX += translateX + } + }) +} + +// 一次性展开滑动菜单 +function openSwipeAction(instance, ownerInstance) { + var state = instance.getState() + // 获取所有按钮的实例,需要通过它去设置按钮的位移 + var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button') + var len = buttons.length + // 处理duration单位问题 + const duration = getDuration(state.duration) + // 展开过程中,是向左移动,所以X的偏移应该为负值 + var buttonsWidth = -state.buttonsWidth + var previewButtonsMoveX = 0 + instance.requestAnimationFrame(function() { + // 设置菜单主体内容 + instance.setStyle({ + 'transition': 'transform ' + duration, + 'transform': 'translateX(' + buttonsWidth + 'px)', + '-webkit-transform': 'translateX(' + buttonsWidth + 'px)', + }) + // 设置各个隐藏的按钮为展开的状态 + for (var i = len - 1; i >= 0; i--) { + // 通过比例,得出元素自身该移动的距离 + var translateX = state.buttons[i].width / state.buttonsWidth * buttonsWidth + // 最终移动的距离,是通过自身比例算出的距离,再加上在它之前所有按钮移动的距离之和 + var realTranslateX = translateX + previewButtonsMoveX + buttons[i].setStyle({ + // 在移动期间,需要加上动画效果 + 'transition': 'transform ' + duration, + 'transform': 'translateX(' + realTranslateX + 'px)', + '-webkit-transform': 'translateX(' + realTranslateX + 'px)' + }) + // 记录本按钮之前的所有按钮的移动距离之和 + previewButtonsMoveX += translateX + } + }) + setStatus('open', instance) +} + +// 标记菜单的当前状态,open-已经打开,close-已经关闭 +function setStatus(status, instance) { + var state = instance.getState() + state.status = status +} + +// 一次性收起滑动菜单 +function closeSwipeAction(instance, ownerInstance) { + var state = instance.getState() + // 获取所有按钮的实例,需要通过它去设置按钮的位移 + var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button') + var len = buttons.length + // 处理duration单位问题 + const duration = getDuration(state.duration) + instance.requestAnimationFrame(function() { + // 设置菜单主体内容 + instance.setStyle({ + 'transition': 'transform ' + duration, + 'transform': 'translateX(0px)', + '-webkit-transform': 'translateX(0px)' + }) + // 设置各个隐藏的按钮为收起的状态 + for (var i = len - 1; i >= 0; i--) { + buttons[i].setStyle({ + 'transition': 'transform ' + duration, + 'transform': 'translateX(0px)', + '-webkit-transform': 'translateX(0px)' + }) + } + }) + setStatus('close', instance) +} + +// show的状态发生变化 +function showChange(newValue, oldValue, ownerInstance, instance) { + var state = instance.getState() + if (state.disabled) return + // 打开或关闭单元格 + if (newValue) { + openSwipeAction(instance, ownerInstance) + } else { + closeSwipeAction(instance, ownerInstance) + } +} + +// 菜单尺寸发生变化 +function sizeChange(newValue, oldValue, ownerInstance, instance) { + // wxs内的局部变量快照 + var state = instance.getState() + state.disabled = newValue.disabled + state.duration = newValue.duration + state.show = newValue.show + state.threshold = newValue.threshold + state.buttons = newValue.buttons + + var len = state.buttons.length + if (len) { + var buttonsWidth = 0 + var buttons = newValue.buttons + for (var i = 0; i < len; i++) { + buttonsWidth += buttons[i].width + } + } + state.buttonsWidth = buttonsWidth +} + +module.exports = { + touchstart: touchstart, + touchmove: touchmove, + touchend: touchend, + sizeChange: sizeChange +} diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index.wxs b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index.wxs new file mode 100644 index 00000000..16add565 --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index.wxs @@ -0,0 +1,225 @@ +/** + * 此为wxs模块,只支持APP-VUE,微信和QQ小程序以及H5平台 + * wxs内部不支持es6语法,变量只能使用var定义,无法使用解构,箭头函数等特性 + */ + +// 开始触摸 +function touchstart(event, ownerInstance) { + // 触发事件的组件的ComponentDescriptor实例 + var instance = event.instance + // wxs内的局部变量快照,此快照是属于整个组件的,在touchstart和touchmove事件中都能获取到相同的结果 + var state = instance.getState() + if (state.disabled) return + var touches = event.touches + // 如果进行的是多指触控,不允许进行操作 + if (touches && touches.length > 1) return + // 标识当前为滑动中状态 + state.moving = true + // 记录触摸开始点的坐标值 + state.startX = touches[0].pageX + state.startY = touches[0].pageY + + ownerInstance.callMethod('closeOther') +} + +// 触摸滑动 +function touchmove(event, ownerInstance) { + // 触发事件的组件的ComponentDescriptor实例 + var instance = event.instance + // wxs内的局部变量快照 + var state = instance.getState() + if (state.disabled || !state.moving) return + var touches = event.touches + var pageX = touches[0].pageX + var pageY = touches[0].pageY + var moveX = pageX - state.startX + var moveY = pageY - state.startY + var buttonsWidth = state.buttonsWidth + + // 移动的X轴距离大于Y轴距离,也即终点与起点位置连线,与X轴夹角小于45度时,禁止页面滚动 + if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > state.threshold) { + event.preventDefault && event.preventDefault() + event.stopPropagation && event.stopPropagation() + } + // 如果移动的X轴距离小于Y轴距离,也即终点位置与起点位置连线,与Y轴夹角小于45度时,认为是页面上下滑动,而不是左右滑动单元格 + if (Math.abs(moveX) < Math.abs(moveY)) return + + // 限制右滑的距离,不允许内容部分往右偏移,右滑会导致X轴偏移值大于0,以此做判断 + // 此处不能直接return,因为滑动过程中会缺失某些关键点坐标,会导致错乱,最好的办法就是 + // 在超出后,设置为0 + if (state.status === 'open') { + // 在开启状态下,向左滑动,需忽略 + if (moveX < 0) moveX = 0 + // 想要收起菜单,最大能移动的距离为按钮的总宽度 + if (moveX > buttonsWidth) moveX = buttonsWidth + // 如果是已经打开了的状态,向左滑动时,移动收起菜单 + moveSwipeAction(-buttonsWidth + moveX, instance, ownerInstance) + } else { + // 关闭状态下,右滑动需忽略 + if (moveX > 0) moveX = 0 + // 滑动的距离不允许超过所有按钮的总宽度,此时只能是左滑,最终设置按钮的总宽度,同时为负数 + if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth + // 只要是在滑过程中,就不断移动单元格内容部分,从而使隐藏的菜单显示出来 + moveSwipeAction(moveX, instance, ownerInstance) + } +} + +// 触摸结束 +function touchend(event, ownerInstance) { + // 触发事件的组件的ComponentDescriptor实例 + var instance = event.instance + // wxs内的局部变量快照 + var state = instance.getState() + if (!state.moving || state.disabled) return + var touches = event.changedTouches ? event.changedTouches[0] : {} + var pageX = touches.pageX + var pageY = touches.pageY + var moveX = pageX - state.startX + if (state.status === 'open') { + // 在展开的状态下,继续左滑,无需操作 + if (moveX < 0) return + // 在开启状态下,点击一下内容区域,moveX为0,也即没有进行移动,这时执行收起菜单逻辑 + if (moveX === 0) { + return closeSwipeAction(instance, ownerInstance) + } + // 在开启状态下,滑动距离小于阈值,则默认为不关闭,同时恢复原来的打开状态 + if (Math.abs(moveX) < state.threshold) { + openSwipeAction(instance, ownerInstance) + } else { + // 如果滑动距离大于阈值,则执行收起逻辑 + closeSwipeAction(instance, ownerInstance) + } + } else { + // 在关闭的状态下,右滑,无需操作 + if (moveX > 0) return + // 理由同上 + if (Math.abs(moveX) < state.threshold) { + closeSwipeAction(instance, ownerInstance) + } else { + openSwipeAction(instance, ownerInstance) + } + } +} + +// 获取过渡时间 +function getDuration(value) { + if (value.toString().indexOf('s') >= 0) return value + return value > 30 ? value + 'ms' : value + 's' +} + +// 滑动结束时判断滑动的方向 +function getMoveDirection(instance, ownerInstance) { + var state = instance.getState() +} + +// 移动滑动选择器内容区域,同时显示出其隐藏的菜单 +function moveSwipeAction(moveX, instance, ownerInstance) { + var state = instance.getState() + // 获取所有按钮的实例,需要通过它去设置按钮的位移 + var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button') + + // 设置菜单内容部分的偏移 + instance.requestAnimationFrame(function() { + instance.setStyle({ + // 设置translateX的值 + 'transition': 'none', + transform: 'translateX(' + moveX + 'px)', + '-webkit-transform': 'translateX(' + moveX + 'px)' + }) + }) +} + +// 一次性展开滑动菜单 +function openSwipeAction(instance, ownerInstance) { + var state = instance.getState() + // 获取所有按钮的实例,需要通过它去设置按钮的位移 + var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button') + // 处理duration单位问题 + var duration = getDuration(state.duration) + // 展开过程中,是向左移动,所以X的偏移应该为负值 + var buttonsWidth = -state.buttonsWidth + instance.requestAnimationFrame(function() { + // 设置菜单主体内容 + instance.setStyle({ + 'transition': 'transform ' + duration, + 'transform': 'translateX(' + buttonsWidth + 'px)', + '-webkit-transform': 'translateX(' + buttonsWidth + 'px)', + }) + }) + setStatus('open', instance, ownerInstance) +} + +// 标记菜单的当前状态,open-已经打开,close-已经关闭 +function setStatus(status, instance, ownerInstance) { + var state = instance.getState() + state.status = status + ownerInstance.callMethod('setState', status) +} + +// 一次性收起滑动菜单 +function closeSwipeAction(instance, ownerInstance) { + var state = instance.getState() + // 获取所有按钮的实例,需要通过它去设置按钮的位移 + var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button') + var len = buttons.length + // 处理duration单位问题 + var duration = getDuration(state.duration) + instance.requestAnimationFrame(function() { + // 设置菜单主体内容 + instance.setStyle({ + 'transition': 'transform ' + duration, + 'transform': 'translateX(0px)', + '-webkit-transform': 'translateX(0px)' + }) + // 设置各个隐藏的按钮为收起的状态 + for (var i = len - 1; i >= 0; i--) { + buttons[i].setStyle({ + 'transition': 'transform ' + duration, + 'transform': 'translateX(0px)', + '-webkit-transform': 'translateX(0px)' + }) + } + }) + setStatus('close', instance, ownerInstance) +} + +// status的状态发生变化 +function statusChange(newValue, oldValue, ownerInstance, instance) { + var state = instance.getState() + if (state.disabled) return + // 打开或关闭单元格 + if (newValue === 'close' && state.status === 'open') { + closeSwipeAction(instance, ownerInstance) + } else if(newValue === 'open' && state.status === 'close') { + openSwipeAction(instance, ownerInstance) + } +} + +// 菜单尺寸发生变化 +function sizeChange(newValue, oldValue, ownerInstance, instance) { + // wxs内的局部变量快照 + var state = instance.getState() + state.disabled = newValue.disabled + state.duration = newValue.duration + state.show = newValue.show + state.threshold = newValue.threshold + state.buttons = newValue.buttons + + if (state.buttons) { + var len = state.buttons.length + var buttonsWidth = 0 + var buttons = newValue.buttons + for (var i = 0; i < len; i++) { + buttonsWidth += buttons[i].width + } + } + state.buttonsWidth = buttonsWidth +} + +module.exports = { + touchstart: touchstart, + touchmove: touchmove, + touchend: touchend, + sizeChange: sizeChange, + statusChange: statusChange +} diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue - backup.js b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue - backup.js new file mode 100644 index 00000000..da259e87 --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue - backup.js @@ -0,0 +1,264 @@ +// nvue操作dom的库,用于获取dom的尺寸信息 +const dom = uni.requireNativePlugin('dom') +// nvue中用于操作元素动画的库,类似于uni.animation,只不过uni.animation不能用于nvue +const animation = uni.requireNativePlugin('animation') +import { sleep } from '@/uni_modules/uv-ui-tools/libs/function/index.js' +export default { + data() { + return { + // 是否滑动中 + moving: false, + // 状态,open-打开状态,close-关闭状态 + status: 'close', + // 开始触摸点的X和Y轴坐标 + startX: 0, + startY: 0, + // 所有隐藏按钮的尺寸信息数组 + buttons: [], + // 所有按钮的总宽度 + buttonsWidth: 0, + // 记录上一次移动的位置值 + moveX: 0, + // 记录上一次滑动的位置,用于前后两次做对比,如果移动的距离小于某一阈值,则认为前后之间没有移动,为了解决可能存在的通信阻塞问题 + lastX: 0 + } + }, + computed: { + // 获取过渡时间 + getDuratin() { + let duration = String(this.duration) + // 如果ms为单位,返回ms的数值部分 + if (duration.indexOf('ms') >= 0) return parseInt(duration) + // 如果s为单位,为了得到ms的数值,需要乘以1000 + if (duration.indexOf('s') >= 0) return parseInt(duration) * 1000 + // 如果值传了数值,且小于30,认为是s单位 + duration = Number(duration) + return duration < 30 ? duration * 1000 : duration + } + }, + watch: { + show: { + immediate: true, + handler(n) { + + } + } + }, + mounted() { + sleep(20).then(() => { + this.queryRect() + }) + }, + methods: { + close() { + this.closeSwipeAction() + }, + // 触摸单元格 + touchstart(event) { + if (this.disabled) return + this.closeOther() + const { touches } = event + // 记录触摸开始点的坐标值 + this.startX = touches[0].pageX + this.startY = touches[0].pageY + }, + // // 触摸滑动 + touchmove(event) { + if (this.disabled) return + const { touches } = event + const { pageX } = touches[0] + const { pageY } = touches[0] + let moveX = pageX - this.startX + const moveY = pageY - this.startY + const { buttonsWidth } = this + const len = this.buttons.length + + // 判断前后两次的移动距离,如果小于一定值,则不进行移动处理 + if (Math.abs(pageX - this.lastX) < 0.3) return + this.lastX = pageX + + // 移动的X轴距离大于Y轴距离,也即终点与起点位置连线,与X轴夹角小于45度时,禁止页面滚动 + if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > this.threshold) { + event.stopPropagation() + } + // 如果移动的X轴距离小于Y轴距离,也即终点位置与起点位置连线,与Y轴夹角小于45度时,认为是页面上下滑动,而不是左右滑动单元格 + if (Math.abs(moveX) < Math.abs(moveY)) return + + // 限制右滑的距离,不允许内容部分往右偏移,右滑会导致X轴偏移值大于0,以此做判断 + // 此处不能直接return,因为滑动过程中会缺失某些关键点坐标,会导致错乱,最好的办法就是 + // 在超出后,设置为0 + if (this.status === 'open') { + // 在开启状态下,向左滑动,需忽略 + if (moveX < 0) moveX = 0 + // 想要收起菜单,最大能移动的距离为按钮的总宽度 + if (moveX > buttonsWidth) moveX = buttonsWidth + // 如果是已经打开了的状态,向左滑动时,移动收起菜单 + this.moveSwipeAction(-buttonsWidth + moveX) + } else { + // 关闭状态下,右滑动需忽略 + if (moveX > 0) moveX = 0 + // 滑动的距离不允许超过所有按钮的总宽度,此时只能是左滑,最终设置按钮的总宽度,同时为负数 + if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth + // 只要是在滑过程中,就不断移动菜单的内容部分,从而使隐藏的菜单显示出来 + this.moveSwipeAction(moveX) + } + }, + // 单元格结束触摸 + touchend(event) { + if (this.disabled) return + const touches = event.changedTouches ? event.changedTouches[0] : {} + const { pageX } = touches + const { pageY } = touches + const { buttonsWidth } = this + this.moveX = pageX - this.startX + if (this.status === 'open') { + // 在展开的状态下,继续左滑,无需操作 + if (this.moveX < 0) this.moveX = 0 + if (this.moveX > buttonsWidth) this.moveX = buttonsWidth + // 在开启状态下,点击一下内容区域,moveX为0,也即没有进行移动,这时执行收起菜单逻辑 + if (this.moveX === 0) { + return this.closeSwipeAction() + } + // 在开启状态下,滑动距离小于阈值,则默认为不关闭,同时恢复原来的打开状态 + if (Math.abs(this.moveX) < this.threshold) { + this.openSwipeAction() + } else { + // 如果滑动距离大于阈值,则执行收起逻辑 + this.closeSwipeAction() + } + } else { + // 在关闭的状态下,右滑,无需操作 + if (this.moveX >= 0) this.moveX = 0 + if (this.moveX <= -buttonsWidth) this.moveX = -buttonsWidth + // 理由同上 + if (Math.abs(this.moveX) < this.threshold) { + this.closeSwipeAction() + } else { + this.openSwipeAction() + } + } + }, + // 移动滑动选择器内容区域,同时显示出其隐藏的菜单 + moveSwipeAction(moveX) { + if (this.moving) return + this.moving = true + + let previewButtonsMoveX = 0 + const len = this.buttons.length + animation.transition(this.$refs['uv-swipe-action-item__content'].ref, { + styles: { + transform: `translateX(${moveX}px)` + }, + timingFunction: 'linear' + }, () => { + this.moving = false + }) + // 按钮的组的长度 + for (let i = len - 1; i >= 0; i--) { + const buttonRef = this.$refs[`uv-swipe-action-item__right__button-${i}`][0].ref + // 通过比例,得出元素自身该移动的距离 + const translateX = this.buttons[i].width / this.buttonsWidth * moveX + // 最终移动的距离,是通过自身比例算出的距离,再加上在它之前所有按钮移动的距离之和 + const realTranslateX = translateX + previewButtonsMoveX + animation.transition(buttonRef, { + styles: { + transform: `translateX(${realTranslateX}px)` + }, + duration: 0, + delay: 0, + timingFunction: 'linear' + }, () => {}) + // 记录本按钮之前的所有按钮的移动距离之和 + previewButtonsMoveX += translateX + } + }, + // 关闭菜单 + closeSwipeAction() { + if (this.status === 'close') return + this.moving = true + const { buttonsWidth } = this + animation.transition(this.$refs['uv-swipe-action-item__content'].ref, { + styles: { + transform: 'translateX(0px)' + }, + duration: this.getDuratin, + timingFunction: 'ease-in-out' + }, () => { + this.status = 'close' + this.moving = false + this.closeHandler() + }) + // 按钮的组的长度 + const len = this.buttons.length + for (let i = len - 1; i >= 0; i--) { + const buttonRef = this.$refs[`uv-swipe-action-item__right__button-${i}`][0].ref + // 如果不满足边界条件,返回 + if (this.buttons.length === 0 || !this.buttons[i] || !this.buttons[i].width) return + + animation.transition(buttonRef, { + styles: { + transform: 'translateX(0px)' + }, + duration: this.getDuratin, + timingFunction: 'ease-in-out' + }, () => {}) + } + }, + // 打开菜单 + openSwipeAction() { + if (this.status === 'open') return + this.moving = true + const buttonsWidth = -this.buttonsWidth + let previewButtonsMoveX = 0 + animation.transition(this.$refs['uv-swipe-action-item__content'].ref, { + styles: { + transform: `translateX(${buttonsWidth}px)` + }, + duration: this.getDuratin, + timingFunction: 'ease-in-out' + }, () => { + this.status = 'open' + this.moving = false + this.openHandler() + }) + // 按钮的组的长度 + const len = this.buttons.length + for (let i = len - 1; i >= 0; i--) { + const buttonRef = this.$refs[`uv-swipe-action-item__right__button-${i}`][0].ref + // 如果不满足边界条件,返回 + if (this.buttons.length === 0 || !this.buttons[i] || !this.buttons[i].width) return + // 通过比例,得出元素自身该移动的距离 + const translateX = this.buttons[i].width / this.buttonsWidth * buttonsWidth + // 最终移动的距离,是通过自身比例算出的距离,再加上在它之前所有按钮移动的距离之和 + const realTranslateX = translateX + previewButtonsMoveX + animation.transition(buttonRef, { + styles: { + transform: `translateX(${realTranslateX}px)` + }, + duration: this.getDuratin, + timingFunction: 'ease-in-out' + }, () => {}) + previewButtonsMoveX += translateX + } + }, + // 查询按钮节点信息 + queryRect() { + // 历遍所有按钮数组,通过getRectByDom返回一个promise + const promiseAll = this.rightOptions.map((item, index) => this.getRectByDom(this.$refs[`uv-swipe-action-item__right__button-${index}`][0])) + // 通过promise.all方法,让所有按钮的查询结果返回一个数组的形式 + Promise.all(promiseAll).then((sizes) => { + this.buttons = sizes + // 计算所有按钮总宽度 + this.buttonsWidth = sizes.reduce((sum, cur) => sum + cur.width, 0) + }) + }, + // 通过nvue的dom模块,查询节点信息 + getRectByDom(ref) { + return new Promise((resolve) => { + dom.getComponentRect(ref, (res) => { + resolve(res.size) + }) + }) + } + } +} diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue.js b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue.js new file mode 100644 index 00000000..6eaf4913 --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue.js @@ -0,0 +1,182 @@ +// nvue操作dom的库,用于获取dom的尺寸信息 +const dom = uni.requireNativePlugin('dom'); +const bindingX = uni.requireNativePlugin('bindingx'); +const animation = uni.requireNativePlugin('animation'); +import { getDuration, getPx } from '@/uni_modules/uv-ui-tools/libs/function/index.js' +export default { + data() { + return { + // 所有按钮的总宽度 + buttonsWidth: 0, + // 是否正在移动中 + moving: false + } + }, + computed: { + // 获取过渡时间 + getDuratin() { + let duration = String(this.duration) + // 如果ms为单位,返回ms的数值部分 + if (duration.indexOf('ms') >= 0) return parseInt(duration) + // 如果s为单位,为了得到ms的数值,需要乘以1000 + if (duration.indexOf('s') >= 0) return parseInt(duration) * 1000 + // 如果值传了数值,且小于30,认为是s单位 + duration = Number(duration) + return duration < 30 ? duration * 1000 : duration + } + }, + watch: { + show(n) { + if(n) { + this.moveCellByAnimation('open') + } else { + this.moveCellByAnimation('close') + } + } + }, + mounted() { + setTimeout(()=>{ + this.initialize() + },20) + }, + methods: { + initialize() { + this.queryRect() + }, + // 关闭单元格,用于打开一个,自动关闭其他单元格的场景 + closeHandler() { + if(this.status === 'open') { + // 如果在打开状态下,进行点击的话,直接关闭单元格 + return this.moveCellByAnimation('close') && this.unbindBindingX() + } + }, + // 点击单元格 + clickHandler() { + // 如果在移动中被点击,进行忽略 + if(this.moving) return + // 尝试关闭其他打开的单元格 + this.parent && this.parent.closeOther(this) + if(this.status === 'open') { + // 如果在打开状态下,进行点击的话,直接关闭单元格 + return this.moveCellByAnimation('close') && this.unbindBindingX() + } + }, + // 滑动单元格 + onTouchstart(e) { + // 如果当前正在移动中,或者disabled状态,则返回 + if(this.moving || this.disabled) { + return this.unbindBindingX() + } + if(this.status === 'open') { + // 如果在打开状态下,进行点击的话,直接关闭单元格 + return this.moveCellByAnimation('close') && this.unbindBindingX() + } + // 特殊情况下,e可能不为一个对象 + e?.stopPropagation && e.stopPropagation() + e?.preventDefault && e.preventDefault() + this.moving = true + // 获取元素ref + const content = this.getContentRef() + let expression = `min(max(${-this.buttonsWidth}, x), 0)` + // 尝试关闭其他打开的单元格 + this.parent && this.parent.closeOther(this) + // 阿里为了KPI而开源的BindingX + this.panEvent = bindingX.bind({ + anchor: content, + eventType: 'pan', + props: [{ + element: content, + // 绑定width属性,设置其宽度值 + property: 'transform.translateX', + expression + }] + }, (res) => { + this.moving = false + if (res.state === 'end' || res.state === 'exit') { + const deltaX = res.deltaX + if(deltaX <= -this.buttonsWidth || deltaX >= 0) { + // 如果触摸滑动的过程中,大于单元格的总宽度,或者大于0,意味着已经动过滑动达到了打开或者关闭的状态 + // 这里直接进行状态的标记 + this.$nextTick(() => { + this.status = deltaX <= -this.buttonsWidth ? 'open' : 'close' + }) + } else if(Math.abs(deltaX) > getPx(this.threshold)) { + // 在移动大于阈值、并且小于总按钮宽度时,进行自动打开或者关闭 + // 移动距离大于0时,意味着需要关闭状态 + if(Math.abs(deltaX) < this.buttonsWidth) { + this.moveCellByAnimation(deltaX > 0 ? 'close' : 'open') + } + } else { + // 在小于阈值时,进行关闭操作(如果在打开状态下,将不会执行bindingX) + this.moveCellByAnimation('close') + } + } + }) + }, + // 释放bindingX + unbindBindingX() { + // 释放上一次的资源 + if (this?.panEvent?.token != 0) { + bindingX.unbind({ + token: this.panEvent?.token, + // pan为手势事件 + eventType: 'pan' + }) + } + }, + // 查询按钮节点信息 + queryRect() { + // 历遍所有按钮数组,通过getRectByDom返回一个promise + const promiseAll = this.options.map(async(item, index) => { + return await this.getRectByDom(this.$refs[`uv-swipe-action-item__right__button-${index}`][0]) + }) + // 通过promise.all方法,让所有按钮的查询结果返回一个数组的形式 + Promise.all(promiseAll).then(sizes => { + this.buttons = sizes + // 计算所有按钮总宽度 + this.buttonsWidth = sizes.reduce((sum, cur) => sum + cur.width, 0) + }) + }, + // 通过nvue的dom模块,查询节点信息 + getRectByDom(ref) { + return new Promise(resolve => { + dom.getComponentRect(ref, res => { + resolve(res.size) + }) + }) + }, + // 移动单元格到左边或者右边尽头 + moveCellByAnimation(status = 'open') { + if(this.moving) return + // 标识当前状态 + this.moveing = true + const content = this.getContentRef() + const x = status === 'open' ? -this.buttonsWidth : 0 + animation.transition(content, { + styles: { + transform: `translateX(${x}px)`, + }, + duration: getDuration(this.duration, false), + timingFunction: 'ease-in-out' + }, () => { + this.moving = false + this.status = status + this.unbindBindingX() + }) + }, + // 获取元素ref + getContentRef() { + return this.$refs['uv-swipe-action-item__content'].ref + } + }, + // #ifdef VUE2 + beforeDestroy() { + this.unbindBindingX() + }, + // #endif + // #ifdef VUE3 + unmounted() { + this.unbindBindingX() + } + // #endif +} diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/props.js b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/props.js new file mode 100644 index 00000000..5b321e23 --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/props.js @@ -0,0 +1,40 @@ +export default { + props: { + // 控制打开或者关闭 + show: { + type: Boolean, + default: false + }, + // 标识符,如果是v-for,可用index索引值 + name: { + type: [String, Number], + default: '' + }, + // 是否禁用 + disabled: { + type: Boolean, + default: false + }, + // 是否自动关闭其他swipe按钮组 + autoClose: { + type: Boolean, + default: true + }, + // 滑动距离阈值,只有大于此值,才被认为是要打开菜单 + threshold: { + type: Number, + default: 20 + }, + // 右侧按钮内容 + options: { + type: Array, + default: () => [] + }, + // 动画过渡时间,单位ms + duration: { + type: [String, Number], + default: 300 + }, + ...uni.$uv?.props?.swipeActionItem + } +} \ No newline at end of file diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/uv-swipe-action-item.vue b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/uv-swipe-action-item.vue new file mode 100644 index 00000000..8fd503a4 --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/uv-swipe-action-item.vue @@ -0,0 +1,200 @@ + + + + + + + diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/wxs.js b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/wxs.js new file mode 100644 index 00000000..ee49c100 --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action-item/wxs.js @@ -0,0 +1,15 @@ +export default { + methods: { + // 关闭时执行 + closeHandler() { + this.status = 'close' + }, + setState(status) { + this.status = status + }, + closeOther() { + // 尝试关闭其他打开的单元格 + this.parent && this.parent.closeOther(this) + } + } +} diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action/props.js b/src/uni_modules/uv-swipe-action/components/uv-swipe-action/props.js new file mode 100644 index 00000000..7d06765f --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action/props.js @@ -0,0 +1,10 @@ +export default { + props: { + // 是否自动关闭其他swipe按钮组 + autoClose: { + type: Boolean, + default: true + }, + ...uni.$uv?.props?.swipeAction + } +} \ No newline at end of file diff --git a/src/uni_modules/uv-swipe-action/components/uv-swipe-action/uv-swipe-action.vue b/src/uni_modules/uv-swipe-action/components/uv-swipe-action/uv-swipe-action.vue new file mode 100644 index 00000000..ed3e9f9c --- /dev/null +++ b/src/uni_modules/uv-swipe-action/components/uv-swipe-action/uv-swipe-action.vue @@ -0,0 +1,65 @@ + + + diff --git a/src/uni_modules/uv-swipe-action/package.json b/src/uni_modules/uv-swipe-action/package.json new file mode 100644 index 00000000..9eef69be --- /dev/null +++ b/src/uni_modules/uv-swipe-action/package.json @@ -0,0 +1,88 @@ +{ + "id": "uv-swipe-action", + "displayName": "uv-swipe-action 滑动单元格 全面兼容小程序、nvue、vue2、vue3等多端", + "version": "1.0.4", + "description": "滑动单元格组件一般用于左滑唤出操作菜单的场景,用的最多的是左滑删除操作。", + "keywords": [ + "uv-swipe-action", + "uvui", + "uv-ui", + "swipe-action", + "滑动单元格" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [ + "uv-ui-tools", + "uv-icon" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/uv-swipe-action/readme.md b/src/uni_modules/uv-swipe-action/readme.md new file mode 100644 index 00000000..31806966 --- /dev/null +++ b/src/uni_modules/uv-swipe-action/readme.md @@ -0,0 +1,11 @@ +## SwipeAction 滑动单元格 + +> **组件名:uv-swipe-action** + +该组件一般用于左滑唤出操作菜单的场景,用的最多的是左滑删除操作。 + +### 查看文档 + +### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui) + +#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:uv-ui官方QQ群 diff --git a/src/uni_modules/uv-swiper/changelog.md b/src/uni_modules/uv-swiper/changelog.md new file mode 100644 index 00000000..30f26c63 --- /dev/null +++ b/src/uni_modules/uv-swiper/changelog.md @@ -0,0 +1,16 @@ +## 1.0.6(2023-12-20) +1. 优化 +## 1.0.5(2023-08-24) +1. 修复标题文字过多未隐藏掉的BUG +## 1.0.4(2023-07-24) +1. 增加 滑动方向是否为纵向 属性vertical +## 1.0.3(2023-06-27) +1. 增加titleStyle属性,方便修改标题样式 +2. 标题上去掉是否是图片的判断,避免无后缀的图片不显示 +## 1.0.2(2023-06-01) +1. 修复点击触发两次事件的BUG +## 1.0.1(2023-05-16) +1. 优化组件依赖,修改后无需全局引入,组件导入即可使用 +2. 优化部分功能 +## 1.0.0(2023-05-10) +uv-swiper 轮播图,走马灯 diff --git a/src/uni_modules/uv-swiper/components/uv-swiper-indicator/props.js b/src/uni_modules/uv-swiper/components/uv-swiper-indicator/props.js new file mode 100644 index 00000000..8f305a0b --- /dev/null +++ b/src/uni_modules/uv-swiper/components/uv-swiper-indicator/props.js @@ -0,0 +1,30 @@ +export default { + props: { + // 轮播的长度 + length: { + type: [String, Number], + default: 0 + }, + // 当前处于活动状态的轮播的索引 + current: { + type: [String, Number], + default: 0 + }, + // 指示器非激活颜色 + indicatorActiveColor: { + type: String, + default: '' + }, + // 指示器的激活颜色 + indicatorInactiveColor: { + type: String, + default: '' + }, + // 指示器模式,line-线型,dot-点型 + indicatorMode: { + type: String, + default: '' + }, + ...uni.$uv?.props?.swiperIndicator + } +} \ No newline at end of file diff --git a/src/uni_modules/uv-swiper/components/uv-swiper-indicator/uv-swiper-indicator.vue b/src/uni_modules/uv-swiper/components/uv-swiper-indicator/uv-swiper-indicator.vue new file mode 100644 index 00000000..b326f437 --- /dev/null +++ b/src/uni_modules/uv-swiper/components/uv-swiper-indicator/uv-swiper-indicator.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/src/uni_modules/uv-swiper/components/uv-swiper/props.js b/src/uni_modules/uv-swiper/components/uv-swiper/props.js new file mode 100644 index 00000000..66e47876 --- /dev/null +++ b/src/uni_modules/uv-swiper/components/uv-swiper/props.js @@ -0,0 +1,136 @@ +export default { + props: { + // 列表数组,元素可为字符串,如为对象可通过keyName指定目标属性名 + list: { + type: Array, + default: () => [] + }, + // 是否显示面板指示器 + indicator: { + type: Boolean, + default: false + }, + // 指示器非激活颜色 + indicatorActiveColor: { + type: String, + default: '#fff' + }, + // 指示器的激活颜色 + indicatorInactiveColor: { + type: String, + default: 'rgba(255, 255, 255, 0.35)' + }, + // 指示器样式,可通过bottom,left,right进行定位 + indicatorStyle: { + type: [String, Object], + default: '' + }, + // 指示器模式,line-线型,dot-点型 + indicatorMode: { + type: String, + default: 'line' + }, + // 是否自动切换 + autoplay: { + type: Boolean, + default: true + }, + // 当前所在滑块的 index + current: { + type: [String, Number], + default: 0 + }, + // 当前所在滑块的 item-id ,不能与 current 被同时指定 + currentItemId: { + type: String, + default: '' + }, + // 滑块自动切换时间间隔 + interval: { + type: [String, Number], + default: 3000 + }, + // 滑块切换过程所需时间 + duration: { + type: [String, Number], + default: 300 + }, + // 播放到末尾后是否重新回到开头 + circular: { + type: Boolean, + default: false + }, + // 滑动方向是否为纵向 + vertical: { + type: Boolean, + default: false + }, + // 前边距,可用于露出前一项的一小部分,nvue和支付宝不支持 + previousMargin: { + type: [String, Number], + default: 0 + }, + // 后边距,可用于露出后一项的一小部分,nvue和支付宝不支持 + nextMargin: { + type: [String, Number], + default: 0 + }, + // 当开启时,会根据滑动速度,连续滑动多屏,支付宝不支持 + acceleration: { + type: Boolean, + default: false + }, + // 同时显示的滑块数量,nvue、支付宝小程序不支持 + displayMultipleItems: { + type: Number, + default: 1 + }, + // 指定swiper切换缓动动画类型,有效值:default、linear、easeInCubic、easeOutCubic、easeInOutCubic + // 只对微信小程序有效 + easingFunction: { + type: String, + default: 'default' + }, + // list数组中指定对象的目标属性名 + keyName: { + type: String, + default: 'url' + }, + // 图片的裁剪模式 + imgMode: { + type: String, + default: 'aspectFill' + }, + // 组件高度 + height: { + type: [String, Number], + default: 130 + }, + // 背景颜色 + bgColor: { + type: String, + default: '#f3f4f6' + }, + // 组件圆角,数值或带单位的字符串 + radius: { + type: [String, Number], + default: 4 + }, + // 是否加载中 + loading: { + type: Boolean, + default: false + }, + // 是否显示标题,要求数组对象中有title属性 + showTitle: { + type: Boolean, + default: false + }, + // 显示的标题样式 + titleStyle: { + type: [Object, String], + default: '' + }, + ...uni.$uv?.props?.swiper + } +} \ No newline at end of file diff --git a/src/uni_modules/uv-swiper/components/uv-swiper/uv-swiper.vue b/src/uni_modules/uv-swiper/components/uv-swiper/uv-swiper.vue new file mode 100644 index 00000000..a5b9dfcc --- /dev/null +++ b/src/uni_modules/uv-swiper/components/uv-swiper/uv-swiper.vue @@ -0,0 +1,257 @@ + + + + + diff --git a/src/uni_modules/uv-swiper/package.json b/src/uni_modules/uv-swiper/package.json new file mode 100644 index 00000000..f561f105 --- /dev/null +++ b/src/uni_modules/uv-swiper/package.json @@ -0,0 +1,88 @@ +{ + "id": "uv-swiper", + "displayName": "uv-swiper 轮播图 全面兼容vue3+2、app、h5、小程序等多端", + "version": "1.0.6", + "description": "该组件为轮播、跑马灯,支持卡片式。一般用于导航轮播,广告展示等场景,开箱即用", + "keywords": [ + "swiper", + "uvui", + "uv-ui", + "轮播图", + "走马灯" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [ + "uv-ui-tools", + "uv-loading-icon" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/uv-swiper/readme.md b/src/uni_modules/uv-swiper/readme.md new file mode 100644 index 00000000..cae255fe --- /dev/null +++ b/src/uni_modules/uv-swiper/readme.md @@ -0,0 +1,19 @@ +## Swiper 轮播图 + +> **组件名:uv-swiper** + +该组件为轮播、跑马灯,支持卡片式。一般用于导航轮播,广告展示等场景,开箱即用。 + +# 查看文档 + +## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) (请不要 下载插件ZIP) + +### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui) + + + +![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png) + + + +#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:官方QQ群 \ No newline at end of file