School Picker - daniel-qa/Vue GitHub Wiki
-
特別注意,computed(), 要和 ref 的變數在同一支檔案,避免邏輯的混亂
-
只引用需要的資料,有些函式,要改寫在子組件
-
需要的數據: subItems
-
SchoolPicker.vue
<template>
<div v-if="activeIndex !== null" class="list2 parent">
<!-- 搜尋框 -->
<el-input v-model="searchQuery"
placeholder="搜尋子項目..."
size="medium"
clearable
class="child"
style="width: 90%; top: 5%;"></el-input>
<!-- 学校列表 -->
<div class="list child" style="height: 85%; top: 12%; width: 90%;">
<div v-for="(subItem, subIndex) in filteredSubItems"
:key="subIndex"
:class="{'active': activeIndex2 === subIndex}"
class="list-item"
@click="setActive2(subIndex)">
{{ subItem.name }} {{ subItem.tchCnt }} 人
<el-button size="small"
@click.stop="addToColumn3(subItem)"
type="success">
加入
</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, defineProps } from "vue";
// 父組件傳入的 props
const props = defineProps({
activeIndex: {
type: Number,
required: true
},
activeIndex2: {
type: Number,
required: true
},
searchQuery: {
type: String,
required: true
},
filteredSubItems: {
type: Array,
required: true
},
setActive2: {
type: Function,
required: true
},
addToColumn3: {
type: Function,
required: true
}
});
</script>
<style scoped>
/* 样式与原程序保持一致 */
.list {
width: 100%;
height: 60vh;
border: 1px solid #ccc;
padding: 10px;
overflow-y: auto;
}
.list2 {
width: 100%;
height: 60vh;
border: 1px solid #ccc;
padding: 10px;
}
.list-item {
min-height: 50px;
max-height: 100px;
line-height: 50px;
padding: 0 10px;
cursor: pointer;
transition: background-color 0.3s ease;
display: flex;
justify-content: space-between;
align-items: center;
}
.list-item:hover {
background-color: #f0f0f0;
}
.list-item.active {
background-color: #409eff;
color: white;
}
.head-text {
font-weight: bold;
font-size: 18px;
}
.el-list-item {
padding: 5px 10px !important;
line-height: 1.5 !important;
height: auto !important;
display: flex;
justify-content: space-between;
}
/* 自定義 select 高度 */
.custom-select {
line-height: 1; /* 調整外部行高,避免過多空間 */
margin: 0; /* 移除外部間距 */
}
.parent {
position: relative; /* 父元素設置為 relative */
}
.child {
position: absolute; /* 子元素設置為 absolute */
top: 20px;
left: 20px;
}
</style>
props 在 Vue 中的作用類似於函式的參數,它是父組件傳遞給子組件的數據或方法。
- 實際載入組件
<!-- 第二列:子级菜单 -->
<el-col :span="8">
<SchoolPicker :activeIndex="activeIndex"
:activeIndex2="activeIndex2"
:searchQuery="searchQuery"
:filteredSubItems="filteredSubItems"
:setActive2="setActive2"
:addToColumn3="addToColumn3" />
</el-col>
- 載入設定
import SchoolPicker from "./SchoolPicker.vue"; // 引入新組件
// 选中状态
const activeIndex = ref(null); // 当前选中的学区
const activeIndex2 = ref(null); // 当前选中的学校
const searchQuery = ref(""); // 搜索框内容
// 过滤子级菜单项(学校)
// filteredSubItems 是一个 计算属性,当 activeIndex 或 searchQuery 更新时会自动重新计算。
const filteredSubItems = computed(() => {
// 如果没有选中任何学区,返回空数组
if (activeIndex.value === null) return [];
// 获取当前选中的学区的学校列表
// 如果当前学区没有学校数据,则返回一个空数组
const currentSubItems = subItems.value[activeIndex.value] || [];
//debugger;
// 根据搜索框的内容过滤学校列表
// 使用 toLowerCase() 进行不区分大小写的匹配
return currentSubItems.filter((item) =>
item.name.toLowerCase().includes(searchQuery.value.toLowerCase())
);
});
// 选中学校
const setActive2 = (index) => {
activeIndex2.value = index;
};
// Type 種類
//1 .學區: area
//2 .地理資訊: geo
//3 .教育機構類型: unit
//4 .學校ID: school
//5 .醍摩豆ID: tmid
// 添加到第三列 (响应式触发更新)
const addToColumn3 = (item) => {
//debugger;
// 转为 JSON 字符串
const newValue = JSON.stringify(item);
// 检查是否已存在
const isExist = column3Items.value.some((column3) => JSON.stringify(column3) === newValue);
if (!isExist) {
column3Items.value.push(item);
ElMessage.success(`已加入接收名單`);
} else {
ElMessage.warning(`已存在接收名單中`);
}
};
- prop 變數的引用
props.activeIndex