偵聽select下拉選單有無被打開(原生js)
偵聽select下拉選單有無被打開(原生js)
在做日期選擇器練習時遇到一些問題,下拉選單出現時,需要顯示出”選擇中”的字樣,由於select在點擊外面時,下拉選單會被收起,滑動滾輪時也會被收起,以下先附上我codepen連結datePicker,再來做解釋如何解決。
需要步驟
- 未選擇日期時,或日期尚未選擇完整時show出”請選擇日期”
- 當按下select時,也就是下拉選單出現時,要顯示出"選擇中"的字樣
- 日期選擇完整後出現日期與日曆
看起來好像不難對不對,但其實有超多bug要修,先上HTML及jS部份,再一一說明
<div class="out">
<select name="year" id="yearSelect">
<option value="" class="hide">-- Year --</option>
</select>
<select name="month" id="monthSelect">
<option value="" class="hide">-- Month --</option>
</select>
<select name="day" id="daySelect">
<option value="" class="hide">-- Day --</option>
</select>
<p id="dateChoose" class="dateChoose"></p>
</div>
<div class="out" id="calendar"></div>
var temp = true;
var firstDay = -1;
var days = 0;
var rows = 0;
//是否選擇中狀態
function select() {
temp = !temp;
!temp ? dateChoose.innerText = "選擇中..." : chose();
};
//換字
function chose() {
!yearSelect.value || !monthSelect.value || !daySelect.value ?
dateChoose.innerText = "請選擇日期" :
dateChoose.innerText = `${yearSelect.value}年${monthSelect.value}月${daySelect.value}日`;
};
//塞年月日選項
function createOption(start, end, select) {
for (let i = start; i <= end; i++) {
let options = document.createElement('option');
options.value = i;
options.text = i;
select.add(options);
}
};
//判斷空白處
function notId(e, text) {
let id = e.target.id;
if (id != yearSelect.id && id != monthSelect.id && id != daySelect.id) {
temp = true;
chose();
console.log(text);
}
};
//取得天數
function getDays(select) {
select.addEventListener("change", function () {
if (yearSelect.value && monthSelect.value) {
days = new Date(yearSelect.value, monthSelect.value, 0).getDate();
daySelect.options.length = 1;
createOption(1, days, daySelect);
firstDay = new Date(yearSelect.value, monthSelect.value - 1, 1).getDay();
rows = Math.ceil((firstDay + days) / 7);
// console.log(firstDay);
}
});
};
//生成日曆
function createCalendar(table,newCalendar) {
let count = 0;
const week = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
for (let i = 0; i < rows + 1; i++) {
let trNode = table.insertRow();
if (i === 0) {
for (const k of week) {
let th = document.createElement('th');
th.innerText = k;
trNode.appendChild(th);
}
} else {
for (let y = 0; y < 7; y++) {
let tdNode = trNode.insertCell();
count++;
count < firstDay + 1 || count > days + firstDay?
tdNode.innerHTML = '':
tdNode.innerHTML = count - firstDay;
if (tdNode.innerHTML === daySelect.value) {
tdNode.classList.add('tdActive');
}
}
}
}
newCalendar.appendChild(table);
};
document.addEventListener("DOMContentLoaded", function () {
const yearSelect = document.getElementById('yearSelect');
const monthSelect = document.getElementById('monthSelect');
const daySelect = document.getElementById('daySelect');
const dateChoose = document.getElementById('dateChoose');
//select部分
dateChoose.innerText = "請選擇日期";
createOption(2010, 2025, yearSelect);
createOption(1, 12, monthSelect);
yearSelect.addEventListener("click", select);
document.addEventListener("click", function (e) {
notId(e, "外面")
});
window.addEventListener("mousewheel", function (e) {
notId(e, "滾輪")
});
getDays(yearSelect);
getDays(monthSelect);
monthSelect.addEventListener("click", function () {
!yearSelect.value ?
alert("請先選擇年份") :
select();
});
daySelect.addEventListener("click", function () {
!yearSelect.value ?
alert("請先選擇年份") :
!monthSelect.value ?
alert("請先選擇月份") :
select();
});
//日曆部份
daySelect.addEventListener('change', function () {
const calendar = document.getElementById("calendar");
const tableNode = document.createElement('table');
tableNode.id = 'tableId';
let tableElement = document.getElementsByTagName('table').length;
if (tableElement > 0) {
document.getElementById('tableId').remove();
createCalendar(tableNode,calendar);
} else {
createCalendar(tableNode,calendar);
}
});
});
解決無選擇日期直接點擊空白處,選擇中狀態卻無消失
剛剛提到只有在下拉選單出現時,才顯示出"選擇中"的字樣,但點旁邊空白處時,也就是不在select裡,狀態就會一直卡在”選擇中”,這個部份可以參考我上一篇的作法(jquery點擊空白處隱藏元素),這裡一樣用類似的作法,你可以想像成有無選擇狀態,跟toggle有點像。
先給一個存放狀態的變數,在給各個select宣告變數
var temp = true; const yearSelect = document.getElementById('yearSelect'); const monthSelect = document.getElementById('monthSelect'); const daySelect = document.getElementById('daySelect'); const dateChoose = document.getElementById('dateChoose');
給預設字
dateChoose.innerText = "請選擇日期";
點擊select呼叫方法
這邊是把temp狀態從true改成false,若為false時,則字就變成選擇中,若為true時,則字就變成選擇的日期yearSelect.addEventListener("click", select); //是否選擇中狀態 function select() { temp = !temp; !temp ? dateChoose.innerText = "選擇中..." : chose(); }; //換字 function chose() { !yearSelect.value || !monthSelect.value || !daySelect.value ? dateChoose.innerText = "請選擇日期" : dateChoose.innerText = `${yearSelect.value}年${monthSelect.value}月${daySelect.value}日`; };
重點來了!!
當document被點擊時,判斷是否在select外面
這邊可以console出來看看有沒有點在外面document.addEventListener("click", function (e) { notId(e, "外面") }); //判斷空白處 function notId(e, text) { let id = e.target.id; if (id != yearSelect.id && id != monthSelect.id && id != daySelect.id) { temp = true; chose(); console.log(text); } };
解決無選擇日期直接滾動滾輪,選擇中狀態卻無消失
判斷是否在select外面使用滾輪事件
這裡的滾輪不是指視窗中的捲軸,所以用scroll是沒有用的window.addEventListener("mousewheel", function (e) { notId(e, "滾輪") });
看到這裡你會發現怎麼那麼麻煩阿!而且在select上面直接滾動滑鼠滾輪(不是下拉選單歐),一樣會壞掉,是因為我們剛剛function已經排除掉select部分,所以當然選單收起來一樣會出現選擇中,那為什麼不直接用<div>及<ul>就好?
對欸!突破盲腸了!各位!
而且select還不能客製樣式!不就打臉自己嗎?好啦~ 這個故事告訴我們要多多善用div哈哈哈..XD(打)
參考資料:
我的codepen連結datePicker
本部落格所有文章除特别聲明外,均采用 CC BY-SA 4.0 協議 ,轉載請註明出處!