大體效果圖是這樣的:
一、涉及的知識點:
- vue 組件化開發,不懂的可以參考vue 組件基礎 ==》https://cn.vuejs.org/v2/guide/components.html
- es6 promise 模擬數據,參考 ==》http://es6.ruanyifeng.com/#docs/promise
其他:
1.可把組件單獨放一個js文件裏,通過script 引入即可。
2.全部寫在一個頁面是爲了更加直觀的理解,開發代碼時,個人不建議用此方法
3.第一次寫文章,有什麼不對的,希望大家別見怪!謝謝
<script src="js/demo-filter.js"></script>
二、實現:
- 主邏輯部分
const vm = new Vue({
el: '#view',
data() {
return {
viewList: [],
viewTime: {
time: true,
msg: '數據拼命加載中...'
},
param: {},
filterList: [],
filterSelData: [] // 過濾選中的數據
}
},
created() {
// 請求數據
this.setRequest('json/demo2.json', this.param, 'get').then(res => {
this.viewList = [...res.list]
return this.setRequest('json/demo3.json', this.param, 'get')
}).then(res => {
this.filterList = [...res.list]
})
},
mounted() {
this.setTime(1000, 0, false)
},
methods: {
// 封裝 axios
setRequest(url, data = {}, method = 'get') {
return new Promise((resolve, reject) => {
axios({
url,
method,
data
}).then(res => {
resolve(res.data)
}).catch(err => {
reject(err)
})
})
},
// 獲取篩選組件選中的值
getFilterSelData(data) {
this.filterSelData = data
},
// 模擬延時顯示數據視圖
setTime(startTime, endTime, bool) {
setTimeout(() => {
this.viewTime.time = bool
setTimeout(() => {
this.viewTime.time = false
}, endTime)
}, startTime)
}
}
})
- 過濾篩選組件
// 過濾組件
Vue.component('demo-filter', {
template: `
<div class="demo">
<div class="demo-warp">
<div class="demo-flex" v-for="(v,k) in getList" :key="k">
<span class="demo-title">{{v.title}}</span>
<div class="demo-content">
<div class="demo-tab" :class="isShow ? 'demo-hide' : ''">
<span v-for="(val, key) in v.childer" :key="key"
:class="{'demo-active': val.active}"
@click="tabClick(val,key,k)">{{val.value}}</span>
</div>
</div>
<div class="demo-more" @click="isShow = !isShow" v-if="v.childer.length >= 14">更多</div>
</div>
</div>
</div>
`,
data() {
return {
isShow: false
}
},
props: {
getList: {
type: Array,
default: () => []
}
},
methods: {
tabClick(data, key, k) {
// 添加 active ==> true 顯示 `active樣式`
this.getList[k].childer.map(item => {
item.active = false
})
this.getList[k].childer[key].active = true
// 選中的數據
let newArray = []
this.getList.map(data => {
data.childer.map(item => {
if (item.active == true) {
newArray.push(item)
}
})
})
this.$emit('get-sel-data', newArray)
this.$emit('set-time', 0, 1000, true)
}
}
})
- 佈局組件
Vue.component('view-layout', {
template: `<div class="view-warp">
<div class="view-box" v-if="!viewTime.time">
<div class="view-flex" v-for="(v,k) in viewData" :key="k" :style="style">
<div class="view-item">
<span>{{v.title}}</span>
</div>
</div>
</div>
<div class="view-no-data" v-else>{{viewTime.msg}}</div>
</div>`,
props: {
viewData: {
type: Array,
default: () => []
},
width: {
type: String,
default: "25%"
},
height: {
type: String,
default: "300px"
},
viewTime: {
type: Object,
default: {
time: true,
msg: '數據加載中...'
}
}
},
computed: {
style() {
return {
width: `${this.width.replace(/%+/, '')}%`,
height: `${this.height.replace(/px+/, '')}px`
}
}
}
})
- 頁面調用
<demo-filter :get-list="filterList" @get-sel-data="getFilterSelData" @set-time="setTime"></demo-filter>
<view-layout :view-data="viewList" width="25%" height="300px" :view-time="viewTime"></view-layout>
- json數據
1.佈局組件json ==> 路徑: json/demo2.json
{
"list": [{
"title": "11"
},
{
"title": "22"
},
{
"title": "33"
},
{
"title": "44"
},
{
"title": "55"
},
{
"title": "66"
}
]
}
2. 過濾篩選組件json ==> 路徑: json/demo3.json
{
"list": [{
"title": "分類:",
"childer": [{
"value": "全部",
"active": true
},
{
"value": "漂浮素材",
"active": false
},
{
"value": "效果元素",
"active": false
},
{
"value": "卡通手繪",
"active": false
},
{
"value": "裝飾圖案",
"active": false
},
{
"value": "圖標元素",
"active": false
},
{
"value": "促銷標籤",
"active": false
},
{
"value": "邊框紋理",
"active": false
},
{
"value": "不規則圖形",
"active": false
},
{
"value": "表情包213123",
"active": false
},
{
"value": "表情包2323",
"active": false
},
{
"value": "表情包1111",
"active": false
},
{
"value": "表情包3333",
"active": false
},
{
"value": "表情包444",
"active": false
}
]
},
{
"title": "格式:",
"childer": [{
"value": "全部",
"active": true
},
{
"value": "PSD",
"active": false
},
{
"value": "AI",
"active": false
},
{
"value": "EPS",
"active": false
}
]
},
{
"title": "排序:",
"childer": [{
"value": "推薦",
"active": true
},
{
"value": "昨日熱門",
"active": false
},
{
"value": "最新上傳",
"active": false
},
{
"value": "熱門下載",
"active": false
},
{
"value": "熱門收藏",
"active": false
}
]
}
]
}
- css 樣式
/* 佈局組件:start */
.view-warp {
flex: 1;
overflow: hidden;
margin: auto;
display: flex;
}
.view-box {
overflow: auto;
width: 1220px;
height: 100%;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
margin: 0 -10px;
}
.view-flex {
padding: 10px;
cursor: pointer;
transition: ease .5s;
transform-style: preserve-3d;
}
.view-flex:hover {
transform: translateY(-10px);
transition: ease .5s;
}
.view-item {
height: 100%;
border: 1px solid red;
display: flex;
}
.view-item>span {
margin: auto;
}
.view-no-data {
margin: auto;
}
/* 佈局組件:end */
/* 過濾列表:start */
.demo {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
margin-bottom: 15px;
min-height: 140px;
height: auto !important;
height: 140px;
}
.demo-warp {
display: flex;
max-width: 1200px;
margin: auto;
height: 100%;
flex-direction: column;
padding: 15px 0;
}
.demo-flex {
display: flex;
margin-bottom: 15px;
}
.demo-flex:last-of-type {
margin-bottom: 0;
}
.demo-title {
flex-basis: 70px;
margin-top: 5px;
}
.demo-content {
display: flex;
flex: 1;
}
.demo-tab {
flex: 1;
margin-right: 15px;
height: 35px;
overflow: hidden;
}
.demo-tab span {
display: inline-block;
margin: 0 5px 15px 5px;
cursor: pointer;
padding: 5px 10px;
color: #999999;
}
.demo-more {
margin-top: 5px;
cursor: pointer;
}
.demo-active {
background-color: #09F;
color: white !important;
border-radius: 3px;
}
.demo-tab span:hover {
background-color: #09F;
color: white;
border-radius: 3px;
}
.demo-hide {
min-height: 35px;
height: auto !important;
}
/* 過濾列表:end */
三、全部html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<style type="text/css">
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body,
section {
width: 100%;
height: 100%;
}
[v-clock] {
display: none;
}
section {
display: flex;
flex-direction: column;
}
/* 佈局組件:start */
.view-warp {
flex: 1;
overflow: hidden;
margin: auto;
display: flex;
}
.view-box {
overflow: auto;
width: 1220px;
height: 100%;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
margin: 0 -10px;
}
.view-flex {
padding: 10px;
cursor: pointer;
transition: ease .5s;
transform-style: preserve-3d;
}
.view-flex:hover {
transform: translateY(-10px);
transition: ease .5s;
}
.view-item {
height: 100%;
border: 1px solid red;
display: flex;
}
.view-item>span {
margin: auto;
}
.view-no-data {
margin: auto;
}
/* 佈局組件:end */
/* 過濾列表:start */
.demo {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
margin-bottom: 15px;
min-height: 140px;
height: auto !important;
height: 140px;
}
.demo-warp {
display: flex;
max-width: 1200px;
margin: auto;
height: 100%;
flex-direction: column;
padding: 15px 0;
}
.demo-flex {
display: flex;
margin-bottom: 15px;
}
.demo-flex:last-of-type {
margin-bottom: 0;
}
.demo-title {
flex-basis: 70px;
margin-top: 5px;
}
.demo-content {
display: flex;
flex: 1;
}
.demo-tab {
flex: 1;
margin-right: 15px;
height: 35px;
overflow: hidden;
}
.demo-tab span {
display: inline-block;
margin: 0 5px 15px 5px;
cursor: pointer;
padding: 5px 10px;
color: #999999;
}
.demo-more {
margin-top: 5px;
cursor: pointer;
}
.demo-active {
background-color: #09F;
color: white !important;
border-radius: 3px;
}
.demo-tab span:hover {
background-color: #09F;
color: white;
border-radius: 3px;
}
.demo-hide {
min-height: 35px;
height: auto !important;
}
/* 過濾列表:end */
</style>
</head>
<body>
<section id="view" clock>
<demo-filter :get-list="filterList" @get-sel-data="getFilterSelData" @set-time="setTime"></demo-filter>
<view-layout :view-data="viewList" width="25%" height="300px" :view-time="viewTime"></view-layout>
<pre>
選中的數據:{{filterSelData}}
</pre>
</section>
<script type="text/javascript">
// 過濾篩選組件
Vue.component('demo-filter', {
template: `
<div class="demo">
<div class="demo-warp">
<div class="demo-flex" v-for="(v,k) in getList" :key="k">
<span class="demo-title">{{v.title}}</span>
<div class="demo-content">
<div class="demo-tab" :class="isShow ? 'demo-hide' : ''">
<span v-for="(val, key) in v.childer" :key="key" :class="{'demo-active': val.active}" @click="tabClick(val,key,k)">{{val.value}}</span>
</div>
</div>
<div class="demo-more" @click="isShow = !isShow" v-if="v.childer.length >= 14">更多</div>
</div>
</div>
</div>
`,
data() {
return {
isShow: false
}
},
props: {
getList: {
type: Array,
default: () => []
}
},
methods: {
tabClick(data, key, k) {
// 添加 active ==> true 顯示 `active樣式`
this.getList[k].childer.map(item => {
item.active = false
})
this.getList[k].childer[key].active = true
// 選中的數據
let newArray = []
this.getList.map(data => {
data.childer.map(item => {
if (item.active == true) {
newArray.push(item)
}
})
})
this.$emit('get-sel-data', newArray)
this.$emit('set-time', 0, 1000, true)
}
}
})
// 佈局組件
Vue.component('view-layout', {
template: `<div class="view-warp">
<div class="view-box" v-if="!viewTime.time">
<div class="view-flex" v-for="(v,k) in viewData" :key="k" :style="style">
<div class="view-item">
<span>{{v.title}}</span>
</div>
</div>
</div>
<div class="view-no-data" v-else>{{viewTime.msg}}</div>
</div>`,
props: {
viewData: {
type: Array,
default: () => []
},
width: {
type: String,
default: "25%"
},
height: {
type: String,
default: "300px"
},
viewTime: {
type: Object,
default: {
time: true,
msg: '數據加載中...'
}
}
},
computed: {
style() {
return {
width: `${this.width.replace(/%+/, '')}%`,
height: `${this.height.replace(/px+/, '')}px`
}
}
}
})
</script>
<script type="text/javascript">
const vm = new Vue({
el: '#view',
data() {
return {
viewList: [],
viewTime: {
time: true,
msg: '數據拼命加載中...'
},
param: {},
filterList: [],
filterSelData: [] // 過濾選中的數據
}
},
created() {
// 請求數據
this.setRequest('json/demo2.json', this.param, 'get').then(res => {
this.viewList = [...res.list]
return this.setRequest('json/demo3.json', this.param, 'get')
}).then(res => {
this.filterList = [...res.list]
})
},
mounted() {
this.setTime(1000, 0, false)
},
methods: {
// 封裝 axios
setRequest(url, data = {}, method = 'get') {
return new Promise((resolve, reject) => {
axios({
url,
method,
data
}).then(res => {
resolve(res.data)
}).catch(err => {
reject(err)
})
})
},
// 獲取篩選組件選中的值
getFilterSelData(data) {
this.filterSelData = data
},
// 模擬延時顯示數據視圖
setTime(startTime, endTime, bool) {
setTimeout(() => {
this.viewTime.time = bool
setTimeout(() => {
this.viewTime.time = false
}, endTime)
}, startTime)
}
}
})
</script>
</body>
</html>