LWR에서 LWC로 Swiper 사용하기

ahncheer·2022년 10월 4일
0

LWC & LWR

목록 보기
17/52

● Swiper Demo와 비슷하게 작성해서 사용

0. 실행화면 미리보기

1. Swiper 코드를 Static Resource에 저장하기

→ Cache Control을 public로 지정해서 저장.
→ 코드는 https://www.jsdelivr.com/package/npm/swiper 에서 다운 받은 것의 일부를 사용함.

▷ 사용한 파일 구성

2. LWR 세팅 확인


→ Lightning Locker가 OFF로 되어있는지 확인하기

3. 코드 작성

※ lwc025ExistingSwiper.html

<template>
    <div class="wrapper">
        <div class="swiper-wrap custom-s-wrap">
            <div class="swiper-container custom-swiper">
                <div class="swiper-wrapper">
                    <template for:each={dessertList} for:item="item" for:index="index">
                        <div key={item.value} class="swiper-slide">{item.label}</div>
                    </template>
                </div>
            </div>
            <div class="swiper-button-prev custom-s-prev"></div>
            <div class="swiper-button-next custom-s-next"></div>
        </div>
    </div>
</template>

※ lwc025ExistingSwiper.js

import { LightningElement, track, api} from 'lwc';
import { loadStyle, loadScript } from 'lightning/platformResourceLoader';
import swiperLib from '@salesforce/resourceUrl/swiperjs'; 

export default class Lwc025ExistingSwiper extends LightningElement {
    @track dessertSwiper; // swiper 저장용
    @track dessertList = 
            [{label : '빵', value : 'bread'}
            ,{label : '초콜릿', value : 'chocolate'}
            ,{label : '쿠키', value : 'cookie'}
            ,{label : '사탕', value : 'candy'}
            ,{label : '아이스크림', value : 'icecream'}
            ,{label : '케이크', value : 'cake'}
            ,{label : '주스', value : 'juice'}
            ,{label : '커피', value : 'coffee'}];

    connectedCallback() {
        // console.log(temp);
        Promise.all([
            loadStyle(this, swiperLib + '/swiper-bundle.min.css'),
            loadScript(this, swiperLib + '/swiper-bundle.min.js'),
        ]).then(() => {
            this.createSwiper();
        }).catch((error) => {
            console.log('errorMsg : ', error);
        });
    }
    /* swiper */
    createSwiper(){
        console.log('createSwiper');
        let nextBtn = this.template.querySelector('.custom-s-next');
        let prevBtn = this.template.querySelector('.custom-s-prev');
        // swiper 감싸는 부분을 .class이름이나 #id값으로 가져오지 말고 this.template을 사용해서 불러올 것 
        this.dessertSwiper = new Swiper(this.template.querySelector('.custom-swiper'), {
            spaceBetween: 30, //slide 사이 간격 
            observer:true, 
            observeParents: true, //위와 비슷함 
            slidesPerView: "auto",
            navigation: {
                nextEl: nextBtn,
                prevEl: prevBtn,
            },
        });
        console.log('this.dessertSwiper  : ', this.dessertSwiper );
    }

}

※ lwc025ExistingSwiper.css

.wrapper{
    width: 100%;
    max-width: 800px;
    margin: 10px auto;
    background-color: #cfcceb;
    padding: 20px 10px;
    border-radius: 5px;
    min-height: 200px;
    box-shadow: rgb(99 99 99 / 20%) 0px 2px 8px 0px;
}
.custom-s-wrap {
    position: relative;
    width: 100%;
}
.custom-s-wrap .custom-swiper {
    overflow: hidden;
    margin: 0 50px;
    width: calc(100% - 100px);
    overflow: hidden;
}
.swiper-slide {
    height: 60px;
    width: fit-content;
    white-space: nowrap;
    padding: 0 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #e4e2f5;
    border-radius: 10px;
}
.swiper-button-next:after, .swiper-button-prev:after{
    color: #333;
}

4. 실행 화면 확인

● LWC DOM을 사용하는 방법

(1번과 2번은 동일)

3. 코드 작성

※ lwc021HandleSwiper.html

<template>
    <div class="wrapper">
        <div class="swiper-wrap">
            <!-- swiper를 불러오는 부분-->
            <div lwc:dom="manual" class="dessertSwiperWrap"></div>
            <!-- swiper next, prev 버튼 (따로 빼서 class이름으로 지정)-->
            <div class="swiper-button-prev swiper-button-disabled" onclick={slidePrev}></div>
            <div class="swiper-button-next" onclick={slideNext}></div>
        </div>
    </div>
</template>

※ lwc021HandleSwiper.js

import { LightningElement, track, api} from 'lwc';
import { loadStyle, loadScript } from 'lightning/platformResourceLoader';
import swiperLib from '@salesforce/resourceUrl/swiperjs'; 
// LWR에서 사용하는 경우 Builder > Security & Privacy > Locker가 Off로 되어있는지 확인.

export default class TestSwiper extends LightningElement {
    @track dSwiper; // swiper 저장용
    @track slidesPerViewNum = 4;
    @track dessertList = [{label : '빵', value : 'bread'}
               ,{label : '초콜릿', value : 'chocolate'}
               ,{label : '쿠키', value : 'cookie'}
               ,{label : '사탕', value : 'candy'}
               ,{label : '아이스크림', value : 'icecream'}
               ,{label : '케이크', value : 'cake'}
               ,{label : '주스', value : 'juice'}
               ,{label : '커피', value : 'coffee'}];
    renderedCallback() {
        // console.log(temp);
        Promise.all([
            loadStyle(this, swiperLib + '/swiper-bundle.min.css'),
            loadScript(this, swiperLib + '/swiper-bundle.min.js'),
        ]).then(() => {
            // swiper의 Content(class, innerHtml)를 만드는 부분
            let containerEl = this.template.querySelector('div.dessertSwiperWrap');
            let swiperEl = document.createElement('div');
            let swiperWrapperEl = document.createElement('div');
            
            swiperEl.classList.add('swiper');
            swiperEl.classList.add('dessertSwiper');
            swiperWrapperEl.className = 'swiper-wrapper';
            
            this.dessertList.forEach((item,index) => {
                let slideEl = document.createElement('div');
                slideEl.className = 'swiper-slide';
                slideEl.innerHTML = '<div class="list-content" data-name="' +  item.value + '"><p> 이름 : '+ item.label +'</p></div>';
                swiperWrapperEl.appendChild(slideEl);
            });

            swiperEl.appendChild(swiperWrapperEl);
            containerEl.appendChild(swiperEl);
            
            // swiper 속성 저장
            this.dSwiper = new Swiper(".dessertSwiper", {
                spaceBetween: 20, //slide 사이 간격 
                slidesPerView : this.slidesPerViewNum, //한번에 보여주는 slide 개수 
                touchRatio: 0,//드래그 금지
                navigation: {
                    nextEl: ".swiper-button-next",
                    prevEl: ".swiper-button-prev",
                },
            });
            
            //onclick 이벤트 추가
            this.template.querySelectorAll('.list-content').forEach((el, index) =>{
                el.addEventListener('click', e => {
                    e.preventDefault();
                    this.clickDessert(index);
                }, false);
            });
        }).catch((error) => {
            console.log('errorMsg : ', error);
        });
    }
    // 다음 버튼(>)을 눌렀을 때 
    slideNext(){
        this.dSwiper.slideNext();
        this.slideBtnDisable(this.dSwiper.activeIndex, this.dessertList.length, this.slidesPerViewNum);
    }
    // 이전 버튼(>)을 눌렀을 때 
    slidePrev(){
        this.dSwiper.slidePrev();
        this.slideBtnDisable(this.dSwiper.activeIndex, this.dessertList.length, this.slidesPerViewNum);
    }

    // Slide가 끝에 갔을 때 버튼에 disable class추가 하는 코드
    // (현재 slide의 index, slide의 전체 갯수, 한번에 보여지는 slide개수)
    slideBtnDisable(idx, listLength, slideViewNum){
        //console.log('swiperIndex : ', idx);
        let nextBtn = this.template.querySelector('.swiper-button-next');
        let prevBtn = this.template.querySelector('.swiper-button-prev');
        if(idx == 0){
            //slide가 처음인 경우 Prev 버튼에 disabled class추가
            prevBtn.classList.add('swiper-button-disabled');
        }else if(idx == (listLength - slideViewNum)){
            //slide가 마지막인 경우 Next 버튼에 disabled class추가
            nextBtn.classList.add('swiper-button-disabled');
        }else{
            nextBtn.classList.remove('swiper-button-disabled');
            prevBtn.classList.remove('swiper-button-disabled');
        }
    }
    // swiper로 추가한 div의 onclick 이벤트
    clickDessert(index){
        console.log('index : ', index);
        let newList =  this.template.querySelectorAll('.list-content');
        let value = newList[index].dataset.name;
        console.log('clickDessert > value3 : ', value);
    }
}

※ lwc021HandleSwiper.css

.wrapper{
    width: 100%;
    max-width: 800px;
    margin: 10px auto;
    background-color: #f3f4f6;
    padding: 20px 10px;
    border-radius: 5px;
    min-height: 200px;
    box-shadow: rgb(99 99 99 / 20%) 0px 2px 8px 0px;
}

.swiper {
    width: 100%;
    height: 100%;
  }

.swiper-wrap{
    position: relative;
  }
.dessertSwiperWrap{
    display: grid;
    width: 100%;
    padding: 0 10%;
}
.list-content{
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.list-content p:nth-child(1){
    height: 100px;
    width: 100%;
    background-color: #dfe3e6;
    border: 2px solid #ffffff;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    color: #717171;
}
.list-content p:nth-child(2){
  width: 100%;
  text-align: center;
  color: #636363;
  font-weight: bold;
}

※ lwc020ChangeLang.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
      <target>lightning__AppPage</target>
      <target>lightning__RecordPage</target>
      <target>lightning__HomePage</target>
      <target>lightningCommunity__Page</target>
      <target>lightningCommunity__Default</target>
    </targets>
</LightningComponentBundle>
  • 따로 빼둔 swiper-button : swiper-button-prev와 swiper-button-next를 따로 빼서 사용했지만, drag로 swiper를 움직였을 경우 swiper의 끝에 닿았는지 따로 확인하지 않아 touchRatio: 0, 속성으로 드래그를 막아두었습니다.
  • swiper의 클릭한 값을 불러오는 부분 : innerHTML로 onclick 이벤트를 주기가 어려웠습니다. swiper 속성을 저장하는 코드 뒤에 this.template.querySelectorAll을 사용해 innerHTML에서 넣은 class와 맞는 리스트를 불러와, addEventListener click을 넣었습니다. value값은 불러오지 못하고 data-value로 불러오면 값을 가져올 수 있었습니다.

4. 실행 화면 확인

221021 dom 사용하지 않는 swiper 추가

profile
개인 공부 기록용.

1개의 댓글

comment-user-thumbnail
2023년 3월 21일

Site에서는 Swiper Demo처럼 작성해도 돌아갑니다.
일반 페이지 (Edit Page로 컴포넌트를 넣는 영역)은 Dom을 사용해야 하는 것으로 기억합니다.

답글 달기