Vue点击展开收起动画与原生JS实现效果不一致如何解决
问题复现
我正在参照教程制作仅使用HTML、CSS与原生JavaScript实现的展开收起动画,预期实现平滑的展开、收起效果:
原生实现代码
HTML
<div class="box"> <div class="top"> <h1>Lorem Ipsum</h1> </div> <p class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. </p> <button><i class="arrow"></i></button> </div>
CSS
@import url("https://fonts.googleapis.com/css?family=Dosis:200,400&display=swap"); body { color: #000; background: #e2e2e2; font-family: "Dosis", sans-serif; } /* Box */ .box { margin: 22px auto; width: 320px; padding: 12px 32px 64px; max-height: 162px; overflow: hidden; transition: max-height 0.3s cubic-bezier(0, 1, 0, 1); } .box.open { max-height: 100rem; transition: max-height 0.3s cubic-bezier(0.9, 0, 0.8, 0.2); } /* Text */ @keyframes open { from { line-clamp: 3; -webkit-line-clamp: 3; } to { line-clamp: initial; -webkit-line-clamp: initial; } } @keyframes close { from { line-clamp: initial; -webkit-line-clamp: initial; } to { line-clamp: 3; -webkit-line-clamp: 3; } } .text { display: -webkit-box; -webkit-box-orient: vertical; text-overflow: ellipsis; overflow: hidden; margin: 12px 0; animation: close 0.1s linear 0.1s forwards; } .open .text { animation: open 0.1s linear 0s forwards; } /* Irrelavant css... */ .arrow { border: solid #000; border-width: 0 2px 2px 0; display: inline-block; padding: 4px; transform: rotate(45deg); -webkit-transform: rotate(45deg); } .open .arrow { transform: rotate(-135deg); -webkit-transform: rotate(-135deg); margin-top: 5px; } button { background: transparent; border: 2px solid #000; height: 32px; width: 32px; border-radius: 50%; outline: none; cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; margin: 0 auto; }
JavaScript
const box = document.querySelector('.box'); let isOpen = false; document.querySelector('button').addEventListener('click', () => { isOpen = !isOpen; isOpen ? box.classList.add('open') : box.classList.remove('open') });
Vue迁移后异常
将上述逻辑迁移到Vue中,使用完全相同的CSS代码,实际效果不符合预期:
异常的Vue代码(App.vue)
<template> <div id="app"> <div :class="{ box, open: showMore }"> <div class="top"> <h1>Show More</h1> </div> <p class="text"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. </p> <button @click="handleShowMore()"><i class="arrow"></i></button> </div> </div> </template> <script> export default { name: "App", data() { return { showMore: false, }; }, methods: { handleShowMore() { this.showMore = !this.showMore; }, }, }; </script> <style> #app { font-family: "Avenir", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } /* Box */ .box { margin: 22px auto; width: 320px; padding: 12px 32px 64px; max-height: 162px; overflow: hidden; transition: max-height 0.3s cubic-bezier(0, 1, 0, 1); } .box.open { max-height: 100rem; transition: max-height 0.3s cubic-bezier(0.9, 0, 0.8, 0.2); } /* Text */ @keyframes open { from { line-clamp: 3; -webkit-line-clamp: 3; } to { line-clamp: initial; -webkit-line-clamp: initial; } } @keyframes close { from { line-clamp: initial; -webkit-line-clamp: initial; } to { line-clamp: 3; -webkit-line-clamp: 3; } } .text { display: -webkit-box; -webkit-box-orient: vertical; text-overflow: ellipsis; overflow: hidden; margin: 12px 0; animation: close 0.1s linear 0.1s forwards; } .open .text { animation: open 0.1s linear 0s forwards; } /* Irrelavant css... */ .arrow { border: solid #000; border-width: 0 2px 2px 0; display: inline-block; padding: 4px; transform: rotate(45deg); -webkit-transform: rotate(45deg); } .open .arrow { transform: rotate(-135deg); -webkit-transform: rotate(-135deg); margin-top: 5px; } button { background: transparent; border: 2px solid #000; height: 32px; width: 32px; border-radius: 50%; outline: none; cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; margin: 0 auto; } </style>
问题解答
差异原因
问题出在Vue的class绑定语法错误:{ box, open: showMore } 这种对象写法里,box会被Vue识别为变量名,而不是字符串类名。你没有在data里定义box变量,所以这个类根本没有被挂载到div上,.box`对应的所有样式都没生效,自然动画不符合预期。
修复方案
修改模板里的class绑定即可,有两种写法可选:
- 把固定的
box类提为静态类,动态类只控制open状态:
<div class="box" :class="{ open: showMore }">
- 保持对象写法,给
box加上引号明确是类名字符串:
<div :class="{ 'box': true, 'open': showMore }">
修改后就能复现原生实现的动画效果。
内容的提问来源于stack exchange,提问作者CCCC
相关产品推荐
相关产品推荐

