Authored by 陈峰

filter box

... ... @@ -18,9 +18,9 @@ module.exports = {
app_type: 1
},
domains: {
api: 'http://api-test2.yohops.com:9999/',
service: 'http://service-test2.yohops.com:9999/',
singleApi: 'http://api-test2.yohops.com:9999/',
api: 'http://api-test3.yohops.com:9999/',
service: 'http://service-test3.yohops.com:9999/',
singleApi: 'http://api-test3.yohops.com:9999/',
// api: 'http://api-test3.yohops.com:9999/',
// service: 'http://service-test3.yohops.com:9999/',
... ...
... ... @@ -9,15 +9,25 @@
</ul>
<div class="sub-level-container">
<ul class="sub-level">
<li class="ellipsis">
<a v-if="jump" href="/product/list?sort={{rightAll.sortId || '' }}&sort_name=全部{{rightAll.categoryName || ''}}&gender={{gender}}">全部{{rightAll.categoryName}}</a>
<a v-else @click="noJumpReturn(rightAll.sortId, '全部' + rightAll.categoryName)">全部{{rightAll.categoryName}}</a>
<li :class="{'sub-checked': rightAll.checked}">
<div class="block ellipsis">
<a v-if="jump" href="/product/list?sort={{rightAll.sortId || '' }}&sort_name=全部{{rightAll.categoryName || ''}}&gender={{gender}}">全部{{rightAll.categoryName}}</a>
<a v-else @click="noJumpReturn(rightAll.sortId, '全部' + rightAll.categoryName, true)">全部{{rightAll.categoryName}}</a>
</div>
<div class="checked">
<i class="icon icon-check"></i>
</div>
</li>
</ul>
<ul class="sub-level">
<li v-for="sub in cateNavRightData" class="ellipsis">
<a v-if="jump" href="/product/list?sort={{sub.relation_parameter.sort}}&sort_name={{sub.category_name}}&gender={{gender}}">{{sub.category_name}}</a>
<a v-else @click="noJumpReturn(sub.relation_parameter.sort, sub.category_name)">{{sub.category_name}}</a>
<li v-for="sub in cateNavRightData" :class="{'sub-checked': sub.checked}">
<div class="block ellipsis">
<a v-if="jump" href="/product/list?sort={{sub.relation_parameter.sort}}&sort_name={{sub.category_name}}&gender={{gender}}">{{sub.category_name}}</a>
<a v-else @click="noJumpReturn(sub.relation_parameter.sort, sub.category_name)">{{sub.category_name}}</a>
</div>
<div class="checked">
<i class="icon icon-check"></i>
</div>
</li>
</ul>
</div>
... ... @@ -184,30 +194,44 @@
line-height: 88px;
border-bottom: 1px solid #e6e6e6;
padding-left: 30px;
margin-right: 30px;
user-select: none;
white-space: nowrap;
overflow-y: auto;
display: flex;
&.highlight {
background: #eee;
}
&.sub-checked {
.icon {
display: inline !important;
}
}
&:hover {
background-color: #efefef;
}
}
a {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 20px;
display: inline;
color: #b0b0b0;
overflow: hidden;
text-overflow: ellipsis;
.block {
flex: 1;
}
.checked {
width: 100px;
text-align: center;
color: #000;
.icon {
display: none;
}
}
a {
color: #b0b0b0;
display: block;
width: 100%;
}
}
}
}
... ... @@ -225,6 +249,12 @@
},
gender: {
type: String
},
value: {
type: Array,
default() {
return [];
}
}
},
data() {
... ... @@ -232,10 +262,15 @@
cateNavLeftData: [], // 左侧分类数据
cateNavRightData: [], // 右侧分类数据
leftcurrent: 0, // 标记当前左侧选中条目
rightAll: {} // 全部XX
rightAll: {}, // 全部XX
currentValue: this.value
};
},
watch: {
value(val) {
this.currentValue = val;
this.categoryChangeHandler();
},
category() {
this.categoryChangeHandler();
}
... ... @@ -244,17 +279,48 @@
cateNavLeftFun(index, categoryId, categoryName) {
this.leftcurrent = index;
this.cateNavRightData = this.cateNavLeftData[index].sub;
let allSorts = this.getAllSortId(this.cateNavRightData);
this.rightAll = {
sortId: categoryId ? categoryId : '',
categoryName: categoryName ? categoryName : ''
sortId: allSorts,
categoryName: categoryName ? categoryName : '',
checked: this.currentValue.some(cate => {
return cate.id.toString() === allSorts;
})
};
},
/* 筛选列表使用返回值 */
noJumpReturn(categoryId, categoryName) {
this.$dispatch('select', {
id: categoryId,
name: categoryName
noJumpReturn(categoryId, categoryName, isall) {
let cateIndex = this.currentValue.findIndex(cate => cate.id.toString() === categoryId);
if (cateIndex >= 0) {
this.currentValue.splice(cateIndex, 1);
} else {
this.currentValue.push({
id: categoryId,
name: categoryName
});
}
if (isall) {
this.cateNavRightData.forEach(cate => {
let cateRmIndex = this.currentValue
.findIndex(c => c.id.toString() === cate.relation_parameter.sort);
if (cateRmIndex >= 0) {
this.currentValue.splice(cateRmIndex, 1);
}
});
} else if (this.rightAll.checked) {
let cateRmIndex = this.currentValue.findIndex(c => c.id.toString() === this.rightAll.sortId);
if (cateRmIndex >= 0) {
this.currentValue.splice(cateRmIndex, 1);
}
}
this.$emit('select', {
value: this.currentValue,
subType: 'group_sort'
});
},
... ... @@ -262,17 +328,30 @@
if (!this.category || !this.category.length) {
return;
}
this.$set('cateNavLeftData', this.category);
this.$set('cateNavRightData', this.cateNavLeftData ? this.cateNavLeftData[0].sub : []);
let selectLeftCate = this.cateNavLeftData[this.leftcurrent] || {};
let allSorts = this.cateNavLeftData[0].sub ?
this.cateNavLeftData[0].sub.map(sort=>sort.relation_parameter.sort).join(',') : '';
this.cateNavRightData = [];
this.$nextTick(() => {
this.$set('cateNavRightData', selectLeftCate.sub);
this.$set('rightAll', this.cateNavLeftData ? {
sortId: allSorts,
categoryName: this.cateNavLeftData[0].category_name
} : {});
this.cateNavRightData.forEach(cate => {
cate.checked = this.currentValue
.some(selCate =>
selCate.id.toString() === cate.relation_parameter.sort);
});
let allSorts = this.getAllSortId(this.cateNavRightData);
this.$set('rightAll', this.cateNavLeftData ? {
sortId: allSorts,
categoryName: selectLeftCate.category_name,
checked: this.currentValue.some(cate => cate.id.toString() === allSorts)
} : {});
});
},
getAllSortId(sub) {
return sub.map(sort=>sort.relation_parameter.sort).join(',') + ',';
}
},
created() {
... ...
<template>
<div class="filter-detail">
<div class="item" @click="select({id: ''})">
<div class="item-inner">所有品牌</div>
</div>
<dl v-for="key in orderKeys">
<dt class="index" id="{{key}}">{{key}}</dt>
<dd class="item" v-for="brand in data[key]" :class="{'active': brand.id === val}" @click="select(brand)">
<dl v-for="item in indexData" :key="item.index">
<dt class="index" id="{{item.index}}">{{item.index}}</dt>
<dd class="item" v-for="brand in currentData[item.index]" :key="brand.id" :class="{'active': brand.checked}" @click="select(brand)">
<div class="item-inner">{{brand.name}}</div>
<div class="item-check">
<i class="icon icon-check"></i>
</div>
</dd>
</dl>
<index-list :index-list="indexList"></index-list>
<index-list class="filter-index-list" :index-list="indexData"></index-list>
</div>
</template>
<script>
... ... @@ -25,55 +25,82 @@
module.exports = {
props: {
val: Number,
data: {
default: () => { return [];},
coerce(data) {
const res = {};
$.each(data, (index, brand) => {
let groupName = brand.alif;
if (!res.hasOwnProperty(groupName)) {
res[groupName] = [];
}
res[groupName].push(brand);
});
return res;
type: Array,
default() {
return [];
}
},
value: {
type: Array,
default() {
return [];
}
}
},
data() {
return {
indexList: []
indexData: [],
currentData: [],
currentValue: this.value
};
},
watch: {
},
methods: {
select: function(val) {
this.$dispatch('select', val);
value(val) {
this.currentValue = val;
this.renderData();
}
},
computed: {
orderKeys() {
let keys = [];
const self = this;
methods: {
renderData() {
const res = {};
$.each(this.data, (index, brand) => {
let groupName = brand.alif;
keys = Object.keys(this.data).sort();
self.$set('indexList', keys.map(k => {
if (!res.hasOwnProperty(groupName)) {
res[groupName] = [];
}
brand.checked = this.currentValue.some(b => b.id === brand.id);
res[groupName].push(brand);
});
this.currentData = res;
this.indexData = Object.keys(this.currentData).sort().map(k => {
return {
index: k,
name: k
};
}));
});
},
select: function(val) {
let brandIndex = this.currentValue.findIndex(brand => brand.id === val.id);
return keys;
if (brandIndex >= 0) {
this.currentValue.splice(brandIndex, 1);
} else {
this.currentValue.push({
id: val.id,
name: val.name
});
}
this.$emit('select', {
value: this.currentValue,
subType: 'brand'
});
}
},
created() {
this.renderData();
},
components: {
indexList
}
};
</script>
<style>
.filter-index-list {
top: calc(70 + 20 * 2 + 1)px;
}
</style>
... ...
<template>
<div class="filter-sub" :class="{'filter-sub-open': isVisible}">
<c-header class="filter-sub-header" :title="type | filter-cn '选择'">
<c-header class="filter-sub-header" :title="type | filter-cn ">
<i class="icon icon-left" slot="left" @click="hide"></i>
<button class="btn-clear" slot="right" @click="clear">清空</button>
</c-header>
<div class="filter-sub-select">
<brand-filter v-if="type === 'brand'" :data="data" @select="selectItem"></brand-filter>
<normal-filter v-if="type !== 'brand' && type !== 'group_sort'" :data="data" :type="type" @select="selectItem"></normal-filter>
<sort-filter class="filter-detail filter-sort" v-if="type === 'group_sort'" :category="data" @select="selectItem"></sort-filter>
<brand-filter
v-if="subType === 'brand'"
:data="data"
:value="currentValue"
@select="selectItem"></brand-filter>
<normal-filter
v-if="subType && subType !== 'brand' && subType !== 'group_sort'"
:data="data"
:value="currentValue"
:type="subType"
@select="selectItem"></normal-filter>
<sort-filter class="filter-detail filter-sort"
v-if="subType === 'group_sort'"
:value="currentValue"
:category="data"
@select="selectItem"></sort-filter>
</div>
</div>
</template>
... ... @@ -18,16 +32,57 @@
module.exports = {
components: {cHeader, brandFilter, normalFilter, sortFilter},
props: ['type', 'data'],
props: {
type: {
type: String,
},
data: {
type: Array,
default() {
return [];
}
},
value: {
type: Array,
default() {
return [];
}
},
},
data() {
return {
isVisible: false
isVisible: false,
subType: this.type,
currentValue: this.value,
currentData: this.data
};
},
watch: {
value(val) {
this.currentValue = val;
},
type(val) {
if (this.currentData.length) {
this.subType = val;
}
},
data(val) {
if (!this.subType) {
this.subType = this.type;
}
this.currentData = val;
},
},
methods: {
selectItem() {
this.hide();
return true;
selectItem(params) {
this.$emit('select', params);
},
clear() {
this.currentValue = [];
this.$emit('select', {
value: this.currentValue,
subType: this.type
});
},
hide() {
this.isVisible = false;
... ... @@ -55,43 +110,61 @@
&.filter-sub-open {
transform: translate3d(0, 0, 0);
box-shadow: 0 0 10px 0 #ccc;
}
.btn-clear {
font-size: 32px;
width: 100px;
}
}
.filter-detail {
$w: 30px;
list-style: none;
margin: 0;
padding: 0;
font-size: 40px;
color: $grey;
-webkit-overflow-scrolling: touch;
overflow: scroll;
height: 100%;
.item,
.index {
margin-left: $w;
margin-right: $w;
border-bottom: 1px solid #eee;
color: #000;
font-size: 28px;
padding-left: 30px;
padding-right: 30px;
}
.index {
font-size: 32px;
font-weight: bold;
color: $black;
height: 60px;
line-height: 60px;
}
.item.active .item-inner {
color: $black;
height: 62px;
line-height: 62px;
background-color: #f6f6f6;
}
.item-inner {
margin-left: -$w;
margin-right: -$w;
padding: 0 $w;
font-size: 34px;
height: 102px;
line-height: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.item {
height: 82px;
line-height: 82px;
display: flex;
border-bottom: solid 1px #eee;
&.active {
.item-check {
display: block;
}
}
.item-inner {
flex: 1;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.item-check {
width: 62px;
display: none;
i {
font-weight: bold;
}
}
}
}
... ... @@ -110,7 +183,7 @@
.filter-detail {
height: 100%;
overflow: auto;
-webkit-overflow-scrolling : touch;
-webkit-overflow-scrolling: touch;
}
.filter-sort {
... ... @@ -118,9 +191,11 @@
margin-top: 0;
height: 100%;
}
.content {
height: 100% !important;
}
.sub-level-container {
overflow: auto;
}
... ...
<template>
<div class="filter-detail">
<div class="item">
<div class="item-inner" @click="select({id:''})">{{type | filter-cn '所有'}}</div>
</div>
<div class="item" v-for="item in data" :class="{active: item.id === val}" @click="select(item)">
<div class="item" v-for="item in currentData" :key="item.id" :class="{active: item.checked}" @click="select(item)">
<div class="item-inner">
{{item.name}}
</div>
<div class="item-check">
<i class="icon icon-check"></i>
</div>
</div>
<slot></slot>
</div>
</template>
<script>
module.exports = {
props: ['data', 'type', 'val'],
computed: {},
props: {
data: {
type: Array,
default() {
return [];
}
},
value: {
type: Array,
default() {
return [];
}
},
type: {
type: String
}
},
data() {
return {
currentData: [],
currentValue: this.value,
subType: this.type
};
},
created() {
this.renderData();
},
watch: {
value(val) {
this.currentValue = val;
this.renderData();
}
},
methods: {
select: function(val) {
this.$dispatch('select', val);
let itemIndex = this.currentValue.findIndex(item => item.id === val.id);
if (itemIndex >= 0) {
this.currentValue.splice(itemIndex, 1);
} else {
this.currentValue.push({
id: val.id,
name: val.name
});
}
this.$emit('select', {
value: this.currentValue,
subType: this.subType
});
},
renderData() {
this.currentData = this.data.map(item => {
return {
id: item.id,
name: item.name,
checked: this.currentValue.some(val => val.id === item.id)
};
});
}
}
};
... ...
<template>
<ul class="list-box">
<li v-for="item in items"><a class="no-intercept" href="#{{item.index}}">{{item.name}}</a></li>
<li v-for="item in items" :key="item.name"><a class="no-intercept" href="#{{item.index}}">{{item.name}}</a></li>
</ul>
</template>
<style>
... ... @@ -62,6 +62,8 @@
index: '0~9',
name: '#'
});
} else {
this.items = this.indexList;
}
}
};
... ...
<template>
<div>
<filter-sub :value="valueData" :type="subType" :data="filterData" v-ref:filter-sub @select="selected"></filter-sub>
<button @click="open('group_sort')"><h2>品类</h2></button>
<button @click="open('brand')"><h2>品牌</h2></button>
<button @click="open('color')"><h2>颜色</h2></button>
<div>品类:<span v-for="item in values.group_sort" :key="item.id">{{item.name}}&nbsp;</span></div>
<div>品牌:<span v-for="item in values.brand" :key="item.id">{{item.name}}&nbsp;</span></div>
<div>颜色:<span v-for="item in values.color" :key="item.id">{{item.name}}&nbsp;</span></div>
</div>
</template>
<script>
const $ = require('jquery');
const filterSub = require('component/product/filter/filter-sub.vue');
module.exports = {
data() {
return {
filterConfig: {},
subType: '',
values: {
group_sort: [],
brand: [],
color: [],
}
};
},
computed: {
filterData() {
return this.filterConfig ? this.filterConfig[this.subType] : {};
},
valueData() {
return this.values && this.values[this.subType];
}
},
created() {
$.get('/product/new.json').then(config => {
this.filterConfig = config.data.filter;
});
},
methods: {
open(subType) {
this.subType = subType;
this.$refs.filterSub.isVisible = true;
},
selected(params) {
this.values[params.subType] = params.value;
console.log(this.values);
}
},
components: {
filterSub
}
};
</script>
<style>
</style>
... ...
... ... @@ -4,6 +4,7 @@
<i v-if="isiOS" class="icon icon-filter" slot="right" @touchstart="openFilter"></i>
<i v-else class="icon icon-filter" slot="right" @click="openFilter"></i>
</cheader>
<demo></demo>
<List :data="productList" :state="listState"></List>
<Filter :config="filterConfig" action="/product/list.json" v-ref:filter></Filter>
</div>
... ... @@ -20,6 +21,7 @@
const cheader = require('component/header.vue');
const list = require('component/product/list.vue');
const filter = require('component/product/filter.vue');
const demo = require('./demo.vue');
let locationQuery = qs(decodeURIComponent(location.search.replace(/^\?/, '')));
... ... @@ -70,7 +72,8 @@
components: {
cheader,
list,
filter
filter,
demo
},
methods: {
search: function() {
... ...