1.创建组件并配置路由

1、创建 src/views/search/index.vue

<template><div class="search-container">搜索页面</div>
</template><script>export default {name: "SearchPage",components: {},props: {},data() {return {};},computed: {},watch: {},created() {},methods: {}};
</script><style scoped></style>

2、把搜索页面的路由配置到根组件路由(一级路由)

{path: '/search',name: 'search',component: () =>import ('@/views/search')}

3.为首页的搜索按钮添加to属性,实现路径跳转

 <van-buttonclass="search-btn"slot="title"type="info"size="small"roundicon="search"to="/search">搜索</van-button>

2.页面布局

1.创建 src/views/search/components/search-history.vue(使用cell组件)

<template><div class="search-history"><van-cell title="搜索历史"><span>全部删除</span><span>完成</span><van-icon name="delete" /></van-cell><van-cell title="hello"><van-icon name="close" /></van-cell><van-cell title="hello"><van-icon name="close" /></van-cell><van-cell title="hello"><van-icon name="close" /></van-cell><van-cell title="hello"><van-icon name="close" /></van-cell></div>
</template><script>
export default {name: 'SearchHistory',components: {},props: {},data () {return {}},computed: {},watch: {},created () {},mounted () {},methods: {}
}
</script><style scoped lang="less"></style>

2.创建 src/views/search/components/search-suggestion.vue(使用cell组件)

<template><div class="search-suggestion"><van-cell title="黑马程序员..." icon="search"></van-cell><van-cell title="黑马程序员..." icon="search"></van-cell><van-cell title="黑马程序员..." icon="search"></van-cell><van-cell title="黑马程序员..." icon="search"></van-cell><van-cell title="黑马程序员..." icon="search"></van-cell></div>
</template><script>
export default {name: 'SearchSuggestion',components: {},props: {},data () {return {}},computed: {},watch: {},created () {},mounted () {},methods: {}
}
</script><style scoped lang="less"></style>

3.创建 src/views/search/components/search-result.vue(使用list组件)

<template><div class="search-result"><van-listv-model="loading":finished="finished"finished-text="没有更多了"@load="onLoad"><van-cell v-for="item in list" :key="item" :title="item" /></van-list></div>
</template><script>
export default {name: 'SearchResult',components: {},props: {},data () {return {list: [],loading: false,finished: false}},computed: {},watch: {},created () {},mounted () {},methods: {onLoad () {// 异步更新数据// setTimeout 仅做示例,真实场景中一般为 ajax 请求setTimeout(() => {for (let i = 0; i < 10; i++) {this.list.push(this.list.length + 1)}// 加载状态结束this.loading = false// 数据全部加载完成if (this.list.length >= 40) {this.finished = true}}, 1000)}}
}
</script><style scoped lang="less"></style>

4.搜索组件(search组件):

取消按钮注册onCancel事件,调用this.$router.back()方法返回页面上一级

<template><div class="search-container"><!-- 搜索栏 --><!--Tips: 在 van-search 外层增加 form 标签,且 action 不为空,即可在 iOS 输入法中显示搜索按钮--><form action="/"><van-searchv-model="searchText"show-actionplaceholder="请输入搜索关键词"background="#3296fa"@search="onSearch"@cancel="onCancel"/></form><!-- /搜索栏 --><!-- 搜索历史记录 --><search-history /><!-- /搜索历史记录 --><!-- 联想建议 --><search-suggestion /><!-- /联想建议 --><!-- 历史记录 --><search-result /><!-- /历史记录 --></div>
</template><script>
import SearchHistory from './components/search-history'
import SearchSuggestion from './components/search-suggestion'
import SearchResult from './components/search-result'export default {name: 'SearchIndex',components: {SearchHistory,SearchSuggestion,SearchResult},props: {},data () {return {searchText: ''}},computed: {},watch: {},created () {},mounted () {},methods: {onSearch (val) {console.log(val)},onCancel () {this.$router.back()}}
}
</script><style scoped lang="less">
.search-container {.van-search__action {color: #fff;}
}
</style>

3.处理页面显示状态

1、在 data 中添加数据用来控制搜索结果的显示状态

data () {...isResultShow: false
}

2.在模板中绑定条件渲染

<!-- 搜索结果 -->
<search-result v-if="isResultShow" />
<!-- /搜索结果 --><!-- 联想建议 -->
<search-suggestion v-else-if="searchText" />
<!-- /联想建议 --><!-- 搜索历史记录 -->
<search-history v-else />
<!-- /搜索历史记录 -->

4.搜索联想建议 

当搜索框输入内容的时候,请求加载联想建议的数据,并将请求得到的结果绑定到模板中

一、将父组件中搜索框输入的内容传给联想建议子组件

二、在子组件中监视搜索框输入内容的变化,如果变化则请求获取联想建议数据

2.1封装联想建议的请求方法(search.js):

/*** 用户相关请求模块*/
import request from '@/utils/request'export const getSearchSuggestions = q => {return request({method: 'GET',url: '/v1_0/suggestion',params: {q}})
}
<script>
import { getSearchSuggestions } from '@/api/search'export default {name: 'SearchSuggestion',components: {},props: {searchText: {type: String,required: true}},data () {return {suggestions: [], // 联想建议数据列表}},computed: {},watch: {searchText: {// 当 searchText 发生改变的时候就会调用 handler 函数// 注意:handler 函数名称是固定的handler (value) {this.loadSearchSuggestions(value)},immediate: true // 该回调将会在侦听开始之后被立即调用}},created () {},mounted () {},methods: {async loadSearchSuggestions (q) {try {const { data } = await getSearchSuggestions(q)this.suggestions = data.data.options} catch (err) {this.$toast('数据获取失败,请稍后重试')}},}
}
</script>

三、将获取到的联想建议数据展示到列表中

 <van-cellicon="search"v-for="(text, index) in suggestions":key="index"></van-cell>

5.联想建议优化——防抖

第三方包:lodash

1、安装 lodash

2、防抖处理

// lodash 支持按需加载,有利于打包结果优化
import { debounce } from "lodash"
// debounce 函数
// 参数1:函数
// 参数2:防抖时间
// 返回值:防抖之后的函数,和参数1功能是一样的
handler: debounce(function (value) {this.loadSearchSuggestions(value)}, 200),// handler (value) {//   this.loadSearchSuggestions(value)// },immediate: true // 该回调将会在侦听开始之后被立即调用}

6.联想建议优化——搜索关键字高亮

 保证不修改原始数据!!

data () {return {htmlStr: 'Hello <span style="color: red">World</span>'}
}
<div>{{ htmlStr }}</div>
<div v-html="htmlStr"></div>

双花括号绑定会直接输出纯文本内容 : <div>{{ htmlStr }}</div> 

使用 v-html 指令可以绑定渲染带有 HTML 标签的字符串 :<div v-html="htmlStr"></div> 

使用插槽:

    <van-cellicon="search"v-for="(text, index) in suggestions":key="index"><div slot="title" v-html="highlight(text)"></div></van-cell>
 highlight (text) {const highlightStr = `<span class="active">${this.searchText}</span>`// 正则表达式 // 中间的内容都会当作匹配字符来使用,而不是数据变量// 如果需要根据数据变量动态的创建正则表达式,则手动 new RegExp// RegExp 正则表达式构造函数//    参数1:匹配模式字符串,它会根据这个字符串创建正则对象//    参数2:匹配模式,要写到字符串中const reg = new RegExp(this.searchText, 'gi')return text.replace(reg, highlightStr)}

bug:// 正则表达式 // 中间的内容都会当作匹配字符来使用,而不是数据变量
      // 如果需要根据数据变量动态的创建正则表达式,则手动
new RegExp


7.搜索结果

一、获取搜索关键字

1、为搜索建议添加点击按钮,将选中的建议传入父组件的搜索框(子传父)

@click="$emit('search', text)"

父组件:

<van-searchv-model="searchText"show-actionplaceholder="请输入搜索关键词"background="#3296fa"@search="onSearch"@cancel="onCancel"@focus="isResultShow = false"/>
onSearch(val) {// 更新文本框内容this.searchText = val// 渲染搜索结果this.isResultShow = true},  

2、父组件给子组件(搜索结果)传递数据(父传子)

<!-- 搜索结果 -->
<search-result v-if="isResultShow" :q="searchText" />
<!-- /搜索结果 -->
props: {q: {type: String,require: true}
},

二、请求获取数据

1、在 api/serach.js添加封装获取搜索结果的请求方法

/*** 获取搜索结果*/
export function getSearch(params) {return request({method: "GET",url: "/app/v1_0/search",params})
}

2、请求获取

+ import { getSearch } from '@/api/search'export default {name: 'SearchResult',components: {},props: {q: {type: String,require: true}},data () {return {list: [],loading: false,finished: false,
+      page: 1,
+      perPage: 20}},computed: {},watch: {},created () {},mounted () {},methods: {
+++    async onLoad () {// 1. 请求获取数据const { data } = await getSearch({page: this.page, // 页码per_page: this.perPage, // 每页大小q: this.q // 搜索关键字})// 2. 将数据添加到列表中const { results } = data.datathis.list.push(...results)// 3. 设置加载状态结束this.loading = false// 4. 判断数据是否加载完毕if (results.length) {this.page++ // 更新获取下一页数据的页码} else {this.finished = true // 没有数据了,将加载状态设置结束,不再 onLoad}}}
}

三、最后,模板绑定

<van-listv-model="loading":finished="finished"finished-text="没有更多了"@load="onLoad"
><van-cell
+    v-for="(article, index) in list"
+    :key="index"
+    :title="article.title"/>
</van-list>

8.历史记录 ——添加历史记录

要求:不要有重复历史记录,最新的排在最前面

1、在 data 中添加一个数据用来存储历史记录

data () {return {...searchHistories: []}
}

2、在触发搜索的时候,记录历史记录

onSearch (val) {// 更新文本框内容this.searchText = val// 存储搜索历史记录// 要求:不要有重复历史记录、最新的排在最前面const index = this.searchHistories.indexOf(val)if (index !== -1) {this.searchHistories.splice(index, 1)}this.searchHistories.unshift(val)// 渲染搜索结果this.isResultShow = true
},

9.历史记录 ——添加历史记录

父传子:

父:

<search-historyv-else:search-histories="searchHistories"/>

子:

<!-- 历史记录 -->
<van-cell-group v-else><van-cell title="历史记录"><van-icon name="delete" /><span>全部删除</span>&nbsp;&nbsp;<span>完成</span></van-cell><van-cell:title="item"v-for="(item, index) in searchHistories":key="index"><van-icon name="close"></van-icon></van-cell>
</van-cell-group>
<!-- /历史记录 -->
 props: {searchHistories: {type: Array,required: true}},

10.历史记录 ——删除

- 给历史记录中的每一项注册点击事件
- 在处理函数中判断
  - 如果是删除状态,则执行删除操作
  - 如果是非删除状态,则执行搜索操作

一、处理删除相关元素的展示状态

1、在 data 中添加一个数据用来控制删除相关元素的显示状态

data () {return {...isDeleteShow: false}
}

2、绑定使用(v-if及v-else)

<!-- 历史记录 -->
<van-cell-group v-else><van-cell title="历史记录"><template v-if="isDeleteShow"><span @click="searchHistories = []">全部删除</span>&nbsp;&nbsp;<span @click="isDeleteShow = false">完成</span></template><van-icon v-else name="delete" @click="isDeleteShow = true"></van-icon></van-cell><van-cell:title="item"v-for="(item, index) in searchHistories":key="index"@click="onSearch(item)"><van-iconv-show="isDeleteShow"name="close"@click="searchHistories.splice(index, 1)"></van-icon></van-cell>
</van-cell-group>
<!-- /历史记录 -->

二、处理删除操作

Prop 数据:Prop 是受父组件数据影响的。

如果是普通数据(数字、字符串、布尔值)绝对不能修改,即便改了也不会传导给父组件

如果是引用类型数据(数组、对象)可以修改,例如 [].push(xxx),对象.xxx = xxx,不能重新赋值, xxx = []

解决bug:让父组件删除!!!

子:<span @click="$emit('clear-search-histories')">全部删除</span>

父:

<search-historyv-else:search-histories="searchHistories"@clear-search-histories="searchHistories = []"/>

<!-- 历史记录 -->
<van-cell-group v-else><van-cell title="历史记录"><template v-if="isDeleteShow">
+      <span @click="searchHistories = []">全部删除</span>&nbsp;&nbsp;<span @click="isDeleteShow = false">完成</span></template><van-icon v-else name="delete" @click="isDeleteShow = true" /></van-cell><van-cell:title="item"v-for="(item, index) in searchHistories":key="index"
+    @click="onHistoryClick(item, index)"><van-icon v-show="isDeleteShow" name="close"></van-icon></van-cell>
</van-cell-group>
<!-- /历史记录 -->
onHistoryClick (item, index) {// 如果是删除状态,则执行删除操作if (this.isDeleteShow) {this.searchHistories.splice(index, 1)} else {// 否则执行搜索操作this.onSearch(item)}
}

11.历史记录 ——数据持久化

1、利用 watch 监视统一存储数据

watch: {searchHistories (val) {// 同步到本地存储setItem('serach-histories', val)}
},

2、初始化的时候从本地存储获取数据

data () {return {...searchHistories: getItem('serach-histories') || [],}
}

仿今日头条项目——首页(文章搜索)相关推荐

  1. 仿今日头条项目——首页(展示文章列表)

    1.头部导航栏组件 1.使用导航栏组件 2.在导航栏组件中插入按钮 <template><div class="home-container"><!- ...

  2. 仿今日头条项目——首页(频道编辑)

    1.频道编辑组件 1.1处理页面弹出层 在 data中添加一个数据用来控制弹层的显示和隐藏,然后在首页模板中的频道列表后面添加弹出层组件 data () {return {...isChannelEd ...

  3. 仿今日头条项目——文章详情

    1.创建组件并配置路由 1.创建 views/article/index.vue 组件 <template><div class="article-container&qu ...

  4. vue 仿今日头条_vue实现仿今日头条首页选项卡的功能 -

    ...的 Web 界面.当和其它网络工具配合使用时,Vue.js 的优秀功能会得到大大加强.如今,已有许多开发人员开始使用 Vue.js 来取代 Angular 和 React.js .那么对于 An ...

  5. android如何展示富文本_android高仿今日头条富文本编辑(发布文章)

    前言: 在经历了几个月的项目期限.我们遇到了前端发布文章,要用到富文本编辑的功能.在一番衡量下最终用到了richeditor-android第三方框架.实现原理就是通过webView和js实现前端富文 ...

  6. android 上下滚动文字_android高仿今日头条富文本编辑(发布文章)

    前言 在经历了几个月的项目期限.我们遇到了前端发布文章,要用到富文本编辑的功能.在一番衡量下最终用到了[richeditor-android](https://github.com/wasabeef/ ...

  7. android 仿写开发者头条,android高仿今日头条富文本编辑(发布文章)

    前言: 在经历了几个月的项目期限.我们遇到了前端发布文章,要用到富文本编辑的功能.在一番衡量下最终用到了richeditor-android第三方框架.实现原理就是通过webView和js实现前端富文 ...

  8. Android仿今日头条的开源项目

    起因 看到众多大神纷纷有了自己的开源项目,于是自己琢磨着也想做一个开源项目来学习下,因为每次无聊必刷的app就是今日头条,评论简直比内容都精彩,所以我打算仿今日头条来练练手,期间也曾放弃过,也遇到很多 ...

  9. Android仿今日头条开源项目

    起因 看到众多大神纷纷有了自己的开源项目,于是自己琢磨着也想做一个开源项目来学习下,因为每次无聊必刷的app就是今日头条,评论简直比内容都精彩,所以我打算仿今日头条来练练手,期间也曾放弃过,也遇到很多 ...

最新文章

  1. 机房管理系列之文件服务器管理
  2. 史上最大中文知识图谱,规模达1.4亿,现在开源可下载,还有配套聊天机器人API...
  3. 【译】Introduction to Smart Contract and DApp Security
  4. react实战项目_React实战之React+Redux实现一个天气预报小项目
  5. 虚拟空间独立服务器哪个好,共享虚拟主机和独立哪个好
  6. java se 1335,1335.逼退法王
  7. 第12章 坚持一百秒(《C和C++游戏趣味编程》教学视频)
  8. 自考运筹学第三章课后题
  9. pulseaudio数据流框图
  10. 1-4-05:整数大小比较
  11. 经典的CSS代码(转)
  12. VS studio源代码管理辅助工具sourceoffsite使用过程中的错误解决方法
  13. 酒店客房管理系统源代码 java_《宾馆客房管理系统》JAVA源代码
  14. Linux-发送邮件
  15. Shel脚本-初步入门之《04》
  16. JAVA金额大小写转换
  17. 第2季极客沙龙资料分享 - 知行·前端体验主题交流会
  18. Pytorch实现Bert模型
  19. 如何调试分布式系统:与微服务调试工具“Squash”创始人Idit Levine的对话
  20. win10安装quicktime

热门文章

  1. 国际风筝节开幕 深圳大梅沙上演嫦娥奔月(图)
  2. 决定重新安装windows2016datacenter 系统。原先的俄罗斯版没虚拟机功能
  3. 首批!智领云CTO宋文欣入选“开源GitOps产业联盟技术委员会”成员名单
  4. 【大学物理·早期量子论和量子力学基础】量子力学中的氢原子问题
  5. Windows 10环境下TensorFlow(gpu版本)配置教程——[图解] [详细版][零基础]
  6. XDOJ1184 - 贪心的小白羊
  7. java 异常 中英文_Java异常与错误处理中英文翻译.doc
  8. 天父的花园-赞美之泉(音乐河4)
  9. 波前边缘检测 Wavefront Frontier Detector
  10. 如何开启bios虚拟化