Vue3 체크박스
1) 배운 내용
<template>
<div class="row items-center wrapper">
<div class="row signinBox">
<form action="#" id="form__wrap">
<div class="signinBox__form">
<div class="row items-center signinBox__checkAll" id="checkAll">
<input type="checkbox" class="check0" id="check0" @click="changeColor(); checkBox();">
<label for="check0"></label>
<span class="q-mr-sm text-bold" style="font-size: 18px;">전체 동의</span>
<span class="checkbox__label" style="text-decoration: none; font-size: 1.3rem;">(선택항목 포함)</span>
</div>
<div v-for="list in lists" :key="list" class="signinBox__wrapper" @click="openDrawer(list);">
<div class="row items-center signinBox__check" @click="checkBoxCheck()">
<input type="checkbox" :id="'input' + list.id" name="agree">
<label :for="'input' + list.id"></label>
<span class="checkbox__label" style="font-size: 15px;">{{ list.label }}</span>
<div :id="'img' + list.id" class="img__arrowUp"></div>
</div>
<div :id="'check' + list.id" class="row item__content">
{{ list.content }}
</div>
</div>
</div>
<div class="row justify-center signinBox__buttonWrapper">
<button type="submit" class="item__button" disabled><a style="color: white;"
href="/#/membership2">다음</a></button>
</div>
</form>
</div>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
return {
right: ref(false)
}
},
data() {
return {
lists: [
{ id: '1', label: '서비스 이용약관 (필수)', content: '1.개인정보처리방침 회원 가입 의사의 확인, 연령 확인 및 법정대리인 동의 진행, 이용자 및 법정대리인의 본인 확인, 이용자 식 별, 회원탈퇴 의사의 확인 등 회원관리를 위하여 개인정보를 이용합니다. 콘텐츠 등 기존 서비스 제공(광고 포함)에 더하여, 인구통계학적 분석, 서비스 방문 및 이용기록의 분석, 개인정보 및 관심에 기반한 이용자 간 관계의 형성, 지인 및 관심사 등에 기반한 맞춤형 서비스 제공 등 신규 서비스 요소의 발굴 및 기존 서비 스 개선 등을 위하여 개인정보를 이용합니다. 법령 및 회사 이용약관을 위반하는 회원에 대한 이용 제한 조치, 부정 이용 행위를 포함하여 서비스의 원활 한 운영에 지장을 주는 행위에 대한 방지 및 제재, 계정도용 및 부정거래 방지, 약관 개정 등의 고지사항 전 달, 분쟁조정' },
{ id: '2', label: '개인정보 수집 및 이용 동의 (필수)', content: '1.개인정보처리방침 회원 가입 의사의 확인, 연령 확인 및 법정대리인 동의 진행, 이용자 및 법정대리인의 본인 확인, 이용자 식 별, 회원탈퇴 의사의 확인 등 회원관리를 위하여 개인정보를 이용합니다. 콘텐츠 등 기존 서비스 제공(광고 포함)에 더하여, 인구통계학적 분석, 서비스 방문 및 이용기록의 분석, 개인정보 및 관심에 기반한 이용자 간 관계의 형성, 지인 및 관심사 등에 기반한 맞춤형 서비스 제공 등 신규 서비스 요소의 발굴 및 기존 서비 스 개선 등을 위하여 개인정보를 이용합니다. 법령 및 회사 이용약관을 위반하는 회원에 대한 이용 제한 조치, 부정 이용 행위를 포함하여 서비스의 원활 한 운영에 지장을 주는 행위에 대한 방지 및 제재, 계정도용 및 부정거래 방지, 약관 개정 등의 고지사항 전 달, 분쟁조정' },
{ id: '3', label: '앱 알림, 마케팅 정보 수신 동의 (선택)', content: '1.개인정보처리방침 회원 가입 의사의 확인, 연령 확인 및 법정대리인 동의 진행, 이용자 및 법정대리인의 본인 확인, 이용자 식 별, 회원탈퇴 의사의 확인 등 회원관리를 위하여 개인정보를 이용합니다. 콘텐츠 등 기존 서비스 제공(광고 포함)에 더하여, 인구통계학적 분석, 서비스 방문 및 이용기록의 분석, 개인정보 및 관심에 기반한 이용자 간 관계의 형성, 지인 및 관심사 등에 기반한 맞춤형 서비스 제공 등 신규 서비스 요소의 발굴 및 기존 서비 스 개선 등을 위하여 개인정보를 이용합니다. 법령 및 회사 이용약관을 위반하는 회원에 대한 이용 제한 조치, 부정 이용 행위를 포함하여 서비스의 원활 한 운영에 지장을 주는 행위에 대한 방지 및 제재, 계정도용 및 부정거래 방지, 약관 개정 등의 고지사항 전 달, 분쟁조정' },
],
checkOthers: [],
statusAll: {},
checkToggles: [],
statusCheck: {}
}
},
methods: {
// 공지사항 세부
openDrawer(list) {
const x = document.getElementById('check' + list.id);
const y = x.classList;
const a = document.getElementById('img' + list.id);
const b = a.classList;
if (y.contains('item__content')) {
y.replace('item__content', 'active');
b.replace('img__arrowUp', 'img__arrowDown');
} else {
y.replace('active', 'item__content');
b.replace('img__arrowDown', 'img__arrowUp');
}
},
// 전체 동의
checkBox() {
const agreeChkAll = document.querySelector('input[id=check0]');
const agreeChk = document.querySelectorAll('input[name=agree]');
const submitButton = document.querySelector('button');
const checkOthers = []
const statusAll = agreeChkAll.checked
agreeChkAll.addEventListener('change', (e) => {
for (let i = 0; i < agreeChk.length; i++) {
agreeChk[i].checked = e.target.checked;
checkOthers.push({
value: e.target.checked
})
}
});
// 전체 체크 시 다음버튼 활성화, 해제 시 다음버튼 비활성화
submitButton.disabled = !submitButton.disabled;
},
// 전체동의 체크 후 필수 체크박스 해제 시 전체동의도 해제
checkBoxCheck() {
const agreeCheck = document.querySelectorAll('.signinBox__check input');
console.log('배열로 받기', agreeCheck)
console.log(agreeCheck[0].checked)
console.log(agreeCheck[1].checked)
console.log(agreeCheck[2].checked)
const checkToggles = [];
for (let i = 0; i < agreeCheck.length; i++) {
checkToggles.push(agreeCheck[i])
}
console.log(checkToggles)
const x = Number(checkToggles[0].checked)
const y = Number(checkToggles[1].checked)
console.log(x, y)
checkToggles.splice(0, 2, x, y)
const sum = checkToggles.reduce((acc, cur, list) => {
if (acc + cur === 2) {
document.getElementById('check0').checked = true;
document.querySelector('button').disabled = false;
} else {
document.getElementById('check0').checked = false;
document.querySelector('button').disabled = true;
}
}, 0)
console.log(sum)
// 필수 해제 시 전체동의도 해제
if (checkToggles[0] && checkToggles[1]) {
document.getElementById('check0').checked = true;
document.querySelector('button').disabled = false;
} else {
document.getElementById('check0').checked = false;
document.querySelector('button').disabled = true;
}
},
changeColor() {
const change = document.getElementById('checkAll')
const color = change.classList;
if (color.contains('signinBox__checkAll')) {
color.replace('signinBox__checkAll', 'check__active');
} else {
color.replace('check__active', 'signinBox__checkAll');
}
}
},
})
</script>
<style lang="scss" scoped>
@import "src/css/app.scss";
* {
overflow-x: hidden;
}
.wrapper {
min-width: 36rem;
min-height: 100vh;
margin: 0 auto 0;
}
.signinBox {
width: 69.3rem;
margin: 0 auto;
}
.signinBox__label {
font-size: 4rem;
color: #980ED8;
line-height: 5rem;
}
.signinBox__form {
width: 70rem;
margin: 0 auto 0;
.signinBox__formTitle {
margin: 0 0 4.4rem;
font-size: 3.5rem;
line-height: 4.2rem;
font-weight: $font-weight-semi-bold;
text-align: center;
}
}
.signinBox__logo {
margin-bottom: 20px;
}
.signinBox__label {
margin-bottom: 70px;
}
.signinBox__checkAll {
width: 69.3rem;
height: 7rem;
padding: 0;
background-color: #F4F4F4;
border-radius: 5px;
margin-bottom: 19px;
}
.check__active {
width: 69.3rem;
height: 7rem;
padding: 0;
background-color: #F4E7FB;
border-radius: 5px;
margin-bottom: 19px;
}
input[type="checkbox"] {
display: none;
}
input[type="checkbox"]+label {
display: inline-block;
width: 30px;
height: 30px;
overflow-y: hidden;
border: 1px solid #A8ABAF;
border-radius: 3px;
position: relative;
margin: 0 11px 0 24px;
}
input[id="check0"]:checked+label::after {
content: '✔︎';
font-size: 25px;
color: white;
background-color: #980ED8;
width: 30px;
height: 30px;
text-align: center;
position: absolute;
left: 0;
top: 0;
}
input[id="input1"]:checked+label::after {
content: '✔︎';
font-size: 25px;
color: white;
background-color: #980ED8;
width: 30px;
height: 30px;
text-align: center;
position: absolute;
left: 0;
top: 0;
}
input[id="input2"]:checked+label::after {
content: '✔︎';
font-size: 25px;
color: white;
background-color: #980ED8;
width: 30px;
height: 30px;
text-align: center;
position: absolute;
left: 0;
top: 0;
}
input[id="input3"]:checked+label::after {
content: '✔︎';
font-size: 25px;
color: white;
background-color: #980ED8;
width: 30px;
height: 30px;
text-align: center;
position: absolute;
left: 0;
top: 0;
}
.checkbox__label {
color: #666C70;
text-decoration: underline;
}
.signinBox__check {
width: 69.3rem;
height: 7rem;
padding: 0;
border: 1px solid rgba(43.9%, 43.9%, 43.9%, 0.37);
border-radius: 5px;
margin-bottom: 6px;
position: relative;
}
.img__arrowUp {
width: 30px;
height: 30px;
position: absolute;
background-image: url("../assets/images/img_arrow_up.svg");
background-size: contain;
background-repeat: no-repeat;
right: 18px;
}
.img__arrowDown {
width: 30px;
height: 30px;
position: absolute;
background-image: url("../assets/images/img_arrow_down.svg");
background-size: contain;
background-repeat: no-repeat;
right: 18px;
}
.item__content {
width: 100%;
display: none;
background-color: #F9F9F9;
}
.active {
width: 100%;
display: block;
background-color: #F9F9F9;
}
.signinBox__buttonWrapper {
width: 100%;
margin-top: 5rem;
}
.item__button {
width: 8.9rem;
height: 5.2rem;
border-radius: 4px;
font-size: 1.8rem;
background-color: #373737;
color: white;
text-decoration: none;
}
</style>
별거 아닌데 이틀 반을 태웠다.
<구현된 부분>
1) 체크박스 전체 클릭 시 나머지 체크박스 전체 체크됨.(반대로도 가능)
2) 필수 체크박스 2개 체크 시, 체크박스 전체 체크됨.
3) 전체 체크박스 클릭된 상태에서 필수 체크박스 2개 중 1개 해제했을 때 전체 체크박스 해제됨.
4) 선택 체크박스는 제외.
5) 위 조건대로 '다음' 버튼 활성화 & 비활성화 구현.
2) Trouble Shooting
-> document.querySelectorAll로 가져올 경우, 배열이 아닌 NodeList를 가져온다.(배열을 새로 생성한 후 작업해야함)
-> 조건식 if, elseif 보다는 혹여 향후에 약관이 추가될 가능성을 생각해서 reduce 메서드를 활용했다.
-> 바닐라 자바스크립트로 돔을 조작해서 해보려 했는데 Vue에서는 돔을 직접조작하는 걸 지양하라고 함.
❇︎리팩토링 필요!
'코딩 > Javascript' 카테고리의 다른 글
TIL(23.05.04) - jQuery 활용한 checkbox 로직구현 (0) | 2023.05.04 |
---|---|
[TIL] 23.01.10 - 자바스크립트에서 ?? 활용 (0) | 2023.01.10 |
[스터디 4일차] 22.12.21 - ES6 클래스 이해하기 (0) | 2022.12.19 |
[스터디] 3일차(2022.12.17) - 얕은 복사, 깊은 복사 (0) | 2022.12.19 |
[스터디 2일차] - 일급함수, 고차함수 특징 알아보기 (0) | 2022.12.10 |