基于Vue3手写选课组件(含时区切换,拖拽选择)
环境说明
基于vue3+vite 无关联别的ui框架,组件化
初次使用vue3,技术菜,大佬勿喷
main.ts
"moment": "^2.29.4","moment-timezone": "^0.5.41",
import moment from 'moment';
import momentTz from "moment-timezone";
import 'moment/dist/locale/zh-cn'
moment.locale('zh-cn')app.config.globalProperties.$moment = moment
// or
window.moment = moment
效果图
代码
<script setup lang="ts">
import { ref, onMounted, onBeforeMount, defineComponent } from "vue";withDefaults(defineProps<{msg: String;show: Boolean;}>(),{msg: () => "测试",show: () => true,}
);const weekData:any = ref([{time: "2023-03-06",mmDD: "03/06",week: "周一",},{time: "2023-03-07",mmDD: "03/07",week: "周二",},{time: "2023-03-08",mmDD: "03/08",week: "周三",},{time: "2023-03-09",mmDD: "03/09",week: "周四",},{time: "2023-03-10",mmDD: "03/10",week: "周五",},{time: "2023-03-11",mmDD: "03/11",week: "周六",},{time: "2023-03-12",mmDD: "03/12",week: "周日",},
]);const selectTimes = ref([]);
const drag = ref(false);
const utc = ref("");
const oldUtc = ref("");
const moment = window.momentonBeforeMount(() => {// request databuildWeekTimeInitData();oldUtc.value = Intl.DateTimeFormat().resolvedOptions().timeZone;utc.value = Intl.DateTimeFormat().resolvedOptions().timeZone;
});onMounted(() => {// load charts// 构造数据
});const buildWeekTimeInitData = () => {const start = 0;const end = 48;var times:any = [];var pref = 0;var aft = 0;for (var i = start; i < end; i++) {var pe = pref + "";var be = aft + "";if (pe.length == 1) {pe = "0" + pe;}if (be.length == 1) {be = "0" + be;}var temp = { value: pe + ":" + be };// 模拟不可选// if(i > 30){// temp.notSelect = true// }times.push(temp);aft = aft + 30;if (aft == 60) {pref = pref + 1;aft = 0;}}console.log(times);var index = 0;weekData.value.map((val:any) => {weekData.value[index]["times"] = JSON.parse(JSON.stringify(times));index++;});selectUTC(null);
};const selectTime = async (week: any, time: any, onlyIn: Boolean) => {// console.log(week,time)var key:any = week.time + "_" + time.value;if (selectTimes.value.includes(key)) {selectTimes.value.splice(selectTimes.value.indexOf(key), 1);} else {selectTimes.value.push(key);}
};const mousedownHandler = async (w:any, t:any) => {drag.value = true;setTimeout(() => {mousemoveHandler(w, t);}, 10);
};const mouseClickHandler = async (w:any, t:any) => {await selectTime(w, t,false);
};const mouseupHandler = async () => {drag.value = false;
};const mousemoveHandler = async (w:any, t:any) => {await setTimeout(async () => {if (drag.value) {if (!t.notSelect) {await selectTime(w, t, true);} else {// 无法选中}}}, 50);
};const selectUTC = (v:any) => {if (!v) {v = Intl.DateTimeFormat().resolvedOptions().timeZone;} else {v = v.target.value || Intl.DateTimeFormat().resolvedOptions().timeZone;}utc.value = v;console.log("切换时区", utc.value);var selectedTimes = JSON.parse(JSON.stringify(selectTimes.value));// console.log(selectedTimes)var preSelectedTimes:any = [];selectedTimes.map((val:any) => {preSelectedTimes.push(val.replace("_", " ") + ":00");});// console.log(preSelectedTimes)var afterSelectedTimes:any = [];preSelectedTimes.map((vt:any) => {// var vdate = new Date(v+ ' '+moment().format('z'))var utcUnit = utc.value;console.log("转时区:", utcUnit);console.log(vt);var newYork = convatTime(vt, oldUtc.value, utc.value);var spi = newYork.split(" ");var pft = spi[0] + "_" + spi[1].substring(0, 5);afterSelectedTimes.push(pft);// console.log(vt,newYork)});console.log("最终:", afterSelectedTimes);selectTimes.value = JSON.parse(JSON.stringify(afterSelectedTimes));oldUtc.value = JSON.parse(JSON.stringify(utc.value));
};const convatTime = (vt:any, fromZone:any, toZone:any) => {console.log("将" + vt, "原格式" + fromZone, "最终格式" + toZone);var zoreDate = new Date(vt + " " + moment().tz(fromZone).format("Z"));var newYork = moment.tz(zoreDate, toZone).format("YYYY-MM-DD HH:mm:ss");return newYork;
};
const convatTimeStrap = (vt:any, fromZone:any, toZone:any) => {console.log("将" + vt, "原格式" + fromZone, "最终格式" + toZone);var zoreDate = new Date(vt + " " + moment().tz(fromZone).format("Z"));var newYork = moment.tz(zoreDate, toZone)._d.getTime();return newYork;
};const submit = () => {var utcData = JSON.parse(JSON.stringify(utc.value))var wtimes:any = []var selectedTimes = JSON.parse(JSON.stringify(selectTimes.value));// console.log(selectedTimes)var preSelectedTimes:any = [];selectedTimes.map((val:any) => {preSelectedTimes.push(val.replace("_", " ") + ":00");});preSelectedTimes.map((val:any)=>{var utcV = convatTimeStrap(val,utcData,'UTC')wtimes.push(utcV)})console.log(preSelectedTimes,utcData)console.log('结果:',wtimes)}const changeWeek = (tag:any) => {if(tag == '>'){console.log('向'+tag+'移动')}else if(tag == '<'){console.log('向'+tag+'移动')}
}</script><template><div class="fc-calendar"><div>日历</div><div>{{ selectTimes }}</div><div><select v-model="utc" @change="selectUTC"><option value="Asia/Shanghai">Asia/Shanghai</option><option value="America/New_York">America/New_York</option></select><button @click="submit">提交</button></div><!-- 左右选择 --><div class="fc-calendar-week"><div class="fc-calendar-arror" @click="changeWeek('<')">{{ "<" }}</div><divclass="fc-calendar-week_item"v-for="(week, index) in weekData":key="index"><div>{{ week.week }}</div><div>{{ week.mmDD }}</div></div><div class="fc-calendar-arror" @click="changeWeek('>')">{{ ">" }}</div></div><div class="fc-calendar-tip"><span> * 点击或拖拽即可选择</span></div><divclass="fc-calendar-time"@mouseleave="drag = false"@mouseup="mouseupHandler()"><divclass="fc-calendar-time-col"v-for="(week, index) in weekData":key="index"><divv-for="(t , idx) in week.times":key="idx"class="fc-calendar-time-row"@click="mouseClickHandler(week, t)"@mousedown="mousedownHandler(week, t)"@mouseenter="mousemoveHandler(week, t)"><div v-if="t.notSelect" :class="'not-select'">{{ t.value }}</div><divv-else:class="selectTimes.includes(week.time + '_' + t.value)? 'select': 'unselect'"@click="selectTime(week, t,false)">{{ t.value }}</div></div></div></div></div>
</template><style scoped>
.fc-calendar {width: 62%;border: 1px solid;padding: 4px;
}.fc-calendar-week {display: flex;justify-content: space-around;text-align: center;padding-bottom: 1rem;
}.fc-calendar-week_item {width: 3rem;border-radius: 7px;cursor: pointer;
}.fc-calendar-tip {text-align: center;
}.fc-calendar-time-col {display: inline-flex;justify-content: space-around;align-items: center;flex-direction: column;align-content: space-between;width: 14%;
}.fc-calendar-time-row {display: block;border: 1px solid #939393;line-height: 2.4rem;margin-bottom: 10px;width: 88%;text-align: center;border-radius: 1px;margin: 5px 9px;cursor: pointer;user-select: none;
}
.fc-calendar-time-row-select {display: block;border: 1px solid #939393;line-height: 2.4rem;margin-bottom: 10px;width: 88%;text-align: center;border-radius: 5px;margin: 5px 9px;cursor: pointer;background-color: #0b8049;color: #fff;user-select: none;
}.fc-calendar-time-row:hover {background-color: #0b8049;color: #fff;
}
.select {background-color: #0b8049;color: #fff;
}.unselect {background-color: #fff;color: #000;
}.not-select {background-color: #939393;color: #fff;cursor: not-allowed;
}.fc-calendar-arror {font-size: larger;position: relative;top: 8px;font-weight: 800;font-family: fangsong;cursor: pointer;
}
</style>