过渡组在 Vue 渲染函数中不起作用
我正在尝试将 Nuxt.js 与 nuxt/tailwind 结合使用来构建我自己的Carousel。
我做了一个工作示例,并通过渲染函数重写了模板部分。
但我发现过渡组并不像以前的那样工作。
这是一个简单的版本,transition-group标签在渲染函数中不起作用:
components/Faded.vue
<script>
export default {
render(h) {
return h(
"transition-group",
{
props: {
name: "faded",
},
},
this.$slots.default
);
},
};
</script>
<style lang="postcss" scoped>
.faded-leave {
opacity: 1;
}
.faded-leave-active {
transition: opacity 1s;
}
.faded-leave-to {
opacity: 0;
}
.faded-enter {
opacity: 0;
}
.faded-enter-active {
transition: opacity 1s;
}
.faded-enter-to {
opacity: 1;
}
</style>
index.vue
<template>
<div>
<button class="bg-green-100" @click="AddIndex">Button</button>
<Faded>
<div key="1" v-show="this.showIndex === 0" class="bg-red-100">0</div>
<div key="2" v-show="this.showIndex === 1" class="bg-yellow-100">1</div>
<div key="3" v-show="this.showIndex === 2" class="bg-blue-100">2</div>
</Faded>
</div>
</template>
<script>
export default {
data() {
return {
showIndex: 0,
};
},
methods: {
AddIndex() {
this.showIndex = (this.showIndex + 1) % 3;
},
},
};
</script>
原始问题
此代码按我的预期工作:
index.vue
<div class="h-screen flex justify-center">
<div class="h-[60%] lg:w-[50%] w-full bg-black">
<Carousel />
</div>
</div>
Carousel.vue
(正确版本)
<template>
<div class="wrap">
<transition-group tag="div" class="container" :name="transitionName">
<Slide v-for="(img,index) of imgs" :key="img.src" v-show="index===show">
<img :src="img.src" class="object-cover select-none"/>
</Slide>
</transition-group>
<NavigationGroup v-show="showNavigators" :show="show" :length="imgs.length" :setShow="setShow"/>
<button @click="setShow(show-1)" v-show="showArrows && (cycle || show!==0)" class="navigate-arrow left-2">
<IconFont type="fas" name="angle-left"/>
</button>
<button @click="setShow(show+1)" v-show="showArrows && (cycle || show!==imgs.length-1)" class="navigate-arrow right-2">
<IconFont type="fas" name="angle-right"/>
</button>
</div>
</template>
<script>
export default {
props :{
interval: {type: Number, default: 5000},
autoplay: {type: Boolean, default: false},
cycle: {type: Boolean, default: true},
showArrows: {type: Boolean ,default: true},
showNavigators: {type: Boolean, default: true},
},
data () {
return {
timer: undefined,
transitionName: 'left-in',
show: 0,
imgs: [
{ src: require('~/assets/images/bear.jpg') },
{ src: require('~/assets/images/all-namin.png') },
{ src: require('~/assets/images/eat.png') },
{ src: require('~/assets/images/teemo.jpg') },
{ src: require('~/assets/images/gun.png') },
]
}
},
mounted () {
if(this.autoplay && this.cycle){
this.timer = setInterval(this.nextShow, this.interval)
}
},
methods: {
setShow (index) {
this.show = index
},
nextShow () {
this.show++
}
},
watch: {
show (nVal, oVal) {
if (nVal < 0) {
this.show = this.cycle? this.imgs.length - 1: oVal
} else if (nVal > this.imgs.length - 1) {
this.show = this.cycle? 0: oVal
} else {
if (oVal < 0) this.transitionName = 'left-in'
else if (oVal > this.imgs.length - 1) this.transitionName = 'right-in'
else this.transitionName = nVal > oVal ? 'right-in' : 'left-in'
}
}
},
}
</script>
<style lang="postcss" scoped>
.right-in-enter{
@apply left-full;
}
.right-in-enter-active, .right-in-leave-active{
transition: left 0.5s;
}
.right-in-enter-to, .right-in-leave{
@apply left-0;
}
.right-in-leave-to{
@apply -left-full;
}
.left-in-enter{
@apply -left-full;
}
.left-in-enter-active, .left-in-leave-active{
transition: left 0.5s;
}
.left-in-enter-to, .left-in-leave{
left:0%
}
.left-in-leave-to{
left:100%
}
.wrap {
@apply relative flex justify-center w-full h-full;
}
.container{
@apply relative overflow-hidden w-full;
margin: 0 auto;
}
.page{
@apply absolute w-full h-full flex justify-center;
}
.navigate-container {
@apply absolute bottom-[5%] flex justify-center gap-2 lg:gap-5 select-none;
}
.navigate-dot {
@apply rounded-full w-4 h-4 bg-gray-500;
}
.navigate-dot-active {
@apply animate-pulse;
box-shadow: 0 0 2px 5px #d1d5db;
}
.navigate-arrow {
@apply absolute top-[50%] w-5 h-5 select-none flex justify-center items-center bg-gray-400 text-xl rounded-full text-white;
}
</style>
但是过渡组似乎在以下代码中不起作用
index.vue
<Carousel>
<img :src="img.src" v-for="img in imgs" :key="img.src" class="object-cover">
</Carousel>
Carousel.vue
(破解版)
<script>
import IconFontVue from '../IconFont.vue'
import NavigationGroupVue from './NavigationGroup.vue'
import SlideVue from './Slide.vue'
export default {
props :{
interval: {type: Number, default: 5000},
autoplay: {type: Boolean, default: false},
cycle: {type: Boolean, default: true},
showArrows: {type: Boolean ,default: true},
showNavigators: {type: Boolean, default: true},
},
data(){
return {
timer: undefined,
transitionDirection: 'left-in',
show: 0,
children: Array(0),
}
},
mounted () {
this.children = this.$slots.default
if(this.autoplay && this.cycle){
this.timer = setInterval(this.nextShow, this.interval)
}
},
methods: {
setShow(index){
this.show = index
},
nextShow () {
this.show++
}
},
watch: {
show (nVal, oVal) {
if (nVal < 0) {
this.show = this.cycle? this.children.length - 1: oVal
} else if (nVal > this.children.length - 1) {
this.show = this.cycle? 0: oVal
} else {
if (oVal < 0) this.transitionDirection = 'left-in'
else if (oVal > this.children.length - 1) this.transitionDirection = 'right-in'
else this.transitionDirection = nVal > oVal ? 'right-in' : 'left-in'
}
}
},
render(h){
return h('div',{
class:{
'wrap':true,
}
},[
// transition group slides
h('transition-group',{
props:{
name: this.transitionDirection,
},
class:{
'containing': true,
}
},this.children.map((elem,index)=>{
return h(SlideVue,{
key: `slide-${index}`,
style:{
'display': this.show===index?'':'none'
}
},[elem])
})),
// navigation button
h(NavigationGroupVue,{
class:{
'hidden':!this.showNavigators,
},
props:{
show: this.show,
length: this.children.length,
setShow: this.setShow,
},
}),
// left button
h('button',{
class:{
'navigate-arrow left-2':true,
'hidden': !(this.showArrows && (this.cycle || this.show!==0))
},
on:{
click:()=>{
this.setShow(this.show-1)
}
}
},[
h(IconFontVue,{
props:{
name:"angle-left",
type:"fas",
}
})
]),
//right button
h('button',{
class:{
'navigate-arrow right-2':true,
'hidden': !(this.showArrows && (this.cycle || this.show!==this.children.length-1))
},
on:{
click:()=>{
this.setShow(this.show+1)
}
}
},[
h(IconFontVue,{
props:{
name:"angle-right",
type:"fas",
}
})
]),
])
}
}
</script>
<style lang="postcss">
.right-in-enter{
@apply left-full;
}
.right-in-enter-to, .right-in-leave{
@apply left-0;
}
.right-in-leave-to{
@apply -left-full;
}
.left-in-enter{
@apply -left-full;
}
.left-in-enter-active,
.left-in-leave-active,
.right-in-enter-active,
.right-in-leave-active{
transition: left 0.5s;
}
.left-in-enter-to, .left-in-leave{
@apply left-0;
}
.left-in-leave-to{
@apply left-full;
}
.wrap {
@apply relative flex justify-center w-full h-full;
}
.containing{
@apply relative overflow-hidden w-full;
margin: 0 auto;
}
.page{
@apply absolute w-full h-full flex justify-center;
}
.navigate-container {
@apply absolute bottom-[5%] flex justify-center gap-2 lg:gap-5 select-none;
}
.navigate-dot {
@apply rounded-full w-4 h-4 bg-gray-500;
}
.navigate-dot-active {
@apply animate-pulse;
box-shadow: 0 0 2px 5px #d1d5db;
}
.navigate-arrow {
@apply absolute top-[50%] w-5 h-5 select-none flex justify-center items-center bg-gray-400 text-xl rounded-full text-white;
}
</style>
两段代码编译后类似。但是当我单击箭头或导航按钮时,转换组的类不起作用。有人可以帮我吗?
I'm trying to use Nuxt.js with nuxt/tailwind to build my own Carousel.
I have done a working example, and rewrite the template part by render function.
But I found that the transition-group is not working as previous one.
Here is a simple version, the transition-group tag is not working in render function:
components/Faded.vue
<script>
export default {
render(h) {
return h(
"transition-group",
{
props: {
name: "faded",
},
},
this.$slots.default
);
},
};
</script>
<style lang="postcss" scoped>
.faded-leave {
opacity: 1;
}
.faded-leave-active {
transition: opacity 1s;
}
.faded-leave-to {
opacity: 0;
}
.faded-enter {
opacity: 0;
}
.faded-enter-active {
transition: opacity 1s;
}
.faded-enter-to {
opacity: 1;
}
</style>
index.vue
<template>
<div>
<button class="bg-green-100" @click="AddIndex">Button</button>
<Faded>
<div key="1" v-show="this.showIndex === 0" class="bg-red-100">0</div>
<div key="2" v-show="this.showIndex === 1" class="bg-yellow-100">1</div>
<div key="3" v-show="this.showIndex === 2" class="bg-blue-100">2</div>
</Faded>
</div>
</template>
<script>
export default {
data() {
return {
showIndex: 0,
};
},
methods: {
AddIndex() {
this.showIndex = (this.showIndex + 1) % 3;
},
},
};
</script>
original question
This code is working as my expect:
index.vue
<div class="h-screen flex justify-center">
<div class="h-[60%] lg:w-[50%] w-full bg-black">
<Carousel />
</div>
</div>
Carousel.vue
(correct version)
<template>
<div class="wrap">
<transition-group tag="div" class="container" :name="transitionName">
<Slide v-for="(img,index) of imgs" :key="img.src" v-show="index===show">
<img :src="img.src" class="object-cover select-none"/>
</Slide>
</transition-group>
<NavigationGroup v-show="showNavigators" :show="show" :length="imgs.length" :setShow="setShow"/>
<button @click="setShow(show-1)" v-show="showArrows && (cycle || show!==0)" class="navigate-arrow left-2">
<IconFont type="fas" name="angle-left"/>
</button>
<button @click="setShow(show+1)" v-show="showArrows && (cycle || show!==imgs.length-1)" class="navigate-arrow right-2">
<IconFont type="fas" name="angle-right"/>
</button>
</div>
</template>
<script>
export default {
props :{
interval: {type: Number, default: 5000},
autoplay: {type: Boolean, default: false},
cycle: {type: Boolean, default: true},
showArrows: {type: Boolean ,default: true},
showNavigators: {type: Boolean, default: true},
},
data () {
return {
timer: undefined,
transitionName: 'left-in',
show: 0,
imgs: [
{ src: require('~/assets/images/bear.jpg') },
{ src: require('~/assets/images/all-namin.png') },
{ src: require('~/assets/images/eat.png') },
{ src: require('~/assets/images/teemo.jpg') },
{ src: require('~/assets/images/gun.png') },
]
}
},
mounted () {
if(this.autoplay && this.cycle){
this.timer = setInterval(this.nextShow, this.interval)
}
},
methods: {
setShow (index) {
this.show = index
},
nextShow () {
this.show++
}
},
watch: {
show (nVal, oVal) {
if (nVal < 0) {
this.show = this.cycle? this.imgs.length - 1: oVal
} else if (nVal > this.imgs.length - 1) {
this.show = this.cycle? 0: oVal
} else {
if (oVal < 0) this.transitionName = 'left-in'
else if (oVal > this.imgs.length - 1) this.transitionName = 'right-in'
else this.transitionName = nVal > oVal ? 'right-in' : 'left-in'
}
}
},
}
</script>
<style lang="postcss" scoped>
.right-in-enter{
@apply left-full;
}
.right-in-enter-active, .right-in-leave-active{
transition: left 0.5s;
}
.right-in-enter-to, .right-in-leave{
@apply left-0;
}
.right-in-leave-to{
@apply -left-full;
}
.left-in-enter{
@apply -left-full;
}
.left-in-enter-active, .left-in-leave-active{
transition: left 0.5s;
}
.left-in-enter-to, .left-in-leave{
left:0%
}
.left-in-leave-to{
left:100%
}
.wrap {
@apply relative flex justify-center w-full h-full;
}
.container{
@apply relative overflow-hidden w-full;
margin: 0 auto;
}
.page{
@apply absolute w-full h-full flex justify-center;
}
.navigate-container {
@apply absolute bottom-[5%] flex justify-center gap-2 lg:gap-5 select-none;
}
.navigate-dot {
@apply rounded-full w-4 h-4 bg-gray-500;
}
.navigate-dot-active {
@apply animate-pulse;
box-shadow: 0 0 2px 5px #d1d5db;
}
.navigate-arrow {
@apply absolute top-[50%] w-5 h-5 select-none flex justify-center items-center bg-gray-400 text-xl rounded-full text-white;
}
</style>
But the transition-group seems not working in the following code
index.vue
<Carousel>
<img :src="img.src" v-for="img in imgs" :key="img.src" class="object-cover">
</Carousel>
Carousel.vue
(broken version)
<script>
import IconFontVue from '../IconFont.vue'
import NavigationGroupVue from './NavigationGroup.vue'
import SlideVue from './Slide.vue'
export default {
props :{
interval: {type: Number, default: 5000},
autoplay: {type: Boolean, default: false},
cycle: {type: Boolean, default: true},
showArrows: {type: Boolean ,default: true},
showNavigators: {type: Boolean, default: true},
},
data(){
return {
timer: undefined,
transitionDirection: 'left-in',
show: 0,
children: Array(0),
}
},
mounted () {
this.children = this.$slots.default
if(this.autoplay && this.cycle){
this.timer = setInterval(this.nextShow, this.interval)
}
},
methods: {
setShow(index){
this.show = index
},
nextShow () {
this.show++
}
},
watch: {
show (nVal, oVal) {
if (nVal < 0) {
this.show = this.cycle? this.children.length - 1: oVal
} else if (nVal > this.children.length - 1) {
this.show = this.cycle? 0: oVal
} else {
if (oVal < 0) this.transitionDirection = 'left-in'
else if (oVal > this.children.length - 1) this.transitionDirection = 'right-in'
else this.transitionDirection = nVal > oVal ? 'right-in' : 'left-in'
}
}
},
render(h){
return h('div',{
class:{
'wrap':true,
}
},[
// transition group slides
h('transition-group',{
props:{
name: this.transitionDirection,
},
class:{
'containing': true,
}
},this.children.map((elem,index)=>{
return h(SlideVue,{
key: `slide-${index}`,
style:{
'display': this.show===index?'':'none'
}
},[elem])
})),
// navigation button
h(NavigationGroupVue,{
class:{
'hidden':!this.showNavigators,
},
props:{
show: this.show,
length: this.children.length,
setShow: this.setShow,
},
}),
// left button
h('button',{
class:{
'navigate-arrow left-2':true,
'hidden': !(this.showArrows && (this.cycle || this.show!==0))
},
on:{
click:()=>{
this.setShow(this.show-1)
}
}
},[
h(IconFontVue,{
props:{
name:"angle-left",
type:"fas",
}
})
]),
//right button
h('button',{
class:{
'navigate-arrow right-2':true,
'hidden': !(this.showArrows && (this.cycle || this.show!==this.children.length-1))
},
on:{
click:()=>{
this.setShow(this.show+1)
}
}
},[
h(IconFontVue,{
props:{
name:"angle-right",
type:"fas",
}
})
]),
])
}
}
</script>
<style lang="postcss">
.right-in-enter{
@apply left-full;
}
.right-in-enter-to, .right-in-leave{
@apply left-0;
}
.right-in-leave-to{
@apply -left-full;
}
.left-in-enter{
@apply -left-full;
}
.left-in-enter-active,
.left-in-leave-active,
.right-in-enter-active,
.right-in-leave-active{
transition: left 0.5s;
}
.left-in-enter-to, .left-in-leave{
@apply left-0;
}
.left-in-leave-to{
@apply left-full;
}
.wrap {
@apply relative flex justify-center w-full h-full;
}
.containing{
@apply relative overflow-hidden w-full;
margin: 0 auto;
}
.page{
@apply absolute w-full h-full flex justify-center;
}
.navigate-container {
@apply absolute bottom-[5%] flex justify-center gap-2 lg:gap-5 select-none;
}
.navigate-dot {
@apply rounded-full w-4 h-4 bg-gray-500;
}
.navigate-dot-active {
@apply animate-pulse;
box-shadow: 0 0 2px 5px #d1d5db;
}
.navigate-arrow {
@apply absolute top-[50%] w-5 h-5 select-none flex justify-center items-center bg-gray-400 text-xl rounded-full text-white;
}
</style>
The two codes are similar after compiling. But the classes of transition-group are not working when I click the arrow or navigating button. Can someone please help me ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论