→ Cache Control을 public로 지정해서 저장.
→ 코드는 https://www.jsdelivr.com/package/npm/swiper 에서 다운 받은 것의 일부를 사용함.
▷ 사용한 파일 구성
→ Lightning Locker가 OFF로 되어있는지 확인하기
※ 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;
}
(1번과 2번은 동일)
※ 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로 불러오면 값을 가져올 수 있었습니다.
221021 dom 사용하지 않는 swiper 추가
Site에서는 Swiper Demo처럼 작성해도 돌아갑니다.
일반 페이지 (Edit Page로 컴포넌트를 넣는 영역)은 Dom을 사용해야 하는 것으로 기억합니다.