91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue不定高度展開效果怎么實現

發布時間:2022-06-20 11:54:28 來源:億速云 閱讀:217 作者:iii 欄目:開發技術

本篇內容介紹了“Vue不定高度展開效果怎么實現”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

使用場景

問答模塊的靜態頁面開發并不復雜,也沒有特殊的交互。唯一有一點難度應該是回答部分的展開特效。

  • 展開時,需要從上往下將回答部分的 div 慢慢撐開,上面的箭頭也要有旋轉的特效。

  • 收回時,需要從下往上將回答部分的 div 慢慢縮小,上面的箭頭也要有旋轉的特效。

對于一般的展開、隱藏特效,只需要在對應元素的 height 上面增加過渡效果即可。但問題是: 不知道對應的 div 的高度,其高度是內部的元素自動撐開的,此時直接在 height 屬性上面添加過渡效果會失效(后面會說明原因)。

對于箭頭的旋轉,則只需要在箭頭元素的 transform 上面增加過渡效果,然后讓其旋轉 180 度(rotateZ(180deg))即可,這個比較好實現。

背景

今天做需求時,正好需要做這種特效。也就是上面的第一張圖。先介紹一下列表的數據結構和其 DOM 結構。

列表數據結構如下:

// Item 表示問答的每一項
interface Item {
  Q: string;  // 問題
  A: string;  // 回答
  show: boolean;  // 是否展示
}

// List 表示問答列表
type List = Item[];

項目中并未使用 TypeScript,這里用 interface 是為了方便理解。

DOM 結構(Vue 版本)如下:

<div class="qa panel">
  <div class="qa__title">
    常見問題
  </div>
  <div class="list-qa">
    <div
      v-for="(item, ind) in qaList"
      :key="ind"
      class="list-qa__item"
    >
      <div class="list-qa__question">
        <span>{{ item.Q }}</span>
        <span class="list-qa__question__arrow" />
      </div>
      <span class="list-qa__answer">
        {{ item.A }}
      </span>
    </div>
  </div>
</div>

上面的結構簡化了一些交互邏輯和展示邏輯,默認問答列表的每一項都會展示。最外層包裹了一層 div,上面是標題,下面是問答列表,問答列表的每一項包括問題、箭頭 icon 和答案。

實現

因為項目使用的框架是 Vue,所以以 Vue 為例,來分析一下如何實現它,以及其實現的原理。

回答是否展示,可以用一個變量控制,這里是 item 的 show 屬性。使用 v-show 實現,因為用戶可能會多次點擊箭頭,導致回答頻繁地展示或隱藏。

<div
  v-for="(item, ind) in list"
  :key="ind"
  class="list-item"
>
  <!-- 。。。省略不相關元素。。。 -->
  <span
    v-show="item.show"
    class="list-answer"
  >
    {{ item.A }}
  </span>
</div>

transition 組件

在 Vue 中,可以使用 transition 組件來為元素添加動態效果。transition 組件讓我們可以為使用條件渲染(v-if、v-show)的元素添加進入、離開時的過渡效果。

<div id="demo">
  <button v-on:click="show = !show">
    Toggle
  </button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

這樣在 name 為 fade 的 transition 組件包裹的 p 標簽展示和隱藏時,會有一個 0.5s 的淡入淡出效果。

過渡效果原理

在展示時,p 標簽的 opacity(透明度)會從 0(.fade-enter 類選擇器中設定的值)開始增加,經過 0.5s 之后,增加至 opacity: 1(元素默認的透明度 opacity 為 1)。

在隱藏時,p 標簽的 opacity(透明度)會從 1 開始減少,經過 0.5s 之后,減少至 opacity: 0.fade-leave-to 類選擇器中設定的值)。

這樣就實現了淡入淡出效果。

同樣的,如果我們想讓一個元素展示時高度從 0 開始增加,經過某一個時間,達到具體的值;隱藏時高度從該具體值開始減少,經過某一個時間,達到 0。這樣就能實現我們前面需要的效果。

我們可以用 css transition 為某一個元素設置過渡效果,過渡效果作用在這個元素的某個屬性上、過渡效果的時長等。

.box {
  transition: height 1s;
}

上面代表為 class 為 box 的元素設置了過渡效果,作用在它的 height 屬性上面,過渡效果的時長為 1s。當該元素的高度從某一個值變化到另一個值時,就會有一個長為 1s 的過渡效果。

過渡效果的本質是: 當作用的屬性的值變化時,并不會立即從一個值變為另一個值,而是在變化的過程中,將中間狀態呈現出來。

例如:設置了過渡效果的元素的高度(height)從 0 變化到 100px 時,并不是直接從 0 變化到 100px 的,其變化過程是一個連續的狀態,從 0 到 1px,從 1px 到 2px&middot;&middot;&middot;&middot;&middot;&middot;直到 100px。把中間的高度展現出來,就可以讓用戶看到過渡效果。

再例如:設置了過渡效果的元素的透明度(opacity)從 0 變化到 1 時,并不是直接從 0 變化到 1 的,其變化過程也是一個連續的狀態,從 0 到 0.1,從 0.1 到 0.2&middot;&middot;&middot;&middot;&middot;&middot;直到 opacity 為1。這樣用戶就可以看到一個元素從透明狀態逐漸變得清晰。當然,并不一定就是從 0 變化到 0.1,然后從 0.1 變化到 0.2,這個過程是一個連續的過程,它的值在慢慢增加,增量是多少并不重要。

需要實現過渡效果,就需要一個起始態和一個終止態,瀏覽器能夠從起始態逐步過渡到終止態。也就是從起始態到終止態之間的部分是連續的,是可以計算的,這樣瀏覽器才能把中間的狀態給我們呈現出來。

再回到之前的問題:不知道 div 的高度,其高度是內部的元素自動撐開的,此時直接在 height 屬性上面添加過渡效果會失效。

為什么會失效?為什么會失效?為什么會失效?

對于一個 div,如果它的高度是由子元素撐開的,那么它的 css 樣式 height 屬性的值為 auto。從 0 變到 auto,或者從 auto 變到 0,其中間狀態都是不可計算的,瀏覽器沒發給我們展示出中間狀態,所以我們看不到過渡效果。

既然從 0 變到 auto,或者從 auto 變到 0,中間狀態無法計算,那我們可以顯式地告訴瀏覽器一個數值,應該從 0 變到多少,或者從多少變到 0,讓瀏覽器可以計算出中間狀態,這樣不就能看到過渡效果了嗎?

解決

當展開時,起始態為 0,我們通過 getComputedStyle(element).height 得到元素的具體高度 x(終止態)。給元素設置 transition 屬性,然后將元素的高度從 0 變到 x,這樣就能實現展開的動效了。

<transition
  name="slide"
  @before-enter="beforeEnter"
  @enter="enter"
  @after-enter="afterEnter"
  @before-leave="beforeLeave"
  @leave="leave"
  @after-leave="afterLeave"
 >
  <span
    v-show="item.show"
    class="list-answer"
  >{{ item.A }}</span>
</transition>
beforeLeave(el) {
  // 給元素設置過渡效果
  el.style.transition = '0.3s height ease-in-out';
  // 高度變化時,讓其內容隱藏
  el.style.overflow = 'hidden';
},
leave(el) {
  el.style.height = 'auto';
  // 設置高度為具體的值
  el.style.height = window.getComputedStyle(el).height;
  // 強制瀏覽器回流,否則瀏覽器會合并兩次元素的高度更改(回流重繪的知識)
  el.offsetHeight;
  el.style.height = '0px';
},
afterLeave(el) {
  // el.style.height = null;
  // 收尾工作,展示完過渡效果之后,設為原來的值
  el.style.transition = '';
  el.style.overflow = 'visible';
},

這里需要給元素設置 overflow: hidden,在元素高度小于內部內容的高度時,才會隱藏內容。

同樣地,隱藏時先通過 getComputedStyle(element).height 得到元素的具體高度 x(起始態),給元素設置 transition 屬性,然后將元素的高度從 x 變到 0,這樣就能實現隱藏的動效了。

beforeEnter(el) {
  // 給元素設置過渡效果
  el.style.transition = '0.3s height ease-in-out';
  // 高度變化時,讓其內容隱藏
  el.style.overflow = 'hidden';
},
enter(el) {
  el.style.height = 'auto';
  // 保存元素原來的高度
  const endWidth = window.getComputedStyle(el).height;
  el.style.height = '0px';
  // 強制瀏覽器回流,否則瀏覽器會合并兩次元素的高度更改(回流重繪的知識)
  el.offsetHeight;
  el.style.height = endWidth;
},
afterEnter(el) {
  // el.style.height = null;
  // 收尾工作,展示完過渡效果之后,設為原來的值
  el.style.transition = '';
  el.style.overflow = 'visible';
},

箭頭的旋轉動效就比較簡單了。先設置過渡效果,然后只需要在點擊箭頭的時候,動態為這個元素添加一個類名,讓其旋轉屬性生效(rotateZ(180deg));當再一次點擊的時候,去掉這個類名就好了。

<span
  class="list-question__arrow"
  :class="{'list-question__rotate-arrow': !item.show}"
  @click="onClickPromblem(ind)"
/>
onClickPromblem(index) {
  const qaItem = this.qaList[index];
  this.$set(qaItem, 'show', !qaItem.show);
},
list-question__arrow {
  width: 12px;
  height: 12px;
  background: url(https://xxx.com/arrowup.png) center no-repeat;
  transition: transform .4s;
}
list-question__rotate-arrow {
  transform: rotateZ(180deg);
  transition: transform .4s;
}

“Vue不定高度展開效果怎么實現”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

vue
AI

施秉县| 阳信县| 客服| 古交市| 彰化县| 盐津县| 苍溪县| 肥城市| 大同市| 安阳县| 申扎县| 高唐县| 永仁县| 绍兴县| 天等县| 且末县| 南乐县| 琼结县| 佛学| 玉林市| 潮州市| 安岳县| 淳化县| 贵南县| 商南县| 石家庄市| 米泉市| 隆林| 施甸县| 年辖:市辖区| 炉霍县| 巫溪县| 白沙| 新蔡县| 泾川县| 德格县| 贺兰县| 济源市| 松滋市| 得荣县| 新平|