CCCC
CCCC

Reputation: 6469

vue - how to do a fade in out for Show More function

This is my current Show More page.
When I click the expand button, the text will be expand or collapse. enter image description here

I tried to update the css to below, in order to make a fade in out effect for the hided text.

@keyframes open {
  from {
    line-clamp: 3;
    -webkit-line-clamp: 3;
    opacity: 0; //new
  }
  to {
    line-clamp: initial;
    -webkit-line-clamp: initial;
    opacity: 1; //new
  }
}

@keyframes close {
  from {
    line-clamp: initial;
    -webkit-line-clamp: initial;
    opacity: 1; //new
  }
  to {
    line-clamp: 3;
    -webkit-line-clamp: 3;
    opacity: 0; //new
  }
}

After I added the code, I found that the original text is hided also.

How can I fix it?

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;
    /* opacity: 0; */
  }
  to {
    line-clamp: initial;
    -webkit-line-clamp: initial;
    opacity: 1;
  }
}

@keyframes close {
  from {
    line-clamp: initial;
    -webkit-line-clamp: initial;
    opacity: 1;
  }
  to {
    line-clamp: 3;
    -webkit-line-clamp: 3;
    /* opacity: 0; */
  }
}

.text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  text-overflow: ellipsis;
  overflow: hidden;
  margin: 12px 0;
  animation: close 2s linear 0.1s forwards;
}
.open .text {
  animation: open 2s 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>

Codesandbox:
https://codesandbox.io/s/amazing-goldwasser-e6l95?file=/src/App.vue

Upvotes: 1

Views: 981

Answers (1)

Anton
Anton

Reputation: 8508

You can't animate the line-clamp property. But, you can solve this problem:

  1. With ref, mounted() to get all height of the text and store the value to data.
  2. Set the max-height: 55px to the .text class. Equivalent to 3 lines of text.
  3. Bind :style with a <p> tag for to toggle the height of the text.
  4. Add another value to data, for toggle class and bind this the box class.
  5. In handleShowMore() adding check and when showMore is falsy, set setTimeout() where timeout unit should be equal to css transition-duration.

Edit dazziling-code

App.vue

<template>
  <div id="app">
    <div class="box" :class="className">
      <div class="top">
        <h1>Show More</h1>
      </div>
      <p
        :style="{ maxHeight: showMore ? expandedTextHeight + 'px' : '' }"
        class="text"
        ref="contentText"
      >
        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: () => ({
    showMore: false,
    expandedTextHeight: 0,
    className: '',
  }),
  methods: {
    handleShowMore() {
      this.showMore = !this.showMore;

      if (this.showMore) {
        this.className = 'open';
      } else {
        // After .5s remove class 'open'
        setTimeout(() => (this.className = ''), 500);
      }
    },
  },
  mounted() {
    // get full height
    this.expandedTextHeight = this.$refs.contentText.scrollHeight;
  },
};
</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: 370px;
  padding: 12px 32px 64px;
  overflow: hidden;
}

.text {
  max-height: 55px; /* Init 3 line height */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  text-overflow: ellipsis;
  overflow: hidden;
  margin: 12px 0;
  position: relative;
  line-clamp: 3;
  -webkit-line-clamp: 3;
  transition: all 0.5s cubic-bezier(0.9, 0, 0.8, 0.2);
}

.open .text {
  line-clamp: initial;
  -webkit-line-clamp: initial;
  transition: all 0.5s cubic-bezier(0.9, 0, 0.8, 0.2);
}

/* 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>

Upvotes: 1

Related Questions