课程详情页面
This commit is contained in:
+3
-1
@@ -3,4 +3,6 @@ ENV = 'development'
|
||||
# 'development'
|
||||
|
||||
# base api
|
||||
VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786'
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786'
|
||||
# 苗扬
|
||||
VITE_APP_BASE_API_Url = 'http://25.64.16.133:9786'
|
||||
|
||||
+8
-6
@@ -7,8 +7,6 @@ import {
|
||||
|
||||
|
||||
export const uploadFile = (file, data) => {
|
||||
|
||||
|
||||
const url = '/plimg/fileUpload/stuMgrUploadImg';
|
||||
const base_url = get_base_url(url);
|
||||
const token = getToken();
|
||||
@@ -43,19 +41,23 @@ export const uploadFile = (file, data) => {
|
||||
|
||||
|
||||
// 对象存储预览 /traoss/tras3/show/{文件ID}
|
||||
export function previewFile(id,responseType = 'blob') {
|
||||
export function previewFile(id,responseType = 'arraybuffer') {
|
||||
const token = getToken();
|
||||
const header = {};
|
||||
const header = {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
};
|
||||
if (token)
|
||||
header['summary'] = token
|
||||
let baseUrl = get_base_url();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: `/traoss/tras3/show/${id}`,
|
||||
url: `${baseUrl}/traoss/tras3/show/${id}`,
|
||||
header,
|
||||
responseType,
|
||||
success(result) {
|
||||
resolve(result.data)
|
||||
let _blob = new Blob([result.data],{type:result.header['content-type'].split(';')[0]})
|
||||
resolve(_blob)
|
||||
},
|
||||
fail(error) {
|
||||
reject(new Error('Upload failed'));
|
||||
|
||||
+57
-16
@@ -1,27 +1,68 @@
|
||||
import request from '@/api/request'
|
||||
|
||||
const base_url = '/traapp'
|
||||
|
||||
// 获取课程分类树接口
|
||||
export const getCourseTypeListApi = (data) => {
|
||||
return request({
|
||||
url: '/app/traCrsCatalogInfo/courseQueryTraCrsCatalogInfoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
return request({
|
||||
url: base_url + '/app/traCrsCatalogInfo/courseQueryTraCrsCatalogInfoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
// 获取生产线分类树接口
|
||||
export const getPrdLineTypeListApi = (data) => {
|
||||
return request({
|
||||
url: '/app/traPrdLineInfo/courseQueryTraPrdLineInfoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
return request({
|
||||
url: base_url + '/app/traPrdLineInfo/courseQueryTraPrdLineInfoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
// 获取标签分类树 接口
|
||||
export const getTraTagListApi = (data) => {
|
||||
return request({
|
||||
url: '/app/traTagCatalogInfo/queryTraTagCatalogInfoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
return request({
|
||||
url: base_url + '/app/traTagCatalogInfo/queryTraTagCatalogInfoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
// 全部模块
|
||||
export const queryCrsInfoByCatalogApi = (data) => {
|
||||
return request({
|
||||
url: base_url + '/crsInfo/queryCrsInfoByCatalog',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
// 生产线模块-
|
||||
export const queryCrsInfoByPrdLineApi = (data) => {
|
||||
return request({
|
||||
url: base_url + '/crsInfo/queryCrsInfoByPrdLine',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
// 最新
|
||||
export const queryCrsInfoByLastnewApi = (data) => {
|
||||
return request({
|
||||
url: base_url + '/crsInfo/queryCrsInfoByLastnew',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
// 最热
|
||||
export const queryCrsInfoByPopularApi = (data) => {
|
||||
return request({
|
||||
url: base_url + '/crsInfo/queryCrsInfoByPopular',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
// 推荐
|
||||
export const queryCrsInfoByRecmdApi = (data) => {
|
||||
return request({
|
||||
url: base_url + '/crsInfo/queryCrsInfoByRecmd',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
+4
-4
@@ -6,7 +6,7 @@ const setUserInfo = data => uni.setStorageSync('userInfo', data)
|
||||
|
||||
// 账号登录接口
|
||||
export const useAccountLoginApp = (data) => request({
|
||||
url: '/access/userLogin',
|
||||
url: '/traapp/access/userLogin',
|
||||
method: 'post',
|
||||
data
|
||||
}).then(async({ rtnCode, body }) => {
|
||||
@@ -29,21 +29,21 @@ export const useAccountLoginApp = (data) => request({
|
||||
|
||||
// 获取个人信息
|
||||
export const queryCurrentUser = (data) => request({
|
||||
url: '/access/queryCurrentUser',
|
||||
url: '/traapp/access/queryCurrentUser',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
|
||||
//获取隐私协议
|
||||
export const getYsxy = (data) => request({
|
||||
url: '/dfAgtInfo/queryValidDfAgt',
|
||||
url: '/traapp/dfAgtInfo/queryValidDfAgt',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
|
||||
// 获取验证码(作废)
|
||||
export const getLoginAppCheckCode = (data) => request({
|
||||
url: '/access/checkCode',
|
||||
url: '/traapp/access/checkCode',
|
||||
method: 'get',
|
||||
data
|
||||
})
|
||||
+8
-6
@@ -8,10 +8,10 @@ const ENV = import.meta.env
|
||||
export const get_base_url = url => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// 开发环境
|
||||
return ENV.VITE_APP_BASE_API_Url + "/traapp"
|
||||
return ENV.VITE_APP_BASE_API_Url
|
||||
} else if (process.env.NODE_ENV === 'production') {
|
||||
// 生产环境
|
||||
return ENV.VITE_APP_BASE_API_Url + "/traapp"
|
||||
return ENV.VITE_APP_BASE_API_Url
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,17 +21,19 @@ export default function request({
|
||||
data,
|
||||
meta,
|
||||
isStream,
|
||||
suppressErrors
|
||||
suppressErrors,
|
||||
header={}
|
||||
}) {
|
||||
const base_url = get_base_url(url);
|
||||
|
||||
const header = {
|
||||
const headers_base = {
|
||||
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
...(header||{})
|
||||
}
|
||||
|
||||
let token = getToken()
|
||||
if (token) {
|
||||
header['summary'] = token // 让每个请求携带令牌
|
||||
headers_base['summary'] = token // 让每个请求携带令牌
|
||||
}
|
||||
let that = this
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -39,7 +41,7 @@ export default function request({
|
||||
url: `${base_url}${url}`,
|
||||
data: data,
|
||||
method: method,
|
||||
header: header,
|
||||
header: headers_base,
|
||||
success: (response) => {
|
||||
if (isStream) { // 流式传输,直接返回
|
||||
return resolve(response);
|
||||
|
||||
@@ -1,20 +1,128 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
<view class="course-item-box" @click="clickItem">
|
||||
<view class="img-box-view">
|
||||
<ImagePreview class="img-box" :imgId="itemInfo.imgId"></ImagePreview>
|
||||
<view class="item-grade">{{itemInfo.evalGrade}}</view>
|
||||
</view>
|
||||
<view class="cont-box">
|
||||
<view class="item-title">{{itemInfo.crsName}}</view>
|
||||
<uv-scroll-list class="item-tags" :indicator="false">
|
||||
<view class="item-tag-view">
|
||||
<view class="item-tag" v-for="item in itemInfo.tagCataList">{{item.tagName}}</view>
|
||||
</view>
|
||||
</uv-scroll-list>
|
||||
<view class="item-publish">发布:{{itemInfo.issuTm}}</view>
|
||||
<view class="item-num">已学:{{itemInfo.accmStdyCnt}}人次</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script >
|
||||
import ImagePreview from '@/components/image-preview/image-preview.vue'
|
||||
export default {
|
||||
name:"course-item",
|
||||
components:{
|
||||
ImagePreview
|
||||
},
|
||||
props:{
|
||||
itemInfo:{
|
||||
type:Object,
|
||||
default:()=>({
|
||||
crsName: '银行核心业务全流程实践哒哒哒哒',
|
||||
tagsList:[{tagName:'公斤业务'},{tagName:'初级'}],
|
||||
publicTime:"2025-01-03",
|
||||
learnedNum:'2222222'
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
methods:{
|
||||
clickItem(){
|
||||
this.$emit('clickItem', this.itemInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.course-item-box{
|
||||
padding: 15rpx;
|
||||
overflow: hidden;
|
||||
.img-box-view{
|
||||
width: 170rpx;
|
||||
height: 170rpx;
|
||||
float: left;
|
||||
position: relative;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
.img-box{
|
||||
width: 170rpx;
|
||||
height: 170rpx;
|
||||
}
|
||||
.item-grade{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 60rpx;
|
||||
height: 46rpx;
|
||||
background-color: #ff581c;
|
||||
top:20rpx;
|
||||
border-radius: 8rpx 0 0 8rpx;
|
||||
color:#fff;
|
||||
text-align: center;
|
||||
// padding-right: 10rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 46rpx;
|
||||
}
|
||||
}
|
||||
.cont-box{
|
||||
width: calc(100% - 170rpx);
|
||||
box-sizing: border-box;
|
||||
padding: 0 10rpx 0 20rpx;
|
||||
float: left;
|
||||
.item-title{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 44rpx;
|
||||
font-size: 29rpx;
|
||||
font-weight: 500;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.item-tags{
|
||||
padding-bottom: 0 !important;
|
||||
.item-tag-view{
|
||||
white-space: nowrap;
|
||||
height: 34rpx;
|
||||
.item-tag{
|
||||
height: 32rpx;
|
||||
line-height: 32rpx;
|
||||
font-size: 20rpx;
|
||||
background-color: #eee;
|
||||
color: rgb(51, 51, 51);
|
||||
padding: 0 20rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-right: 20rpx;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 200rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-publish,
|
||||
.item-num{
|
||||
height: 32rpx;
|
||||
line-height: 32rpx;
|
||||
font-size: 20rpx;
|
||||
color: rgb(102,102,102);
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,27 +1,29 @@
|
||||
<template>
|
||||
<image :src="imgUrl"></image>
|
||||
<image :src="imgUrlShow" fit="cover"></image>
|
||||
<!-- <image class="img" src="@/static/images/test/1.png"></image> -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import previewFile from'@/api/common.js'
|
||||
import {previewFile} from'@/api/common.js'
|
||||
export default {
|
||||
name:"image-preview",
|
||||
props:{
|
||||
modelValue:{
|
||||
imgId:{
|
||||
default:'',
|
||||
type:String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
imgUrl
|
||||
imgUrlShow:'',
|
||||
watching:false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
imgId: {
|
||||
handler(newval, oldval) {
|
||||
if (newval) {
|
||||
this.getPreviewUrlBlob(newval);
|
||||
if (newval && this.watching) {
|
||||
this.getPreviewUrlBlob(newval);
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
@@ -39,9 +41,9 @@
|
||||
},
|
||||
methods: {
|
||||
getPreviewUrlBlob(id) {
|
||||
// this.imgUrlShow = '@/static/images/index/message_b.png'
|
||||
previewFile(id).then((res) => {
|
||||
this.imgUrlShow = URL.createObjectURL(res);
|
||||
|
||||
// const reader = new FileReader();
|
||||
// reader.readAsDataURL(res)
|
||||
// reader.onloadend = () => {
|
||||
@@ -51,9 +53,10 @@
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.modelValue) {
|
||||
this.getPreviewUrlBlob(this.modelValue);
|
||||
if (this.imgId) {
|
||||
this.getPreviewUrlBlob(this.imgId);
|
||||
}
|
||||
this.watching = true
|
||||
},
|
||||
beforeDestroy() {
|
||||
URL.revokeObjectURL(this.imgUrlShow);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
"path": "pages/courseDetail/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "课程详情",
|
||||
@@ -19,6 +20,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
=======
|
||||
>>>>>>> f0015d5ea46c4904ce35c5ec4a03028d9ec6d5b4
|
||||
"path": "pages/study/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学习",
|
||||
@@ -90,6 +93,18 @@
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
},
|
||||
{
|
||||
"path": "pages/course/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "课程中心",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
>>>>>>> f0015d5ea46c4904ce35c5ec4a03028d9ec6d5b4
|
||||
}
|
||||
],
|
||||
"tabBar": {
|
||||
|
||||
+352
-31
@@ -7,15 +7,15 @@
|
||||
<uv-icon class="arrow-icon" name="arrow-left" @click="common.navigateBack()"/>
|
||||
课程中心
|
||||
</view>
|
||||
<view class="input-view">
|
||||
<uv-input shape="circle"
|
||||
placeholderStyle='color:#999999;font-size:28rpx'
|
||||
placeholder="请输入课程名"
|
||||
suffixIcon="search"
|
||||
:customStyle="customStyle"
|
||||
:suffixIconStyle="suffixIconStyle"
|
||||
:readonly="true">
|
||||
</uv-input>
|
||||
<view class="input-view" @click="toSearchPage">
|
||||
<uv-input shape="circle"
|
||||
placeholderStyle='color:#999999;font-size:28rpx'
|
||||
placeholder="请输入课程名"
|
||||
suffixIcon="search"
|
||||
:customStyle="customStyle"
|
||||
:suffixIconStyle="suffixIconStyle"
|
||||
:readonly="true">
|
||||
</uv-input>
|
||||
</view>
|
||||
<view class="tabs-view">
|
||||
<uv-tabs :list="tabList" @click="changeTab" :scrollable="false"
|
||||
@@ -24,17 +24,87 @@
|
||||
></uv-tabs>
|
||||
</view>
|
||||
<view class="list-view">
|
||||
<view class="filter-btn" @click="showFilterList = true">筛选
|
||||
<uv-icon class="filter-icon" name="list"/>
|
||||
</view>
|
||||
<view :class="['filter-list',showFilterList?'show':'']">
|
||||
<view class="filter-type" v-for="item in tagsTree.filter(t=>(t.children||[]).length>0)" :key="item.value">
|
||||
<view class="filter-type-title">{{item.label}}</view>
|
||||
<view class="filter-type-list">
|
||||
<view :class="['filter-type-item', activeTag===itemT.value?'is-active':'']" v-for="itemT in (item.children||[])" @click="chooseTag(itemT)">
|
||||
{{itemT.label}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-scroll-list class="tags-view" :indicator="false">
|
||||
<uv-tags text="全部" shape="circle" plain class="tags-item" size="mini"></uv-tags>
|
||||
<uv-tags text="全部" v-for="item in 15" shape="circle" plain type="info" class="tags-item" size="mini"></uv-tags>
|
||||
<uv-tags text="全部"
|
||||
shape="circle"
|
||||
plain
|
||||
class="tags-item"
|
||||
size="mini"
|
||||
:type="activeTag === ''?'primary':'info'"
|
||||
@click="chooseTag({value:''})"
|
||||
></uv-tags>
|
||||
<uv-tags :text="item.label"
|
||||
v-for="item in tagsList"
|
||||
:key="item.value"
|
||||
shape="circle"
|
||||
plain
|
||||
:type="activeTag === item.value?'primary':'info'"
|
||||
@click="chooseTag(item)"
|
||||
class="tags-item" size="mini"
|
||||
></uv-tags>
|
||||
</uv-scroll-list>
|
||||
<view class="course-list">
|
||||
<view class="left-type-list">
|
||||
<view v-for="item in 6" :class="['type-item', item == 3 ?'is-active':'']">
|
||||
课程分类
|
||||
<view class="left-type-list" v-if="'全部' === activeTab">
|
||||
<view
|
||||
v-for="item in courseTypeList"
|
||||
:key="item.value"
|
||||
:class="['type-item',activeCourseType == item.value ?'is-active':'']"
|
||||
@click="changeCourseType(item)"
|
||||
>
|
||||
{{item.label}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="left-type-list" v-if="'生产线'===activeTab">
|
||||
<view
|
||||
v-for="item in coursePrdlineList"
|
||||
:key="item.value"
|
||||
:class="['type-item', activePrdlineType == item.value ?'is-active':'']"
|
||||
@click="changePrdLine(item)"
|
||||
>
|
||||
{{item.label}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="right-course-list">
|
||||
<view
|
||||
class="type-list"
|
||||
v-for="item in courseListTreeShow"
|
||||
:key="item.value"
|
||||
>
|
||||
<view
|
||||
class="type-title"
|
||||
v-if="item.courseList.length > 0 && showTypeName"
|
||||
>
|
||||
<!-- v-if="itemT.courseList.length>0 && " -->
|
||||
<view class="left-color"></view>
|
||||
{{item.label}}
|
||||
</view>
|
||||
<CourseItem v-for="itemC in item.courseList" :key="itemC.crsNum" :itemInfo="itemC" @clickItem="toCourseDetail(itemC)"/>
|
||||
<view
|
||||
class="type-list"
|
||||
v-for="itemT in item.children"
|
||||
:key="itemT.value"
|
||||
>
|
||||
<view class="type-title" v-if="itemT.courseList.length>0">
|
||||
<view class="left-color"></view>
|
||||
{{itemT.label}}
|
||||
</view>
|
||||
<CourseItem v-for="itemTC in itemT.courseList" :key="itemTC.crsNum" :itemInfo="itemTC" @clickItem="toCourseDetail(itemTC)"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="right-course-list"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -42,13 +112,19 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import CourseItem from "@/components/course-item/course-item.vue"
|
||||
import common from '@/common/common'
|
||||
import {
|
||||
getPrdLineTypeListApi,
|
||||
getTraTagListApi,
|
||||
getCourseTypeListApi
|
||||
getCourseTypeListApi,
|
||||
queryCrsInfoByCatalogApi,
|
||||
queryCrsInfoByPrdLineApi,
|
||||
queryCrsInfoByLastnewApi,
|
||||
queryCrsInfoByPopularApi,
|
||||
queryCrsInfoByRecmdApi
|
||||
} from "@/api/course.js"
|
||||
import { onMounted } from 'vue'
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
const customStyle = {
|
||||
backgroundColor: "#ffffff",
|
||||
paddingLeft: "40rpx",
|
||||
@@ -63,24 +139,156 @@ import { onMounted } from 'vue'
|
||||
}
|
||||
const tabsCustomStyle ={
|
||||
backgroundColor: "#ffffff",
|
||||
marginTop: '23rpx',
|
||||
borderRadius: '23rpx',
|
||||
}
|
||||
const tabList = [
|
||||
{ name:'全部'},
|
||||
{ name:'热门'},
|
||||
{ name:'最新'},
|
||||
{ name:'推荐'},
|
||||
{ name:'生产线'},
|
||||
]
|
||||
const changeTab = (item) => {
|
||||
console.log(item)
|
||||
{ name:'全部'},
|
||||
{ name:'热门'},
|
||||
{ name:'最新'},
|
||||
{ name:'推荐'},
|
||||
{ name:'生产线'},
|
||||
]
|
||||
const activeTab = ref('全部')
|
||||
const activeCourseType = ref('')
|
||||
const activePrdlineType = ref('')
|
||||
const activeTag = ref('')
|
||||
const courseTypeList = ref([])
|
||||
const coursePrdlineList = ref([])
|
||||
const tagsTree = ref([])
|
||||
|
||||
const showFilterList = ref(false)
|
||||
|
||||
// 点击标签
|
||||
const chooseTag = (item)=>{
|
||||
activeTag.value = item.value
|
||||
showFilterList.value = false
|
||||
}
|
||||
// 点击生产线分类
|
||||
const changePrdLine = (item)=>{
|
||||
activePrdlineType.value = item.value
|
||||
}
|
||||
// 点击课程分类
|
||||
const changeCourseType = (item)=>{
|
||||
activeCourseType.value = item.value
|
||||
|
||||
setTimeout(()=>{
|
||||
console.log(courseListTreeShow.value)
|
||||
})
|
||||
|
||||
}
|
||||
const showTypeName = computed(()=>{
|
||||
return (activeTab.value === '全部' && activeCourseType.value === '') || (activeTab.value === '生产线' && activePrdlineType.value === '')
|
||||
})
|
||||
const tagsList = computed(()=>{
|
||||
let _arr = []
|
||||
tagsTree.value.forEach(t=>{
|
||||
let _tarr = t.children || []
|
||||
_arr = _arr.concat(_tarr)
|
||||
})
|
||||
return _arr.sort((a,b)=>{
|
||||
a.required == "Y" && b.required === 'N'
|
||||
})
|
||||
})
|
||||
const courseListBase = ref([])
|
||||
const courseList = computed(()=>{
|
||||
return activeTag.value
|
||||
?courseListBase.value.filter(t=>t.tagCataList.map(k=>k.tagId).indexOf(activeTag.value)>=0)
|
||||
:courseListBase.value
|
||||
})
|
||||
// 整理树形
|
||||
const courseListTree = computed(()=>{
|
||||
let _arr = activeTab.value === '全部'? courseTypeList.value
|
||||
: activeTab.value === '生产线'? coursePrdlineList.value: []
|
||||
let _idKey = activeTab.value === '全部'? 'tagId': 'prdLineId'
|
||||
|
||||
let _tree = _arr.map(t=>{
|
||||
let _children = t.children||[]
|
||||
return {
|
||||
label: t.label,
|
||||
required: t.required,
|
||||
value:t.value,
|
||||
courseList: courseList.value.filter(k=>k[_idKey] === t.value),
|
||||
children: _children.map(k=>{
|
||||
return {
|
||||
...k,
|
||||
courseList: courseList.value.filter(m=>m[_idKey] === k.value),
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return _tree
|
||||
})
|
||||
// 过滤树形
|
||||
const courseListTreeShow = computed(()=>{
|
||||
let _type = activeTab.value === '全部'? activeCourseType.value : activePrdlineType.value
|
||||
if(activeTab.value === '全部'|| activeTab.value === '生产线'){
|
||||
if(_type){
|
||||
return courseListTree.value.filter(t=> t.value === _type)
|
||||
}else{
|
||||
return courseListTree.value
|
||||
}
|
||||
}else{
|
||||
return [{
|
||||
children: [],
|
||||
courseList: courseList.value,
|
||||
label: "",
|
||||
value: "333"
|
||||
}]
|
||||
}
|
||||
})
|
||||
const changeTab = (item) => {
|
||||
if(!item) return
|
||||
activeTab.value = item.name
|
||||
activeTag.value = ''
|
||||
activeCourseType.value = ''
|
||||
activePrdlineType.value = ''
|
||||
switch (item.name){
|
||||
case '全部':
|
||||
queryCrsInfoByCatalogApi().then(res=>{
|
||||
courseListBase.value = res.body || []
|
||||
})
|
||||
break;
|
||||
case '热门':
|
||||
queryCrsInfoByPopularApi().then(res=>{
|
||||
courseListBase.value = res.body || []
|
||||
})
|
||||
break;
|
||||
case '最新':
|
||||
queryCrsInfoByLastnewApi().then(res=>{
|
||||
courseListBase.value = res.body || []
|
||||
})
|
||||
break;
|
||||
case '推荐':
|
||||
queryCrsInfoByRecmdApi().then(res=>{
|
||||
courseListBase.value = res.body || []
|
||||
})
|
||||
break;
|
||||
case '生产线':
|
||||
queryCrsInfoByPrdLineApi().then(res=>{
|
||||
courseListBase.value = res.body || []
|
||||
})
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 跳转搜索页
|
||||
const toSearchPage = () => {
|
||||
common.navigateTo('/pages/search/search')
|
||||
}
|
||||
// 跳转 课程详情
|
||||
const toCourseDetail = (item) => {
|
||||
common.navigateTo('/pages/courseDetail/index?crsNum=' + item.crsNum)
|
||||
}
|
||||
onMounted(()=>{
|
||||
// getPrdLineTypeListApi().then(res=>{
|
||||
// console.log(res)
|
||||
// })
|
||||
getCourseTypeListApi().then(res=>{
|
||||
courseTypeList.value = res.body||[]
|
||||
})
|
||||
getPrdLineTypeListApi().then(res=>{
|
||||
coursePrdlineList.value = res.body||[]
|
||||
})
|
||||
getTraTagListApi().then(res=>{
|
||||
tagsTree.value = res.body||[]
|
||||
})
|
||||
changeTab({name:'全部'})
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -102,6 +310,7 @@ import { onMounted } from 'vue'
|
||||
}
|
||||
.course-center-body{
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
left:0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
@@ -120,6 +329,7 @@ import { onMounted } from 'vue'
|
||||
font-weight: 500;
|
||||
color:#000;
|
||||
position: relative;
|
||||
// margin-bottom: 23rpx;
|
||||
.arrow-icon{
|
||||
position: absolute;
|
||||
left:36rpx;
|
||||
@@ -139,15 +349,99 @@ import { onMounted } from 'vue'
|
||||
}
|
||||
.list-view{
|
||||
flex:1;
|
||||
overflow: hidden;
|
||||
margin-bottom: 80rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 23rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
.filter-list{
|
||||
position: absolute;
|
||||
top: 84rpx;
|
||||
left:0;
|
||||
width: 100%;
|
||||
height: 508rpx;
|
||||
overflow-y: auto;
|
||||
z-index: 2;
|
||||
background-color: #f9f9f9;
|
||||
box-shadow: 0rpx 3.85rpx 38rpx rgba(0,0,0,.05);
|
||||
padding: 0rpx 25rpx;
|
||||
box-sizing: border-box;
|
||||
.filter-type{
|
||||
padding: 10rpx 0;
|
||||
box-sizing: border-box;
|
||||
.filter-type-title{
|
||||
font-size: 29rpx;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 15rpx;
|
||||
color: #000;
|
||||
}
|
||||
.filter-type-list{
|
||||
overflow: hidden;
|
||||
.filter-type-item{
|
||||
width: calc(25% - 18rpx);
|
||||
font-size: 29rpx;
|
||||
box-sizing: border-box;
|
||||
padding:0 20rpx;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
float: left;
|
||||
margin-right: 24rpx;
|
||||
height: 65rpx;
|
||||
line-height: 65rpx;
|
||||
background-color: #f1f3f8;
|
||||
border-radius: 6rpx;
|
||||
margin-bottom: 20rpx;
|
||||
&:nth-child(4n){
|
||||
margin-right: 0;
|
||||
}
|
||||
&.is-active{
|
||||
color: #06f;
|
||||
}
|
||||
}
|
||||
}
|
||||
&+.filter-type{
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.filter-list{
|
||||
display: none;
|
||||
&.show{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.filter-btn{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 83rpx;
|
||||
width: 120rpx;
|
||||
line-height: 83rpx;
|
||||
font-size: 26rpx;
|
||||
background: #fff;
|
||||
z-index: 2;
|
||||
text-align: center;
|
||||
box-shadow: -4rpx 0 6rpx rgba(0,0,0,.05);
|
||||
white-space: nowrap;
|
||||
padding-right: 30rpx;
|
||||
box-sizing: border-box;
|
||||
.filter-icon{
|
||||
// display: inline-block;
|
||||
font-size: 26rpx;
|
||||
position: absolute;
|
||||
right: 15rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
.tags-view{
|
||||
height: 84rpx;
|
||||
display: block;
|
||||
padding: 20rpx;
|
||||
padding: 20rpx 120rpx 20rpx 20rpx;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
border-bottom: 2rpx solid #eee;
|
||||
@@ -158,16 +452,21 @@ import { onMounted } from 'vue'
|
||||
padding: 0 20rpx;
|
||||
.uv-tags__text{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 200rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.course-list{
|
||||
display: flex;
|
||||
flex:1;
|
||||
flex:1;
|
||||
overflow: hidden;
|
||||
.left-type-list{
|
||||
width: 152rpx;
|
||||
border-right: 2rpx solid #eee;
|
||||
overflow-y: auto;
|
||||
.type-item{
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
@@ -185,6 +484,28 @@ import { onMounted } from 'vue'
|
||||
}
|
||||
.right-course-list{
|
||||
flex:1;
|
||||
overflow-y: auto;
|
||||
.type-list{
|
||||
.type-title{
|
||||
font-size: 33rpx;
|
||||
line-height: 43rpx;
|
||||
margin: 20rpx 15rpx 5rpx;
|
||||
height: 43rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: 600;
|
||||
.left-color{
|
||||
width: 8rpx;
|
||||
height: 33rpx;
|
||||
margin-top: 5rpx;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
background-color: #06f;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"pages": [
|
||||
|
||||
{
|
||||
"path": "pages/course/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "课程中心",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
## 1.0.8(2023-10-18)
|
||||
1. 修复在APP上不能正常显示的BUG
|
||||
## 1.0.7(2023-10-12)
|
||||
1. 修复部分情况,修改某属性自动关闭的BUG
|
||||
## 1.0.6(2023-07-24)
|
||||
1. 优化 nvue模式下增加cellChild参数,是否在list中cell节点下,nvue中cell下建议设置成true
|
||||
## 1.0.5(2023-07-02)
|
||||
修改VUE3模式下可能存在的BUG
|
||||
## 1.0.4(2023-07-02)
|
||||
uv-transition 动画组件,代码重构优化,性能更加友好,增加自定义动画功能。详情参考文档:https://www.uvui.cn/components/transition.html
|
||||
## 1.0.3(2023-06-12)
|
||||
1. 恢复this.$nextTick的使用,经过测试百度等平台无问题
|
||||
## 1.0.2(2023-05-23)
|
||||
1. 百度小程序等平台不支持this.$nextick,修改成延时
|
||||
## 1.0.1(2023-05-16)
|
||||
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
|
||||
2. 优化部分功能
|
||||
## 1.0.0(2023-05-10)
|
||||
1. 新增动画组件
|
||||
@@ -0,0 +1,131 @@
|
||||
// const defaultOption = {
|
||||
// duration: 300,
|
||||
// timingFunction: 'linear',
|
||||
// delay: 0,
|
||||
// transformOrigin: '50% 50% 0'
|
||||
// }
|
||||
// #ifdef APP-NVUE
|
||||
const nvueAnimation = uni.requireNativePlugin('animation')
|
||||
// #endif
|
||||
class MPAnimation {
|
||||
constructor(options, _this) {
|
||||
this.options = options
|
||||
// 在iOS10+QQ小程序平台下,传给原生的对象一定是个普通对象而不是Proxy对象,否则会报parameter should be Object instead of ProxyObject的错误
|
||||
this.animation = uni.createAnimation({
|
||||
...options
|
||||
})
|
||||
this.currentStepAnimates = {}
|
||||
this.next = 0
|
||||
this.$ = _this
|
||||
|
||||
}
|
||||
|
||||
_nvuePushAnimates(type, args) {
|
||||
let aniObj = this.currentStepAnimates[this.next]
|
||||
let styles = {}
|
||||
if (!aniObj) {
|
||||
styles = {
|
||||
styles: {},
|
||||
config: {}
|
||||
}
|
||||
} else {
|
||||
styles = aniObj
|
||||
}
|
||||
if (animateTypes1.includes(type)) {
|
||||
if (!styles.styles.transform) {
|
||||
styles.styles.transform = ''
|
||||
}
|
||||
let unit = ''
|
||||
if(type === 'rotate'){
|
||||
unit = 'deg'
|
||||
}
|
||||
styles.styles.transform += `${type}(${args+unit}) `
|
||||
} else {
|
||||
styles.styles[type] = `${args}`
|
||||
}
|
||||
this.currentStepAnimates[this.next] = styles
|
||||
}
|
||||
_animateRun(styles = {}, config = {}) {
|
||||
let ref = this.$.$refs['ani'].ref
|
||||
if (!ref) return
|
||||
return new Promise((resolve, reject) => {
|
||||
nvueAnimation.transition(ref, {
|
||||
styles,
|
||||
...config
|
||||
}, res => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
_nvueNextAnimate(animates, step = 0, fn) {
|
||||
let obj = animates[step]
|
||||
if (obj) {
|
||||
let {
|
||||
styles,
|
||||
config
|
||||
} = obj
|
||||
this._animateRun(styles, config).then(() => {
|
||||
step += 1
|
||||
this._nvueNextAnimate(animates, step, fn)
|
||||
})
|
||||
} else {
|
||||
this.currentStepAnimates = {}
|
||||
typeof fn === 'function' && fn()
|
||||
this.isEnd = true
|
||||
}
|
||||
}
|
||||
|
||||
step(config = {}) {
|
||||
// #ifndef APP-NVUE
|
||||
this.animation.step(config)
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
|
||||
this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
|
||||
this.next++
|
||||
// #endif
|
||||
return this
|
||||
}
|
||||
|
||||
run(fn) {
|
||||
// #ifndef APP-NVUE
|
||||
this.$.animationData = this.animation.export()
|
||||
this.$.timer = setTimeout(() => {
|
||||
typeof fn === 'function' && fn()
|
||||
}, this.$.durationTime)
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.isEnd = false
|
||||
let ref = this.$.$refs['ani'] && this.$.$refs['ani'].ref
|
||||
if(!ref) return
|
||||
this._nvueNextAnimate(this.currentStepAnimates, 0, fn)
|
||||
this.next = 0
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
|
||||
'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
|
||||
'translateZ'
|
||||
]
|
||||
const animateTypes2 = ['opacity', 'backgroundColor']
|
||||
const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom']
|
||||
animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
|
||||
MPAnimation.prototype[type] = function(...args) {
|
||||
// #ifndef APP-NVUE
|
||||
this.animation[type](...args)
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this._nvuePushAnimates(type, args)
|
||||
// #endif
|
||||
return this
|
||||
}
|
||||
})
|
||||
|
||||
export function createAnimation(option, _this) {
|
||||
if(!_this) return
|
||||
clearTimeout(_this.timer)
|
||||
return new MPAnimation(option, _this)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
export default {
|
||||
props: {
|
||||
// 是否展示组件
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 使用的动画模式
|
||||
mode: {
|
||||
type: [Array, String, null],
|
||||
default() {
|
||||
return 'fade'
|
||||
}
|
||||
},
|
||||
// 动画的执行时间,单位ms
|
||||
duration: {
|
||||
type: [String, Number],
|
||||
default: 300
|
||||
},
|
||||
// 使用的动画过渡函数
|
||||
timingFunction: {
|
||||
type: String,
|
||||
default: 'ease-out'
|
||||
},
|
||||
customClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
...uni.$uv?.props?.transition
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
<template>
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view
|
||||
v-if="isShow"
|
||||
ref="ani"
|
||||
:animation="animationData"
|
||||
:class="customClass"
|
||||
:style="transformStyles"
|
||||
@click="onClick">
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<view
|
||||
v-if="isShow"
|
||||
ref="ani"
|
||||
:animation="animationData"
|
||||
:class="customClass"
|
||||
:style="transformStyles"
|
||||
@click="onClick">
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<script>
|
||||
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
|
||||
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
|
||||
import { createAnimation } from './createAnimation'
|
||||
/**
|
||||
* transition 动画组件
|
||||
* @description
|
||||
* @tutorial
|
||||
* @property {Boolean} show 控制组件显示或关闭 (默认 false )
|
||||
* @property {Array | String } mode 内置过渡动画类型 (默认 'fade' )
|
||||
* @value fade 渐隐渐出过渡
|
||||
* @value slide-top 由上至下过渡
|
||||
* @value slide-bottom 由下至上过渡
|
||||
* @value slide-left 由左至右过渡
|
||||
* @value slide-right 由右至左过渡
|
||||
* @value zoom-in 由小到大过渡
|
||||
* @value zoom-out 由大到小过渡
|
||||
* @property {String | Number} duration 动画的执行时间,单位ms (默认 300 )
|
||||
* @property {String} timingFunction 使用的动画过渡函数 (默认 'ease-out' )
|
||||
* @property {Object} customStyle 自定义样式
|
||||
* @property {String} customClass 自定义类名
|
||||
* @event {Function} click 点击组件触发
|
||||
* @event {Function} change 过渡动画结束时触发
|
||||
* @example
|
||||
*/
|
||||
export default {
|
||||
name: 'uv-transition',
|
||||
mixins: [mpMixin,mixin],
|
||||
emits:['click','change'],
|
||||
props: {
|
||||
// 是否展示组件
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 使用的动画模式
|
||||
mode: {
|
||||
type: [Array, String, null],
|
||||
default() {
|
||||
return 'fade'
|
||||
}
|
||||
},
|
||||
// 动画的执行时间,单位ms
|
||||
duration: {
|
||||
type: [String, Number],
|
||||
default: 300
|
||||
},
|
||||
// 使用的动画过渡函数
|
||||
timingFunction: {
|
||||
type: String,
|
||||
default: 'ease-out'
|
||||
},
|
||||
customClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// nvue模式下 是否直接显示,在uv-list等cell下面使用就需要设置
|
||||
cellChild: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
isShow: false,
|
||||
transform: '',
|
||||
opacity: 1,
|
||||
animationData: {},
|
||||
durationTime: 300,
|
||||
config: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.open();
|
||||
} else {
|
||||
// 避免上来就执行 close,导致动画错乱
|
||||
if (this.isShow) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 初始化动画条件
|
||||
transformStyles() {
|
||||
const style = {
|
||||
transform: this.transform,
|
||||
opacity: this.opacity,
|
||||
...this.$uv.addStyle(this.customStyle),
|
||||
'transition-duration': `${this.duration / 1000}s`
|
||||
};
|
||||
return this.$uv.addStyle(style,'string');
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 动画默认配置
|
||||
this.config = {
|
||||
duration: this.duration,
|
||||
timingFunction: this.timingFunction,
|
||||
transformOrigin: '50% 50%',
|
||||
delay: 0
|
||||
};
|
||||
this.durationTime = this.duration;
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* ref 触发 初始化动画
|
||||
*/
|
||||
init(obj = {}) {
|
||||
if (obj.duration) {
|
||||
this.durationTime = obj.duration;
|
||||
}
|
||||
this.animation = createAnimation(Object.assign(this.config, obj),this);
|
||||
},
|
||||
/**
|
||||
* 点击组件触发回调
|
||||
*/
|
||||
onClick() {
|
||||
this.$emit('click', {
|
||||
detail: this.isShow
|
||||
})
|
||||
},
|
||||
/**
|
||||
* ref 触发 动画分组
|
||||
* @param {Object} obj
|
||||
*/
|
||||
step(obj, config = {}) {
|
||||
if (!this.animation) return;
|
||||
for (let i in obj) {
|
||||
try {
|
||||
if(typeof obj[i] === 'object'){
|
||||
this.animation[i](...obj[i]);
|
||||
}else{
|
||||
this.animation[i](obj[i]);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`方法 ${i} 不存在`);
|
||||
}
|
||||
}
|
||||
this.animation.step(config);
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* ref 触发 执行动画
|
||||
*/
|
||||
run(fn) {
|
||||
if (!this.animation) return;
|
||||
this.animation.run(fn);
|
||||
},
|
||||
// 开始过度动画
|
||||
open() {
|
||||
clearTimeout(this.timer);
|
||||
this.transform = '';
|
||||
this.isShow = true;
|
||||
let { opacity, transform } = this.styleInit(false);
|
||||
if (typeof opacity !== 'undefined') {
|
||||
this.opacity = opacity;
|
||||
}
|
||||
this.transform = transform;
|
||||
// 确保动态样式已经生效后,执行动画,如果不加 nextTick ,会导致 wx 动画执行异常
|
||||
this.$nextTick(() => {
|
||||
// TODO 定时器保证动画完全执行,目前有些问题,后面会取消定时器
|
||||
this.timer = setTimeout(() => {
|
||||
this.animation = createAnimation(this.config, this);
|
||||
this.tranfromInit(false).step();
|
||||
// #ifdef APP-NVUE
|
||||
if(this.cellChild) {
|
||||
this.opacity = 1;
|
||||
} else{
|
||||
this.animation.run();
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
this.animation.run();
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
// #ifdef H5
|
||||
this.opacity = 1;
|
||||
// #endif
|
||||
// #endif
|
||||
this.$emit('change', {
|
||||
detail: this.isShow
|
||||
})
|
||||
// #ifdef H5
|
||||
// #ifdef VUE3
|
||||
this.transform = '';
|
||||
// #endif
|
||||
// #endif
|
||||
}, 20);
|
||||
})
|
||||
},
|
||||
// 关闭过渡动画
|
||||
close(type) {
|
||||
if (!this.animation) return;
|
||||
this.tranfromInit(true)
|
||||
.step()
|
||||
.run(() => {
|
||||
this.isShow = false;
|
||||
this.animationData = null;
|
||||
this.animation = null;
|
||||
let { opacity, transform } = this.styleInit(false);
|
||||
this.opacity = opacity || 1;
|
||||
this.transform = transform;
|
||||
this.$emit('change', {
|
||||
detail: this.isShow
|
||||
});
|
||||
})
|
||||
},
|
||||
// 处理动画开始前的默认样式
|
||||
styleInit(type) {
|
||||
let styles = {
|
||||
transform: ''
|
||||
};
|
||||
let buildStyle = (type, mode) => {
|
||||
if (mode === 'fade') {
|
||||
styles.opacity = this.animationType(type)[mode];
|
||||
} else {
|
||||
styles.transform += this.animationType(type)[mode] + ' ';
|
||||
}
|
||||
}
|
||||
if (typeof this.mode === 'string') {
|
||||
buildStyle(type, this.mode);
|
||||
} else {
|
||||
this.mode.forEach(mode => {
|
||||
buildStyle(type, mode)
|
||||
})
|
||||
}
|
||||
return styles
|
||||
},
|
||||
// 处理内置组合动画
|
||||
tranfromInit(type) {
|
||||
let buildTranfrom = (type, mode) => {
|
||||
let aniNum = null;
|
||||
if (mode === 'fade') {
|
||||
aniNum = type ? 0 : 1;
|
||||
} else {
|
||||
aniNum = type ? '-100%' : '0';
|
||||
if (mode === 'zoom-in') {
|
||||
aniNum = type ? 0.8 : 1
|
||||
}
|
||||
if (mode === 'zoom-out') {
|
||||
aniNum = type ? 1.2 : 1
|
||||
}
|
||||
if (mode === 'slide-right') {
|
||||
aniNum = type ? '100%' : '0'
|
||||
}
|
||||
if (mode === 'slide-bottom') {
|
||||
aniNum = type ? '100%' : '0'
|
||||
}
|
||||
}
|
||||
this.animation[this.animationMode()[mode]](aniNum)
|
||||
}
|
||||
if (typeof this.mode === 'string') {
|
||||
buildTranfrom(type, this.mode)
|
||||
} else {
|
||||
this.mode.forEach(mode => {
|
||||
buildTranfrom(type, mode)
|
||||
})
|
||||
}
|
||||
return this.animation;
|
||||
},
|
||||
animationType(type) {
|
||||
return {
|
||||
fade: type ? 1 : 0,
|
||||
'slide-top': `translateY(${type ? '0' : '-100%'})`,
|
||||
'slide-right': `translateX(${type ? '0' : '100%'})`,
|
||||
'slide-bottom': `translateY(${type ? '0' : '100%'})`,
|
||||
'slide-left': `translateX(${type ? '0' : '-100%'})`,
|
||||
'zoom-in': `scaleX(${type ? 1 : 0.8}) scaleY(${type ? 1 : 0.8})`,
|
||||
'zoom-out': `scaleX(${type ? 1 : 1.2}) scaleY(${type ? 1 : 1.2})`
|
||||
}
|
||||
},
|
||||
// 内置动画类型与实际动画对应字典
|
||||
animationMode() {
|
||||
return {
|
||||
fade: 'opacity',
|
||||
'slide-top': 'translateY',
|
||||
'slide-right': 'translateX',
|
||||
'slide-bottom': 'translateY',
|
||||
'slide-left': 'translateX',
|
||||
'zoom-in': 'scale',
|
||||
'zoom-out': 'scale'
|
||||
}
|
||||
},
|
||||
// 驼峰转中横线
|
||||
toLine(name) {
|
||||
return name.replace(/([A-Z])/g, '-$1').toLowerCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"id": "uv-transition",
|
||||
"displayName": "uv-transition 动画 全面兼容vue3+2、app、h5、小程序等多端",
|
||||
"version": "1.0.8",
|
||||
"description": "transition 该组件用于组件的动画过渡效果。",
|
||||
"keywords": [
|
||||
"uv-transition",
|
||||
"uvui",
|
||||
"uv-ui",
|
||||
"transition",
|
||||
"动画"
|
||||
],
|
||||
"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"
|
||||
],
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
## Transition 动画
|
||||
|
||||
> **组件名:uv-transition**
|
||||
|
||||
该组件用于组件的动画过渡效果,支持自定义动画,开箱即用。
|
||||
|
||||
# <a href="https://www.uvui.cn/components/transition.html" target="_blank">查看文档</a>
|
||||
|
||||
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui)
|
||||
|
||||
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
|
||||
|
||||

|
||||
|
||||
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
|
||||
Reference in New Issue
Block a user