# 搜索功能的简单实现
# 对象定义:
记录所有标签的数组
tags(标签集合):[tag,tag,tag...]
tag(单个标签):{
id(标签ID,从0计数): Number,
label(标签名): String,
posts(记录拥有该标签的帖子的id): [Num,Num,Num],(post.ID,post.ID,post.ID...)
// 默认为空!
}
记录所有帖子的数组
allPosts(所有帖子):[post,post,post...]
post(单个帖子):{
id(帖子ID,从0计数): Num,
classical(所属分类,从0计数): Num,
tag(所拥有标签的ID): [Num,Num...], (tag.id,tag.id,tag.id...)
title(标题): String,
BI(brief introduction 简介的缩写): String,
updataUserID(上传者ID): Num,
updataDate(上传日期): String,
updataTime(上传时间): String,
url(帖子链接): String
}
classicals(分类集):[
{
id(分类id):0...8(0-3图文\4-7视听\8论坛帖子)
label(分类名): String
}
]
记录用户输入用于搜索的内容,传输给搜索结果页
searchForm(搜索表单):{
option: Num(0-4),
// 用户选择的搜索范围
content: String
// 用户输入的搜索内容
}
记录所有用户的信息:
allUsers:[user,user,user...]
单个用户的信息:
user:[id:Num,name:String,postID:[post.id,post.id,post.id...]]
临时存储所有帖子的tagID的数组
tempTagList:[[tag,id],[tag.id,tag.id...],[...]...]
临时存储所有匹配项的数组
tempSortList:[post.id,post.id,post.id]
存储筛选之后剩下的帖子的数组
allPostsExcluded
# 实现思路:
# 1.当搜索页点击 "搜索"按钮时,且搜索表单(searchForm)不为空时,向 搜索结果页(searchResultPage) 跳转,并传输 搜索表单
通过命名路由向 搜索结果页 发送参数
this.$router.push({name:'searchResultPage',params:{参数名:参数值}})
结果页 获取参数
this.$router.params.参数名
该方法需要在路由配置中给路由配置name
考虑到需要支持刷新之后所传递的参数不会丢失……但是目前也不知道该如何操作……
以下内容已经废弃! 需要注意的是,query传参的参数会在浏览器地址栏上显示出参数,实际上也是一开始因为这个不太美观导致我直接选择了params
this.router.push({path:'地址',query:{参数名:参数值}})
获取参数
this.$router.query.参数名
# 2.将帖子数据按照tag分类
tempTagList 用于临时存储所有帖子的tagID,得到的是一个嵌套数组(二维数组):如: tempTagList = [[2],[2,3],[3,7,8]...]
let tempTagList = allPosts.map(post => post.tag)
此处获得的嵌套数组,或得到了所有帖子的tagID 接下来判断这个帖子所属的标签,并且将这个帖子的ID存入tag.posts
for(i=0; i<tempTagList.length; i++) {
for(j=0;j<tempTagList[i].length;j++){
tags[tempTagList[i][j]].posts.push(i)
}
}
# 3.将 searchForm 中的 content 与 tags中的label匹配
如果匹配,则将该 tag 中 post 属性 存储的 postID 存储于 用于临时保存所有匹配项的数组 tempSortList[], 且用于标记该postID是否多次录入的数组 postSortCount[post.id]++ if postSortCount[post.ID] == 1,则表示该帖子已经记录,不再进行录入
let postSortCount = []
for(let n = 0; n<allPosts.length;n++){
postSortCount[n]=0;
}
(tags.filter(tag => searchForm.content.toLowerCase().indexOf(tag.label.toLowerCase())!== -1)).map(tag => tag.posts).forEach(post=>post.forEach(postID=>{
if( postSortCount[postID]==0){
postSortCount[postID]++;
tempSortList.push(postID);
}
}))
# 代码分解
let postSortCount = []
for(...){...}
这里是对用于标记某个post是否已经录入的数组进行初始化操作
tags.filter(tag => searchForm.content.toLowerCase().indexOf(tag.label)!== -1)
这一段代码 是实现 对tags 中 单个tag的label进行匹配后的筛选 Str1.indexOf(src2),是实现对两个字符串的对比,如果两个字符串src2在src1中没有出现,则会返回-1 筛选出来的就是符合条件的tag了,但是这个时候得到的是一个 对象数组,要把对象数组中单个对象提取出来,并且把里面的属性提取出来需要进行下一步操作
.map(tag => tag.posts)
将对象数组变成了一个嵌套数组,存储的是 符合匹配 的标签里 所存储的帖子ID数组,可见第二步操作 接下来要把这个嵌套数组抹平,提取到每个posts中的每个id
.forEach(posts=>posts.forEach(postID=>))
遍历嵌套,即可获得单个post的ID了 接下来就是判断这个ID是否已经被录入了,如果否则录入,且录入标记
# 4.将allPosts 中 已经存储的帖子排除
考虑到以下原因: 之后会将 searchForm.content 与 post.title 、 post.BI 进行匹配 因为字符串之间的匹配进行的遍历次数更多,时间复杂度更高,且post.BI的字符串长度偏长,优先排除掉已经 被匹配的post 被列入了步骤之中 将用 allPostsExcluded 来存储排除之后的数组
let allPostsExcluded = allPosts.filter(post => postSortCount[post.id] === 0)
# 5.将剩余的帖子的title、BI 与 search.content 进行匹配
使用的方法依旧是 filter() 和 indexOf(), 同时,我们依旧将匹配到的帖子的ID存入 tempSortList
allPostsExclude.filter(post => (post.title.toLowerCase().indexOf(searchForm.content.toLowerCase()) !== -1) || (post.BI.toLowerCase().indexOf(searchForm.content.toLowerCase()) !== -1)).forEach(post => {
postSortCount[post.id]++
tempSortList.push(post.id)
})
为什么不可以下面这样?
tempSortList.push(allPostExclude.filter(...).map(post=>{postSortCount[post.id]++; return post.id}))
原因很简单,allPostExclude.filter.map之后,得到的是一个数组,而tempSortList本身已经是数组,push之后的结果变成了数组嵌套
一个小吐槽:因为记错知识点的问题,我一度以为javascript的数组也可以像我不记得哪个语言那样子可以直接数组相加,所以我试了无数次 tempSortList+.... 数组相加得到的实际上是一串字符串,typeof出来的是String
# 6.重复4的操作,将已经存储的帖子再次排除掉
allPostExclude = allPostExclude.filter(post => postSortCount[post.id]===0)
# 7.检索匹配的用户名
let userRetrieval = allUsers.filter(user => user.name.indexOf(searchForm.content)!== -1)
// userRetrieval:[user,user,user...]
// user: {id:Num,name:string,posts:[...]}
# 8.将符合条件的用户的帖子存入tempSortList
userRetrieval.forEach(user => user.posts.forEach(postID => if(postSortCount[postID] === 0){postSortCount[postID]++;tempSortList.push(postID)}))
# 9.将筛选得到的结果序列进行从大到小排序,以优先输出最新的帖子
因为 id 偏后的帖子意味着更新
tempSortList = tempSortList.sort((a,b) => b-a)
# 10.得到所有检索的结果
let allSearchResult = tempSortList.map(n => allPosts[n])
# 11.根据所选项目(search.option)输出结果
case(0): outPutSearchResult = allSearchResult
case(1): outPutSearchResult = allSearchResult.filter(post=>post.classical<4)
case(2): outPutSearchResult = allSearchResult.filter(post=>post.classical>=4&&post.classical<8)
case(3): outPutSearchResult = allSearchResult.filter(post=>post.classical==8)
case(4): outPutSearchResult = userRetrieval