vue 實現多條件篩選

大體效果圖是這樣的:
​​在這裏插入圖片描述
在這裏插入圖片描述
一、涉及的知識點:

  1. vue 組件化開發,不懂的可以參考vue 組件基礎 ==》https://cn.vuejs.org/v2/guide/components.html
  2. es6 promise 模擬數據,參考 ==》http://es6.ruanyifeng.com/#docs/promise

其他:
1.可把組件單獨放一個js文件裏,通過script 引入即可。
2.全部寫在一個頁面是爲了更加直觀的理解,開發代碼時,個人不建議用此方法
3.第一次寫文章,有什麼不對的,希望大家別見怪!謝謝

<script src="js/demo-filter.js"></script>

二、實現:

  1. 主邏輯部分
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)
		}
	}
})
  1. 過濾篩選組件
// 過濾組件
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)
		}
	}
})
  1. 佈局組件
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`
			}
		}
	}
})
  1. 頁面調用
<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>
  1. 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
				}
			]
		}
	]
}
  1. 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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章