# 搜索功能的简单实现

# 对象定义:

记录所有标签的数组

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
更新时间: 7/4/2021, 10:56:16 PM