tianyi 3 weeks ago
parent
commit
cc61f1c2f5
  1. 9
      uni_modules/uni-transition/changelog.md
  2. 520
      uni_modules/uni-transition/components/uni-transition/uni-transition.vue
  3. 102
      uni_modules/uni-transition/package.json

9
uni_modules/uni-transition/changelog.md

@ -1,3 +1,12 @@
## 1.3.6(2025-07-18)
- 修复 nvue 页面,样式错误问题
## 1.3.5(2025-06-11)
- 修复 第一次执行不显示动画的问题
## 1.3.4(2025-04-16)
- 修复 页面数据更新到底动画复原的问题
- 修复 示例页面打开报错的问题
## 1.3.3(2024-04-23)
- 修复 当元素会受变量影响自动隐藏的bug
## 1.3.2(2023-05-04) ## 1.3.2(2023-05-04)
- 修复 NVUE 平台报错的问题 - 修复 NVUE 平台报错的问题
## 1.3.1(2021-11-23) ## 1.3.1(2021-11-23)

520
uni_modules/uni-transition/components/uni-transition/uni-transition.vue

@ -1,286 +1,292 @@
<template> <template>
<!-- #ifndef APP-NVUE --> <!-- #ifndef APP-NVUE -->
<view v-show="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view> <view v-show="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick">
<!-- #endif --> <slot></slot>
<!-- #ifdef APP-NVUE --> </view>
<view v-if="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view> <!-- #endif -->
<!-- #endif --> <!-- #ifdef APP-NVUE -->
<view v-if="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick">
<slot></slot>
</view>
<!-- #endif -->
</template> </template>
<script> <script>
import { createAnimation } from './createAnimation' import { createAnimation } from './createAnimation'
/** /**
* Transition 过渡动画 * Transition 过渡动画
* @description 简单过渡动画组件 * @description 简单过渡动画组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=985 * @tutorial https://ext.dcloud.net.cn/plugin?id=985
* @property {Boolean} show = [false|true] 控制组件显示或隐藏 * @property {Boolean} show = [false|true] 控制组件显示或隐藏
* @property {Array|String} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型 * @property {Array|String} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
* @value fade 渐隐渐出过渡 * @value fade 渐隐渐出过渡
* @value slide-top 由上至下过渡 * @value slide-top 由上至下过渡
* @value slide-right 由右至左过渡 * @value slide-right 由右至左过渡
* @value slide-bottom 由下至上过渡 * @value slide-bottom 由下至上过渡
* @value slide-left 由左至右过渡 * @value slide-left 由左至右过渡
* @value zoom-in 由小到大过渡 * @value zoom-in 由小到大过渡
* @value zoom-out 由大到小过渡 * @value zoom-out 由大到小过渡
* @property {Number} duration 过渡动画持续时间 * @property {Number} duration 过渡动画持续时间
* @property {Object} styles 组件样式 css 样式注意带-连接符的属性需要使用小驼峰写法如`backgroundColor:red` * @property {Object} styles 组件样式 css 样式注意带-连接符的属性需要使用小驼峰写法如`backgroundColor:red`
*/ */
export default { export default {
name: 'uniTransition', name: 'uniTransition',
emits:['click','change'], emits: ['click', 'change'],
props: { props: {
show: { show: {
type: Boolean, type: Boolean,
default: false default: false
}, },
modeClass: { modeClass: {
type: [Array, String], type: [Array, String],
default() { default () {
return 'fade' return 'fade'
}
},
duration: {
type: Number,
default: 300
},
styles: {
type: Object,
default() {
return {}
}
},
customClass:{
type: String,
default: ''
},
onceRender:{
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 duration: {
} type: Number,
}, default: 300
computed: { },
// styles: {
stylesObject() { type: Object,
let styles = { default () {
...this.styles, return {}
'transition-duration': this.duration / 1000 + 's' }
} },
let transform = '' customClass: {
for (let i in styles) { type: String,
let line = this.toLine(i) default: ''
transform += line + ':' + styles[i] + ';' },
} onceRender: {
return transform type: Boolean,
default: false
},
}, },
// data() {
transformStyles() { return {
return 'transform:' + this.transform + ';' + 'opacity:' + this.opacity + ';' + this.stylesObject isShow: false,
} transform: '',
}, opacity: 0,
created() { animationData: {},
// durationTime: 300,
this.config = { config: {}
duration: this.duration,
timingFunction: 'ease',
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)
}, },
/** watch: {
* 点击组件触发回调 show: {
*/ handler(newVal) {
onClick() { if (newVal) {
this.$emit('click', { this.open()
detail: this.isShow } else {
}) // close,
}, if (this.isShow) {
/** this.close()
* 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} 不存在`) immediate: true
}
} }
this.animation.step(config)
return this
}, },
/** computed: {
* ref 触发 执行动画 //
*/ stylesObject() {
run(fn) { let styles = {
if (!this.animation) return ...this.styles,
this.animation.run(fn) 'transition-duration': this.duration / 1000 + 's'
}, }
// let transform = ''
open() { for (let i in styles) {
clearTimeout(this.timer) let line = this.toLine(i)
this.transform = '' transform += line + ':' + styles[i] + ';'
this.isShow = true }
let { opacity, transform } = this.styleInit(false) return transform
if (typeof opacity !== 'undefined') { },
this.opacity = opacity //
transformStyles() {
return 'transform:' + this.transform + ';' + 'opacity:' + this.opacity + ';' + this.stylesObject
} }
this.transform = transform
// nextTick wx
this.$nextTick(() => {
// TODO
this.timer = setTimeout(() => {
this.animation = createAnimation(this.config, this)
this.tranfromInit(false).step()
this.animation.run()
this.$emit('change', {
detail: this.isShow
})
}, 20)
})
}, },
// created() {
close(type) { //
if (!this.animation) return this.config = {
this.tranfromInit(true) duration: this.duration,
.step() timingFunction: 'ease',
.run(() => { transformOrigin: '50% 50%',
this.isShow = false delay: 0
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) => { this.durationTime = this.duration
if (mode === 'fade') { },
styles.opacity = this.animationType(type)[mode] methods: {
} else { /**
styles.transform += this.animationType(type)[mode] + ' ' * ref 触发 初始化动画
*/
init(obj = {}) {
if (obj.duration) {
this.durationTime = obj.duration
} }
} this.animation = createAnimation(Object.assign(this.config, obj), this)
if (typeof this.modeClass === 'string') { },
buildStyle(type, this.modeClass) /**
} else { * 点击组件触发回调
this.modeClass.forEach(mode => { */
buildStyle(type, mode) onClick() {
this.$emit('click', {
detail: this.isShow
}) })
} },
return styles /**
}, * ref 触发 动画分组
// * @param {Object} obj
tranfromInit(type) { */
let buildTranfrom = (type, mode) => { step(obj, config = {}) {
let aniNum = null if (!this.animation) return this
if (mode === 'fade') { Object.keys(obj).forEach(key => {
aniNum = type ? 0 : 1 const value = obj[key]
} else { if (typeof this.animation[key] === 'function') {
aniNum = type ? '-100%' : '0' Array.isArray(value) ?
if (mode === 'zoom-in') { this.animation[key](...value) :
aniNum = type ? 0.8 : 1 this.animation[key](value)
}
if (mode === 'zoom-out') {
aniNum = type ? 1.2 : 1
} }
if (mode === 'slide-right') { })
aniNum = type ? '100%' : '0' this.animation.step(config)
return this
},
/**
* ref 触发 执行动画
*/
run(fn) {
if (!this.animation) return
this.animation.run(fn)
},
//
open() {
clearTimeout(this.timer)
this.isShow = true
//
this.transform = this.styleInit(false).transform || ''
this.opacity = this.styleInit(false).opacity || 0
// nextTick wx
this.$nextTick(() => {
// TODO
this.timer = setTimeout(() => {
this.animation = createAnimation(this.config, this)
this.tranfromInit(false).step()
this.animation.run(() => {
// #ifdef APP-NVUE
this.transform = this.styleInit(false).transform || ''
this.opacity = this.styleInit(false).opacity || 1
// #endif
// #ifndef APP-NVUE
this.transform = ''
this.opacity = this.styleInit(false).opacity || 1
// #endif
this.$emit('change', {
detail: this.isShow
})
})
}, 80)
})
},
//
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: '', opacity: 1 }
const buildStyle = (type, mode) => {
const value = this.animationType(type)[mode] // 使 type
if (mode.startsWith('fade')) {
styles.opacity = value
} else {
styles.transform += value + ' '
} }
if (mode === 'slide-bottom') { }
aniNum = type ? '100%' : '0'
if (typeof this.modeClass === 'string') {
buildStyle(type, this.modeClass)
} else {
this.modeClass.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.modeClass === 'string') {
buildTranfrom(type, this.modeClass)
} else {
this.modeClass.forEach(mode => {
buildTranfrom(type, mode)
})
} }
this.animation[this.animationMode()[mode]](aniNum)
}
if (typeof this.modeClass === 'string') {
buildTranfrom(type, this.modeClass)
} else {
this.modeClass.forEach(mode => {
buildTranfrom(type, mode)
})
}
return this.animation return this.animation
}, },
animationType(type) { animationType(type) {
return { return {
fade: type ? 1 : 0, fade: type ? 1 : 0,
'slide-top': `translateY(${type ? '0' : '-100%'})`, 'slide-top': `translateY(${type ? '0' : '-100%'})`,
'slide-right': `translateX(${type ? '0' : '100%'})`, 'slide-right': `translateX(${type ? '0' : '100%'})`,
'slide-bottom': `translateY(${type ? '0' : '100%'})`, 'slide-bottom': `translateY(${type ? '0' : '100%'})`,
'slide-left': `translateX(${type ? '0' : '-100%'})`, 'slide-left': `translateX(${type ? '0' : '-100%'})`,
'zoom-in': `scaleX(${type ? 1 : 0.8}) scaleY(${type ? 1 : 0.8})`, 'zoom-in': `scaleX(${type ? 1 : 0.8}) scaleY(${type ? 1 : 0.8})`,
'zoom-out': `scaleX(${type ? 1 : 1.2}) scaleY(${type ? 1 : 1.2})` 'zoom-out': `scaleX(${type ? 1 : 1.2}) scaleY(${type ? 1 : 1.2})`
} }
}, },
// //
animationMode() { animationMode() {
return { return {
fade: 'opacity', fade: 'opacity',
'slide-top': 'translateY', 'slide-top': 'translateY',
'slide-right': 'translateX', 'slide-right': 'translateX',
'slide-bottom': 'translateY', 'slide-bottom': 'translateY',
'slide-left': 'translateX', 'slide-left': 'translateX',
'zoom-in': 'scale', 'zoom-in': 'scale',
'zoom-out': 'scale' 'zoom-out': 'scale'
}
},
// 线
toLine(name) {
return name.replace(/([A-Z])/g, '-$1').toLowerCase()
} }
},
// 线
toLine(name) {
return name.replace(/([A-Z])/g, '-$1').toLowerCase()
} }
} }
}
</script> </script>
<style></style> <style></style>

102
uni_modules/uni-transition/package.json

@ -1,7 +1,7 @@
{ {
"id": "uni-transition", "id": "uni-transition",
"displayName": "uni-transition 过渡动画", "displayName": "uni-transition 过渡动画",
"version": "1.3.2", "version": "1.3.6",
"description": "元素的简单过渡动画", "description": "元素的简单过渡动画",
"keywords": [ "keywords": [
"uni-ui", "uni-ui",
@ -12,12 +12,14 @@
], ],
"repository": "https://github.com/dcloudio/uni-ui", "repository": "https://github.com/dcloudio/uni-ui",
"engines": { "engines": {
"HBuilderX": "" "HBuilderX": "",
"uni-app": "^4.12",
"uni-app-x": ""
}, },
"directories": { "directories": {
"example": "../../temps/example_temps" "example": "../../temps/example_temps"
}, },
"dcloudext": { "dcloudext": {
"sale": { "sale": {
"regular": { "regular": {
"price": "0.00" "price": "0.00"
@ -35,48 +37,74 @@
"permissions": "无" "permissions": "无"
}, },
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue" "type": "component-vue",
"darkmode": "x",
"i18n": "x",
"widescreen": "x"
}, },
"uni_modules": { "uni_modules": {
"dependencies": ["uni-scss"], "dependencies": [
"uni-scss"
],
"encrypt": [], "encrypt": [],
"platforms": { "platforms": {
"cloud": { "cloud": {
"tcb": "y", "tcb": "x",
"aliyun": "y" "aliyun": "x",
"alipay": "x"
}, },
"client": { "client": {
"App": { "uni-app": {
"app-vue": "y", "vue": {
"app-nvue": "y" "vue2": "√",
"vue3": "√"
},
"web": {
"safari": "√",
"chrome": "√"
},
"app": {
"vue": "√",
"nvue": "√",
"android": "√",
"ios": "√",
"harmony": "√"
},
"mp": {
"weixin": {
},
"alipay": {
},
"toutiao": {
},
"baidu": {
},
"kuaishou": {
},
"jd": {
},
"harmony": "-",
"qq": "√",
"lark": "-"
},
"quickapp": {
"huawei": "√",
"union": "√"
}
}, },
"H5-mobile": { "uni-app-x": {
"Safari": "y", "web": {
"Android Browser": "y", "safari": "-",
"微信浏览器(Android)": "y", "chrome": "-"
"QQ浏览器(Android)": "y" },
}, "app": {
"H5-pc": { "android": "-",
"Chrome": "y", "ios": "-",
"IE": "y", "harmony": "-"
"Edge": "y", },
"Firefox": "y", "mp": {
"Safari": "y" "weixin": "-"
}, }
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
} }
} }
} }

Loading…
Cancel
Save