Vite Vue 麵包屑拖曳(語法糖)

Vite Vue 麵包屑拖曳(語法糖)

  • 點擊左邊菜單項目新增到麵包屑:陣列新增項目 => 使用 push()
  • 過濾掉相同的菜單項目並顯示在麵包屑:
    1.定義一個空陣列
    2.點擊菜單按鈕=>如果if從localStorage.getItem回來的數據不為null=> 原來的陣列等於localStorage.get回來的數據 ;無論localStorage.getItem回來的數據是否是null;都必須新增項目並過濾Fotmat (forEach遍歷 如果 空陣列與原陣列沒有發現相同那就新增push項目並且將數據localStorage.setItem)
  • 刪除麵包屑項目:獲取JSON.parse(localStorage.getItem('horizontalFilter')as string) =>如果 length 大於 0 =>刪除splice(id,1) 並且在setItem到localStorage 並且回調 在渲染的陣列get回來畫面上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
<template>
<div class="w-fill admin">
<div class="side left">
<div class="tabs" v-for="(item) in sideLists" :key="item.id">
<div class="tab">
<input type="radio" :id="item.id" name="rd">
<label class="tab-label hvr-underline-from-right" :for="item.id">
<i :class="item.icon"></i>
{{ item.title }}
</label>

<div class="tab-content">
<ul v-if="item.children">
<li class="hvr-underline-from-right" v-for="(i,id) in item.children"
:key="id"
:class="active === i.id ? 'isActive' : ''"
@click="sendClickActive(i)">
<router-link :to="i.href"> {{ i.title }}</router-link>
</li>
</ul>
</div>
</li>
</div>
</div>
</div><!---/side-->
<div class="rightContent">
<!--麵包屑--->
<div class="horizontal_menu">
<!--打開就看到首頁按鈕-->
<ul class="horizontalNav home">
<li v-for="item in homeItem" :key="item.title">
<router-link :to="item.href">{{ item.title }} </router-link>
</li>
</ul>

<ul class="horizontalNav">
<li v-for="item in horizontalfilter" :key="item.title">
<router-link :to="item.href">{{ item.title }} </router-link>
</li>
</ul>
</div>

<router-view />
</div><!---/rightContent-->
</div>
</template>

<script setup lang="ts">
import { ref, computed ,onMounted} from "vue"
import { useRouter } from 'vue-router'

interface horizontalNavType{
id:string,
title:string |any ,
href:string | any,
}
// 麵包屑陣列
const horizontal=ref<horizontalNavType[]>([]);
// 過濾的麵包屑陣列
const horizontalfilter=ref<horizontalNavType[]>([]);
// ***過濾掉重複函式
const horizontalfilterFormat =(horizontal:any) =>{
let filteredItems = horizontal;
const getResult: any[] = [];
filteredItems.forEach((item:any) => {
if (!getResult.find((r: { title: string; })=> r.title === item.title)) {
getResult.push(item);
localStorage.setItem('horizontalFilter',JSON.stringify( getResult)) ;
}
})
}
// 點擊左邊菜單新增到使用的麵包屑
const clickActiveSide = (i: horizontalNavType) => {
activeSide.value = i.id;
try{
let query: any={
id:i.id,
title:i.title,
href:i.href
}
if(JSON.parse(localStorage.getItem('horizontalFilter')as string)!=null){
let get =JSON.parse(localStorage.getItem('horizontalFilter')as string);
horizontal.value=get;
}
horizontal.value.push(query);
horizontalfilterFormat(horizontal.value)
horizontalfilter.value= JSON.parse(localStorage.getItem('horizontalFilter')as string);
}
catch(err){
console.log(err)
}
}
// 刪除麵包屑項目
const deleteHorizontalNav =(title:any |string)=>{
const lists =JSON.parse(localStorage.getItem('horizontalFilter')as string);
if(lists.length>0 ){
lists.splice(title,1);
localStorage.setItem('horizontalFilter', JSON.stringify(lists)) ; horizontalfilter.value= JSON.parse(localStorage.getItem('horizontalFilter')as string);
}else{
router.push({ path: '/admin'})
}
}
const activeSide = ref<string>('')
const isActiveSide = ref<boolean>(false);
interface sideListType{
id:string,
title:string,
icon:string,
children:object,
}
//左手邊菜單
const sideLists=ref<sideListType[]>([
{
id:'buildSet',
title: "建檔設定",
icon:"fa-solid fa-address-book",
children: [
{id:'buildSet1-1',title: "工程資料建檔",href:"/one"}
{id:'buildSet1-2',title: "供料資料建檔",href:"/two"}
{id:'buildSet1-3',title: "供料資料建檔",href:"/three"}
{id:'buildSet1-4',title: "供料資料建檔",href:"/four"}
]
},
{
id:'dataSearch',
title: "資料搜尋",
icon:"fa-solid fa-address-book",
children: [
{id:'dataSearch1-1',title: "業主資料查詢",href:"/one"}
{id:'dataSearch1-2',title: "工程資料查詢",href:"/two"}
{id:'dataSearch1-3',title: "採購合約查詢",href:"/three"}

]
}
])
//首頁麵包屑定義
const homeItem =ref<any[]>([]);
// 打開時 讓選單可以出現首頁
const homeBtn=()=>{
const query={
id:'home',
title:'首頁',
href:'/admin',
}
homeItem.value.push(query);
}
onMounted(() => {
homeBtn();
localStorage.removeItem('horizontalFilter')
});
</script>



<style lang="scss" >
//左邊菜單
.admin {
display: flex;
width:100%;
//Side
.side{
border-right: 2px solid #c6e2ff;
background-color: #c6e2ff;
flex-direction: column;
max-width: 240px;
min-height: 100vh;
overflow-y: calc(100vh - 0px);
padding-top: 25px;
width: 240px;
ul {
list-style-type:none;
margin-block-start: 0em;
margin-block-end: 0em;
padding-inline-start: 35px;
}
.tabs {
overflow: hidden;
.tab{
color: #333;
overflow: hidden;
width: 100%;
input {
display: none;
&:checked{
~ .tab-content {
max-height: 100vh;
padding: .2em 0px .2em 1em;
}
}
}
.tab-label {
cursor: pointer;
display: flex;
justify-content: space-around;
padding: 0.6em;
font-size: 16px;
i {
color: #3F51B5;
font-size: 20px;
}
&:after {
content: "❯";
width: 1em;
height: 1em;
text-align: center;
transition: all 0.35s;
}
}
.tab-content{
max-height: 0;
padding: 0 1em;
color: #2c3e50;
transition: all 0.35s;
}
}
}
}

}


.rightContent{
display: flex;
flex-direction: column;
width: calc(100% - 240px);
max-width: 100%;

.horizontal_menu{
display: flex;
.horizontalNav{
display: flex;
list-style-type: none;
margin-block-start: 0em;
margin-block-end: 0em;
padding: 5px 0px;
li{
display: flex;
list-style-type: none;
margin: 0% 4px;
a{
text-decoration: none;
background-color: #409eff;
color: white;
padding: 8px 18px;
border-radius: 8px 8px;
-webkit-border-radius: 8px 8px;
i{
color: white;
&:hover{
color#ddd;
}
}
}
}
}
}
}
<style>

特別講解過濾重複陣列

  • forEach() js 遍歷
  • find() js 傳回通過測試的陣列中第一個元素的值)
  • push js 新增
  • localStorage.setItem為陣列時必須使用JSON.stringify()
  • localStorage.getItem為陣列時必須使用JSON.parse(localStorage.getItem('horizontalFilter')as string)
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const horizontalfilterFormat =(horizontal:any) =>{
    let filteredItems = horizontal;
    const getResult: any[] = [];
    filteredItems.forEach((item:any) => {
    if (!getResult.find((r: { title: string; })=> r.title === item.title)) {
    getResult.push(item);
    localStorage.setItem('horizontalFilter',JSON.stringify( getResult)) ;
    }
    })
    }

    gitHib

    增加可以拖動功能

    安裝swiperjs

    1
    2
    3
    ```
    npm install swiper --save

    檔案node_modules/swiper/swiper-bundle.css另存到@/assets/swiper-bundle.css 並且到main.ts全局加入

    1
    import '@/assets/css/swiper-bundle.css';
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    <template>
    <div class="horizontal_menu">
    <ul class="horizontalNav">
    <li v-for="item in homeItem" :key="item.title">
    <router-link :to="item.href">{{ item.title }} </router-link>
    </li>
    </ul>
    <swiper
    :modules="modules"
    :slides-per-view="3"
    :space-between="10"
    :loop="false"
    :autoplay="false"
    @swiper="onSwiper"
    @slideChange="onSlideChange"
    >
    <swiper-slide v-for="item in horizontalfilter" :key="item.title">
    <a :href="item.href">{{ item.title }}
    <i class="icon-cross"
    @click.prevent="deleteHorizontalNav(item.title)">
    </i>
    </a>
    </swiper-slide>
    </swiper>
    </div>
    </template>


    <script setup lang="ts">
    import { ref, computed ,onMounted} from "vue"
    import { useRouter } from 'vue-router'
    import { homeMenuType } from "@/types/navMenuType"
    import { Swiper, SwiperSlide } from 'swiper/vue'//引入
    import { Autoplay, Pagination, Navigation, Scrollbar }from 'swiper/modules'//解構取出

    interface horizontalNavType{
    id:string,
    title:string |any ,
    href:string | any,
    }
    const horizontal=ref<horizontalNavType[]>([]);
    const horizontalfilter=ref<horizontalNavType[]>([]);
    //過濾掉重複
    const horizontalfilterFormat =(horizontal:any) =>{
    let filteredItems = horizontal;
    const getResult: any[] = [];
    filteredItems.forEach((item:any) => {
    if (!getResult.find((r: { title: string; })=> r.title === item.title)) {
    getResult.push(item);
    localStorage.setItem('horizontalFilter',JSON.stringify( getResult)) ;
    }
    })
    }
    // Swiper定義
    const modules = [Autoplay, Pagination, Navigation, Scrollbar]
    const onSwiper = (swiper:any) => {
    console.log(swiper);
    };
    const onSlideChange = () => {
    console.log('slide change');
    };

    // 點擊左邊菜單新增到使用頁眉
    const clickActiveSide = (i: horizontalNavType) => {
    activeSide.value = i.id;
    try{
    let query: any={
    id:i.id,
    title:i.title,
    href:i.href
    }
    if(JSON.parse(localStorage.getItem('horizontalFilter')as string)!=null){
    let get =JSON.parse(localStorage.getItem('horizontalFilter')as string);
    horizontal.value=get;
    }
    horizontal.value.push(query);
    horizontalfilterFormat(horizontal.value)
    horizontalfilter.value= JSON.parse(localStorage.getItem('horizontalFilter')as string);
    }
    catch(err){
    console.log(err)
    }
    }

    const deleteHorizontalNav =(title:any |string)=>{
    const lists =JSON.parse(localStorage.getItem('horizontalFilter')as string);
    if(lists.length>0 ){
    lists.splice(title,1);
    localStorage.setItem('horizontalFilter', JSON.stringify(lists)) ; horizontalfilter.value= JSON.parse(localStorage.getItem('horizontalFilter')as string);
    }else{
    router.push({ path: '/admin'})
    }
    }
    const homeItem =ref<any[]>([])
    // 打開時 讓選單可以出現首頁
    const homeBtn=()=>{
    const query={
    id:'home',
    title:'首頁',
    href:'/admin',
    }
    homeItem.value.push(query);
    }
    onMounted(() => {
    homeBtn();
    localStorage.removeItem('horizontalFilter')
    });
    </script>



    <style lang="scss">
    .horizontal_menu{
    display: flex;
    justify-content: flex-start;
    .horizontalNav{
    display: flex;
    padding-inline-start: 0px;
    width: 55px;
    li{
    margin: auto 8px;
    }
    a{
    width: 80px;
    display: block;
    text-align: center;
    line-height: 38px;
    background-color: cornflowerblue;
    color:white;
    padding: 8px 14px;
    height: 38px;
    border-radius: 8px;
    }
    }
    .swiper{
    margin-left: 15px;
    overflow: visible;
    display: flex;
    align-items: center;
    &.swiper-horizontal{
    text-align: left;
    margin-left: 45px;
    }
    .swiper-wrapper{
    display: flex;
    justify-content: flex-start;
    overflow: visible;
    align-items: center;
    .swiper-slide{
    width: auto!important;background-color: cornflowerblue;
    color: white;
    overflow: visible;
    display: flex;
    align-items: center;
    padding-left: 8px;
    padding-right: 8px;
    border-radius: 7px;
    height: 38px;
    a{
    color: white;
    display: flex;
    align-items: center;
    .icon-cross{
    margin-left: 5px;
    }
    }
    }
    }
    }
    </style>

    gitHub 麵包屑拖曳

    js相同陣列過濾去除

    css手風琴菜單