仿今日头条项目——首页(文章搜索)
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> <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> <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> <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.使用导航栏组件 2.在导航栏组件中插入按钮 <template><div class="home-container"><!- ...
- 仿今日头条项目——首页(频道编辑)
1.频道编辑组件 1.1处理页面弹出层 在 data中添加一个数据用来控制弹层的显示和隐藏,然后在首页模板中的频道列表后面添加弹出层组件 data () {return {...isChannelEd ...
- 仿今日头条项目——文章详情
1.创建组件并配置路由 1.创建 views/article/index.vue 组件 <template><div class="article-container&qu ...
- vue 仿今日头条_vue实现仿今日头条首页选项卡的功能 -
...的 Web 界面.当和其它网络工具配合使用时,Vue.js 的优秀功能会得到大大加强.如今,已有许多开发人员开始使用 Vue.js 来取代 Angular 和 React.js .那么对于 An ...
- android如何展示富文本_android高仿今日头条富文本编辑(发布文章)
前言: 在经历了几个月的项目期限.我们遇到了前端发布文章,要用到富文本编辑的功能.在一番衡量下最终用到了richeditor-android第三方框架.实现原理就是通过webView和js实现前端富文 ...
- android 上下滚动文字_android高仿今日头条富文本编辑(发布文章)
前言 在经历了几个月的项目期限.我们遇到了前端发布文章,要用到富文本编辑的功能.在一番衡量下最终用到了[richeditor-android](https://github.com/wasabeef/ ...
- android 仿写开发者头条,android高仿今日头条富文本编辑(发布文章)
前言: 在经历了几个月的项目期限.我们遇到了前端发布文章,要用到富文本编辑的功能.在一番衡量下最终用到了richeditor-android第三方框架.实现原理就是通过webView和js实现前端富文 ...
- Android仿今日头条的开源项目
起因 看到众多大神纷纷有了自己的开源项目,于是自己琢磨着也想做一个开源项目来学习下,因为每次无聊必刷的app就是今日头条,评论简直比内容都精彩,所以我打算仿今日头条来练练手,期间也曾放弃过,也遇到很多 ...
- Android仿今日头条开源项目
起因 看到众多大神纷纷有了自己的开源项目,于是自己琢磨着也想做一个开源项目来学习下,因为每次无聊必刷的app就是今日头条,评论简直比内容都精彩,所以我打算仿今日头条来练练手,期间也曾放弃过,也遇到很多 ...
最新文章
- 机房管理系列之文件服务器管理
- 史上最大中文知识图谱,规模达1.4亿,现在开源可下载,还有配套聊天机器人API...
- 【译】Introduction to Smart Contract and DApp Security
- react实战项目_React实战之React+Redux实现一个天气预报小项目
- 虚拟空间独立服务器哪个好,共享虚拟主机和独立哪个好
- java se 1335,1335.逼退法王
- 第12章 坚持一百秒(《C和C++游戏趣味编程》教学视频)
- 自考运筹学第三章课后题
- pulseaudio数据流框图
- 1-4-05:整数大小比较
- 经典的CSS代码(转)
- VS studio源代码管理辅助工具sourceoffsite使用过程中的错误解决方法
- 酒店客房管理系统源代码 java_《宾馆客房管理系统》JAVA源代码
- Linux-发送邮件
- Shel脚本-初步入门之《04》
- JAVA金额大小写转换
- 第2季极客沙龙资料分享 - 知行·前端体验主题交流会
- Pytorch实现Bert模型
- 如何调试分布式系统:与微服务调试工具“Squash”创始人Idit Levine的对话
- win10安装quicktime
热门文章
- 国际风筝节开幕 深圳大梅沙上演嫦娥奔月(图)
- 决定重新安装windows2016datacenter 系统。原先的俄罗斯版没虚拟机功能
- 首批!智领云CTO宋文欣入选“开源GitOps产业联盟技术委员会”成员名单
- 【大学物理·早期量子论和量子力学基础】量子力学中的氢原子问题
- Windows 10环境下TensorFlow(gpu版本)配置教程——[图解] [详细版][零基础]
- XDOJ1184 - 贪心的小白羊
- java 异常 中英文_Java异常与错误处理中英文翻译.doc
- 天父的花园-赞美之泉(音乐河4)
- 波前边缘检测 Wavefront Frontier Detector
- 如何开启bios虚拟化