因此,经过大约2-3周的阅读,尝试简单的例子,并在VueJs中采取婴儿步骤,尝试更复杂的用例,我被卡住了。
创建一个基本搜索方法,按标题过滤数据,并以3列网格布局迭代返回结果。
现在我需要让这个东西可以重复使用。
当然,'暴力'方式是为每个内容数组编写一种过滤方法。但实际上,我只是一个VueJs noob谁知道(2)是可能的,不能编码。
提前感谢任何指示。
HTML
<div id="app">
<h2>Search</h2>
<div><input type="text" v-model="searchString" placeholder="Search" /></div>
<section id="section1">
<div class="row" v-for="i in rowCount" :key="i.id">
<div v-for="content in filtered1(i)" :key="content.id" class="one-third">
<img :src="content.image" class="center-block" />
<h3>{{content.title}}</h3>
<p class="m-t-content tablet">{{content.description}}</p>
<p class="m-t-content mobile-center tablet"><a :href="content.url">Read more</a></p>
</div>
</div>
</section>
<section id="section2">
</section>
</div>
JS
new Vue({
el: "#app",
data () {
return {
searchString: '',
itemsPerRow: 3,
contents1: [
{
'title': 'Android',
'url': '/',
'description': 'Lorem ipsum dolor sit amet.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/android-icon.png'
},
{
'title': 'Pinterest',
'url': '/',
'description': 'Consectetur adipiscing elit.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/pinterest-icon.png'
},
{
'title': 'Behance',
'url': '/',
'description': 'Pellentesque pulvinar nisi.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/behance-icon.png'
},
{
'title': 'Evernote',
'url': '/',
'description': 'Id tincidunt orci elementum.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/evernote-icon.png'
},
{
'title': 'Github',
'url': '/',
'description': 'Lorem ipsum dolor sit amet.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/github-icon.png'
}
]
}
},
computed: {
rowCount: function () {
return Math.ceil(this.contents1.length / this.itemsPerRow)
}
},
methods: {
filtered1: function (index) {
var contentsArray = this.contents1
var searchString = this.searchString
if (!searchString) {
return contentsArray.slice((index - 1) * this.itemsPerRow, index * this.itemsPerRow)
}
searchString = searchString.trim().toLowerCase()
contentsArray = contentsArray.filter(function (item) {
if (item.title.toLowerCase().indexOf(searchString) !== -1) {
return item
}
})
return contentsArray.slice((index - 1) * this.itemsPerRow, index * this.itemsPerRow)
}
}
})
CSS
body {
background: #fff;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
h3 {
font-weight: bold;
margin-bottom: 5px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
.one-third {
box-sizing: border-box;
float: left;
margin: 0 1%;
width: 31.33%;
}
.row {
margin: 10px 0;
}
.row:after {
content: "";
display: table;
clear: both;
}
答案 0 :(得分:2)
一个非常简单的实现方法是将您的Vue转换为一个组件,并将每个渲染元素的内容暴露给一个插槽,以便父级可以设置自定义内容。
这是我的意思的一个例子。
console.clear()
Vue.component("filtered", {
template: `
<div>
<h2>Search</h2>
<div><input type="text" v-model="searchString" placeholder="Search" /></div>
<section>
<div class="row" v-for="i in rowCount" :key="i">
<div v-for="content in filtered.slice(itemsPerRow * (i - 1), itemsPerRow * i)" :key="content[keyColumn]" class="one-third">
<slot :content="content" />
</div>
</div>
</section>
</div>
`,
props: ["contents", "itemsPerRow", "filterColumns", "keyColumn"],
data(){
return {
searchString: ''
}
},
computed: {
rowCount: function () {
return Math.ceil(this.filtered.length / this.itemsPerRow)
},
filtered(){
let results = this.contents
if (!this.searchString)
return results
let searchString = this.searchString.toLowerCase()
return results.filter(item => {
for (let column of this.filterColumns)
if (item[column].toLowerCase().includes(searchString))
return true
return false
})
}
},
})
new Vue({
el: "#app",
data () {
return {
records:[
{
name: "Dark Side of the Moon",
artist: "Pink Floyd"
},
{
name: "Wish You Were Here",
artist: "Pink Floyd",
},
{
name: "The Joshua Tree",
artist: "U2"
}
],
contents1: [
{
'title': 'Android',
'url': '/',
'description': 'Lorem ipsum dolor sit amet.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/android-icon.png'
},
{
'title': 'Pinterest',
'url': '/',
'description': 'Consectetur adipiscing elit.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/pinterest-icon.png'
},
{
'title': 'Behance',
'url': '/',
'description': 'Pellentesque pulvinar nisi.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/behance-icon.png'
},
{
'title': 'Evernote',
'url': '/',
'description': 'Id tincidunt orci elementum.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/evernote-icon.png'
},
{
'title': 'Github',
'url': '/',
'description': 'Lorem ipsum dolor sit amet.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/github-icon.png'
}
]
}
},
})
&#13;
body {
background: #fff;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
h3 {
font-weight: bold;
margin-bottom: 5px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
.one-third {
box-sizing: border-box;
float: left;
margin: 0 1%;
width: 31.33%;
}
.row {
margin: 10px 0;
}
.row:after {
content: "";
display: table;
clear: both;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<filtered :contents="records" :items-per-row="2" :filter-columns="['name']" :key-column="'name'">
<template slot-scope="{content}">
<h4>{{content.name}}</h4>
</template>
</filtered>
<filtered :contents="contents1" :items-per-row="3" :filter-columns="['title', 'description']" :key-column="'title'">
<template slot-scope="{content}">
<img :src="content.image" class="center-block" />
<h3>{{content.title}}</h3>
<p class="m-t-content tablet">{{content.description}}</p>
<p class="m-t-content mobile-center tablet"><a :href="content.url">Read more</a></p>
</template>
</filtered>
</div>
&#13;
根据评论中的进一步讨论,您可以使用以下公共搜索字符串:
console.clear()
Vue.component("filtered", {
props: ["contents","itemsPerRow", "filterColumns", "keyColumn", "searchString"],
template: `
<section>
<div class="row" v-for="i in rowCount" :key="i">
<div v-for="content in filtered.slice(itemsPerRow * (i - 1), itemsPerRow * i)" :key="content[keyColumn]" class="one-third">
<slot :content="content" />
</div>
</div>
</section>
`,
computed: {
rowCount: function () {
return Math.ceil(this.filtered.length / this.itemsPerRow)
},
filtered(){
let results = this.contents
if (!this.searchString)
return results
let searchString = this.searchString.toLowerCase()
return results.filter(item => {
for (let column of this.filterColumns)
if (item[column].toLowerCase().includes(searchString))
return true
return false
})
}
},
})
new Vue({
el: "#app",
data () {
return {
searchString: '',
records:[
{
name: "Dark Side of the Moon",
artist: "Pink Floyd"
},
{
name: "Wish You Were Here",
artist: "Pink Floyd",
},
{
name: "The Joshua Tree",
artist: "U2"
}
],
contents1: [
{
'title': 'Android',
'url': '/',
'description': 'Lorem ipsum dolor sit amet.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/android-icon.png'
},
{
'title': 'Pinterest',
'url': '/',
'description': 'Consectetur adipiscing elit.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/pinterest-icon.png'
},
{
'title': 'Behance',
'url': '/',
'description': 'Pellentesque pulvinar nisi.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/behance-icon.png'
},
{
'title': 'Evernote',
'url': '/',
'description': 'Id tincidunt orci elementum.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/evernote-icon.png'
},
{
'title': 'Github',
'url': '/',
'description': 'Lorem ipsum dolor sit amet.',
'image': 'http://icons.iconarchive.com/icons/danleech/simple/64/github-icon.png'
}
]
}
},
})
&#13;
body {
background: #fff;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
h3 {
font-weight: bold;
margin-bottom: 5px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
.one-third {
box-sizing: border-box;
float: left;
margin: 0 1%;
width: 31.33%;
}
.row {
margin: 10px 0;
}
.row:after {
content: "";
display: table;
clear: both;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<h2>Search</h2>
<div><input type="text" v-model="searchString" placeholder="Search" /></div>
<filtered :contents="records"
:items-per-row="2"
:filter-columns="['name']"
:key-column="'name'"
:search-string="searchString">
<template slot-scope="{content}">
<h4>{{content.name}}</h4>
</template>
</filtered>
<filtered :contents="contents1"
:items-per-row="3"
:filter-columns="['title', 'description']"
:key-column="'title'"
:search-string="searchString">
<template slot-scope="{content}">
<img :src="content.image" class="center-block" />
<h3>{{content.title}}</h3>
<p class="m-t-content tablet">{{content.description}}</p>
<p class="m-t-content mobile-center tablet"><a :href="content.url">Read more</a></p>
</template>
</filtered>
</div>
&#13;
答案 1 :(得分:0)
检查一下!
一个基于VUEJS的非常简单而强大的网格,该示例与ASP.NET MVC相结合
https://github.com/Dariush-Tasdighi/LEARNING_VUE
Learn_1000操作和视图具有过滤器!