- Published on
- ·10 min read
하나의 데이터로 여러개의 select box 동시 제어(javascript)
설명할 내용
화면 비율(Aspect Ratio) 비교 서비스의 경우
-- 비율 --
, -- 해상도 --
, -- 사용처 --
선택박스는 동일한 객체(데이터)를 사용합니다.
위 선택 박스 중 한 곳에서 비율을 선택하면 다른 선택 박스의 비율도 자동으로 disable 하도록 처리했습니다.
예를 들어, -- 사용처 --
의 Instagram - 1:1
을 선택한 경우
-- 비율 --
의 1:1
과 -- 해상도 --
의 1080x1080 - 1:1
이 함께 disable 처리됩니다.
아래 GIF 이미지를 참고하세요.
들어가기 전 참고
설명을 위해 약간의 편집이 들어간 소스 공유입니다.
실제 소스에서 함수로 쪼개진 부분을 합치기도 하고, 해당 기능에 필요 없는 소스는 생략하기도 했습니다. 설명을 위해 주석과 중복으로 코드가 들어간 부분도 있다는 점 참고하시길 바랍니다.
구현
1. 각 선택박스에 사용할 데이터 정의
비율 정보와, 사용처 목록(usages), 해상도 목록(resolutions)을 각각의 key로 정의합니다.
코드는 아래와 같습니다.
const AspectRatioInfo = function () {
const originalRatioData = [
{
key: '1', // Key값으로 사용, select > option 의 value로 사용
width: 1, // 비율 계산용
height: 1, // 비율 계산용
text: '1:1', // select box 표시용
range: [1], // 직접 비율 계산시 해당 범위로 찾을 수 있도록 배열로
usages: ['Instagram'], // 사용처 목록(배열)
resolutions: ['1080x1080'], // 해상도 목록(배열)
},
{
key: '1.33',
width: 4,
height: 3,
text: '4:3 (1.33:1)',
range: [1.33],
usages: ['iPad 5/6/7/8/9', 'iPad Mini 2/3/4/5', 'iPad Air 1/2/3', 'iPad Pro 12.9'],
resolutions: ['800x600', '1024x768', '1600x1200', '2048x1536'],
},
{
key: '1.77',
width: 16,
height: 9,
text: '16:9 (1.77:1)',
range: [1.77, 1.78],
usages: ['iPhone 5/6/7/8', 'iMac', 'Galaxy Note 5/9', 'YouTube'],
resolutions: [
'640x360',
'1280x720',
'1600x900',
'1920x1080',
'2560x1440',
'3200x1800',
'3840x2160',
'5120x2880',
'7680x4320',
],
},
// ... 생략 ...
]
// ... 데이터 필터링 함수 내용으로 아래에서 설명하므로 생략 ...
}
2. 각 선택박스에 보여질 데이터 필터링 함수
const AspectRatioInfo = function () {
// ... originalRatioData 선언 내용으로 위에서 설명됨. 생략 ...
// -- 비율 -- 선택박스용 데이터 정렬
const getListOfWidthHeight = function () {
const listOfWidthHeight = originalRatioData
.sort(function (a, b) {
return a.width - b.width
})
.map(function (ratio) {
return {
key: ratio.key,
width: ratio.width,
height: ratio.height,
text: ratio.text,
ratio: ratio.range[0],
}
})
return listOfWidthHeight
}
// -- 해상도 -- 선택박스용 데이터 필터링 및 정렬
const getListOfResolution = function () {
const resolutionArray = []
// originalRatioData > resolutions 배열 이용하기
originalRatioData.forEach(function (ratio) {
ratio.resolutions.forEach(function (resolution) {
resolutionArray.push({
key: ratio.key,
resolution: resolution,
text: ratio.text,
})
})
})
return resolutionArray.sort(function (a, b) {
const [a1, a2] = a.resolution.split('x').map(Number)
const [b1, b2] = b.resolution.split('x').map(Number)
return a1 - b1 || a2 - b2
})
}
// -- 사용처 -- 선택박스용 데이터 필터링 및 정렬
const getListOfUsage = function () {
const usageArray = []
// originalRatioData > usages 배열 이용하기
originalRatioData.forEach(function (ratio) {
ratio.usages.forEach(function (usage) {
usageArray.push({
key: ratio.key,
usage: usage,
text: ratio.text,
})
})
})
return usageArray.sort(function (a, b) {
return a.usage.localeCompare(b.usage)
})
}
}
3. 선택 박스 생성
<select id="selRatio" class="input-select-short">
<option value="">-- 비율 --</option>
</select>
<select id="selResolution" class="input-select-short">
<option value="">-- 해상도 --</option>
</select>
<select id="selUsage" class="input-select-short">
<option value="">-- 사용처 --</option>
</select>
const aspectRatioInfo = new AspectRatioInfo()
window.addEventListener('load', function () {
setSelectBox()
})
function setSelectBox() {
// 선택박스 -- 비율 --
createSelectBox(document.getElementById('selRatio'), aspectRatioInfo.getListOfWidthHeight())
// 선택박스 -- 해상도 --
createSelectBox(document.getElementById('selResolution'), aspectRatioInfo.getListOfResolution())
// 선택박스 -- 사용처 --
createSelectBox(document.getElementById('selUsage'), aspectRatioInfo.getListOfUsage())
}
// 선택박스 생성
function createSelectBox(element, list) {
list.forEach(function (item) {
const optionElement = document.createElement('option')
optionElement.value = item.key
// 각 선택박스에 따라 보여지는 텍스트 내용이 달라져야 하는 부분
if (element.id === 'selResolution') {
optionElement.innerHTML = `${item.resolution} - ${item.text}`
} else if (element.id === 'selUsage') {
optionElement.innerHTML = `${item.usage} - ${item.text}`
} else {
optionElement.innerHTML = item.text
}
element.appendChild(optionElement)
})
}
4. 선택박스에서 선택 시 모든 선택박스에서 해당 비율 disable 처리
const AspectRatioInfo = function () {
const getRatioInfoByKey = function (key) {
const ratioInfo = originalRatioData.find(function (ratio) {
return ratio.key === key
})
return ratioInfo
}
}
// ---------------------------------
const aspectRatioInfo = new AspectRatioInfo()
let selectedAspectRatiosState = [] // 선택된 aspect ratio
// 선택박스 선택 시 이벤트 처리
window.addEventListener('load', function () {
document.addEventListener('change', function (event) {
if (event.target.tagName.toLowerCase() === 'select') {
const selectKey = event.target.value
// 선택된 key의 데이터를 가져와 selectedAspectRatiosState에 추가
const info = aspectRatioInfo.getRatioInfoByKey(selectKey)
info && addSelectedAspectRatiosState(info)
event.target.value = ''
}
})
})
// 이미 선택된 비율이 있을 경우 return 아닐 경우 추가
function addSelectedAspectRatiosState(info) {
if (selectedAspectRatiosState.find((item) => item.key === info.key)) {
return
}
setSelectedAspectRatiosState([...selectedAspectRatiosState, info])
}
// 선택된 비율 추가하고, Disable 처리 함수를 호출
function setSelectedAspectRatiosState(newState) {
selectedAspectRatiosState = newState
selectedKeyDisabled()
}
// 선택된 비율들 disabled 처리하기
function selectedKeyDisabled() {
const optionElementList = document.querySelectorAll('option')
optionElementList.forEach(function (optionElement) {
if (
selectedAspectRatiosState.find(function (selectedKey) {
return selectedKey.key === optionElement.value
})
) {
optionElement.disabled = true
} else {
optionElement.disabled = false
}
})
}
JSFiddle에서 확인하기
태그와 연관된 글
2023. 12. 17.
데이터 양이 많아지면서 발생한 React Native 앱 성능 문제 개선하기2023. 11. 21.
애드몹(AdMob) GDPR 적용 - React Native(안드로이드)2023. 11. 20.
애드몹(AdMob) GDPR 적용 - 안드로이드2023. 11. 16.
진행률을 표시할 Progress Bar(Circle) 만들기 - React Native2023. 07. 25.
Color Picker(ambilwarna) 라이브러리 사용하여 색상 변경(안드로이드)