前情提要:
前面已經有提到使用swiper輪播圖的用法,今天要用到更進階的教學,要像581那樣,點下按鈕跳出另外一個頁面,並且圖片可以在上面輪播


swiper安裝、使用

如果還不知道 swiper 怎麼使用的,請到前面一篇文章查看 swiper基礎教學

House show頁面

首先看到show這邊的view怎麼設定的,可以看到section裡面包著三個render部分,一個是圖片展示部分的上方區塊,一個是留言展示的下方區塊,還有一個留言表單區塊。
不過今天我們只要看圖片部分而已,所以另外部分就先不看。

view/houses/show

> <section class="mx-36">
>   <div class="mb-6 bg-white rounded-lg shadow">
>     
>     <%# 渲染房子上方區塊 %>
>     <%= render "card", house: @house %>
>   
>     <div class="w-full p-4 text-gray-600 focus-within:text-gray-400">            
>       <%# 下面這邊是渲染留言表單出來,順便會把兩個實體變數傳過去,一個是房子實體變數傳過去變區域變數,一個是把nil當作parent區域變數傳過去 <%>
>       <%= render partial: 'comments/form', locals: { house: @house, parent: nil, url: comments_path(@house) } %>                
>     </div>
> 
>     <div class="w-full p-10 mb-8 border-gray-100 border-y">
>       <%= render @comments %>                            
>     </div>
>     <br>
>      
>   </div>
> </section>

_card 頁面

下面這一區塊就是圖片展示區塊,可以看到 查看所有圖片按鈕 那一個區塊,我有掛上一個controller和action,所以等等點擊下去後,會跳出另外一個頁面

> <%# 圖片輪播區塊 %>    
> <div class="relative px-2 mx-3 mt-6 text-sm font-medium text-gray-400 mb-7">
>   <div class="flex gap-2">           
>     <%# 左邊圖片 %>
>     <div class="w-1/2">
>       <div class="w-full mr-1 text-xs text-blue-700 cursor-pointer font-base">
>         <%= image_tag house.images.first.variant(:first), class: "object-cover w-full h-full rounded-l-xl align-center" %>
>       </div>                                                                        
>     </div>
>     <%# 右邊圖片 %>
>     <div class="w-1/2 overflow-hidden rounded-r-xl">
>       <div class="grid grid-cols-2 grid-rows-2 gap-2">
>         <% house.images[1..4].each do |image| %>
>         <div class="w-full row-span-1 mr-1 text-xs text-blue-700 cursor-pointer font-base">                
>           <%= link_to image_tag(image.variant(:standard)), image.url, data: { lightbox: 'image-gallery' }, class: "object-cover w-full h-full", target: "_blank"%>
>         </div>
>         <% end %>
>       </div>                                                                          
>     </div>


>     <%# 查看所有圖片按鈕 %>
>     <div class="absolute right-0 px-6 py-3 text-base text-black bg-gray-100 rounded cursor-pointer bottom-3 hover:bg-gray-300" 
>          data-controller="show-all-images"
>          data-action="click->show-all-images#lookPics"
>          >
>       <p>
>         查看所有圖片 - <%= house.images.size %> 張 -> 
>       </p>
>     </div>


>   </div>
> </div>

查看所有圖片的controller.JS

來看一下剛剛查看所有圖片的controller做了什麼事,我們在點下按鈕的時候,使用兩個controller互相溝通的方法,把 popup_carousel 這個action給傳出去了

// show_all_images_controller.js

import { Controller } from "@hotwired/stimulus"
import { dispatchAction } from "./lib/dispatch"

export default class extends Controller {

  static targets = []

  connect() {}

  lookPics() {    
    const evt = new CustomEvent("popup_carousel")
    window.dispatchEvent(evt)    
  }
}

設定輪播頁面

現在我們來把輪播圖要放的區塊放出來,我們把該區塊放在house的show頁面,這邊有幾點要特別注意
(1) 因為這區塊一開始是隱藏的,所以用hidden藏起來 (2) 在這區塊設定一個新的controller,並接住剛剛傳出來的action (3) 為了方便整理,用渲染的方式,把輪播圖程式碼放到另外一個頁面

view/houses/show

> <section class="mx-36">
>  ...省略
> </section>
> 
> 
> <%# 點下去會出現所有圖片的輪播圖 %>
> <div class="absolute hidden" data-controller="carousel-pop-up"
>                              data-carousel-pop-up-target="page"
>                              data-action="popup_carousel@window->carousel-pop-up#showPop"
>                              >
>   <%= render "carousel", house: @house %>
> </div>

這個頁面就是輪播圖確定頁面了,這邊也幾個特別要提的

(1) 有新增一個叉叉的icon,上面有掛action,點下去的時候,要把hidden的css加回這個區塊 (2) 輪播圖區塊的垂直置中,要在swiper-wrapper的地方,加上items-center

_carousel.html.erb

> <div class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-95">
>   <div class="relative w-full p-20 rounded-lg">
>     <div class="">
>       <i class= "absolute text-white cursor-pointer right-[200px] top-[50px] text-4xl fa-solid fa-x" data-action="click->carousel-pop-up#close"></i>
>     </div>
> 
>     <div class="flex items-center justify-center">
>       <div class="w-1/3">
>         <div class="swiper-container" data-controller="carousel" 
>                                       data-carousel-options-value='{
>                                         "pagination": { "el": ".swiper-pagination", 
>                                                         "dynamicBullets": "true" },
>                                         "navigation": { "nextEl": ".swiper-button-next", 
>                                                         "prevEl": ".swiper-button-prev"},
>                                         "effect": "fade", 
>                                         "fadeEffect": { "crossFade": "true" },
>                                         "centeredSlidesBounds": false
>                                       }'
>                                       >
>           // 這邊很重要,如果今天想要讓圖片垂直置中,要在這邊加上items-center
>           <div class="flex items-center swiper-wrapper">
>         	<% house.images.each do |image| %>
>         	  <div class="swiper-slide">	    
>               <%= link_to image_tag(image), image.url, data: { lightbox: 'image-gallery' }, class: "object-contain w-full h-full", target: "_blank" %>
>         	  </div>
>         	<% end %>  
>           </div>
>           <!-- Add Pagination -->
>           <div class="swiper-pagination"></div>
>           <!-- Add Navigation -->
>           <div class="mr-5 swiper-button-next">
>             <div class="w-[60px] h-[60px] bg-white absolute opacity-90 rounded-full"></div>
>           </div>
>           <div class="ml-5 swiper-button-prev">
>             <div class="w-[60px] h-[60px] bg-white absolute opacity-90 rounded-full"></div>
>           </div>    
>         </div>
>       </div>
>     </div>
>   
>   </div>
> <div>

輪播圖區塊掛上的controller

可以這下面看到兩個action,一個是把輪播圖頁面的hidden刪掉,一個是把輪播圖頁面的hidden加回來

// carousel_pop_up_controller.js

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {

  static targets = [ 'page' ]

  connect() {}

  showPop() {
    this.pageTarget.classList.remove("hidden")
  }

  close() {
    this.pageTarget.classList.add("hidden") 
  }
}