长春微信做网站,佛山网站优化排名推广,免费推广软件哪个好一点,网站访问加速器本文将开发一款仿“今日头条”的新闻App。该案例是基于 Vue3.0 Vue Router webpack TypeScript 等技术栈实现的一款新闻资讯类App#xff0c;适合有一定Vue框架使用经验的开发者进行学习。 项目源码在文章末尾
1 项目概述
该项目是一款“今日头条”的新闻资讯App#xf… 本文将开发一款仿“今日头条”的新闻App。该案例是基于 Vue3.0 Vue Router webpack TypeScript 等技术栈实现的一款新闻资讯类App适合有一定Vue框架使用经验的开发者进行学习。 项目源码在文章末尾
1 项目概述
该项目是一款“今日头条”的新闻资讯App主要有以下功能。
新闻分类首页新闻列表刷新加载最新新闻用户私信留言新闻搜索查看新闻详情
1.1 开发环境
本项目是基于Vue3框架开发的一款WebApp使用Vue CLI脚手架工具创建项目。在指定的硬盘目录处启动命令行工具例如在 C:\project 目录下打开命令行工具并执行以下命令。
#安装脚手架
npm i -g vue/cli#创建项目
vue create toutiao项目创建成功后继续在命令行工具中执行 cd toutiao 命令进入项目根目录安装Vant UI组件库和axios模块。执行命令如下
#安装Vant3 UI组件库
npm i vantnext -S#安装axios模块
npm i axios -S项目的调试使用Google Chrome浏览器的控制台进行在浏览器中按下F12键然后单击“切换设备工具栏”进入移动端的调试界面可以选择相应的设备进行调试。 项目运行的效果如图1 所示。 图 1 项目效果图
1.2 项目结构
项目结构如图2所示其中src文件夹是项目的源文件目录src文件夹下的项目结构如图3所示。 图2 项目结构 图3 src文件夹
项目结构中主要文件说明如下。
node_modules项目依赖管理目录。public项目的静态文件存放目录也是本地服务器的根目录。src项目源文件存放目录。package.json项目npm配置文件。vue.config.js项目构建配置文件
src文件夹目录说明如下。
assets静态资源文件存放目。components公共组件存放目录。hooks项目的静态数据和模块封装管理目录。router路由配置文件存放目录。store状态管理配置存放目录。views视图组件存放目录。App.vue项目的根组件。main.ts项目的入口文件。Shims-vue.d.ts typescript的适配定义文件。
2 入口文件
项目的入口文件有 index.html、main.ts和App.vue三个文件这些入口文件的具体内容介绍如下。
2.1 项目入口页面
index.html是项目默认的主渲染页面文件主要用于Vue实例挂载点的声明与DOM渲染。代码如下
!DOCTYPE html
html langheadmeta charsetutf-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0, maximum-scale1.0, minimum-scale1.0, user-scalable0link relicon href% BASE_URL %favicon.icotitle% htmlWebpackPlugin.options.title %/title/headbodynoscriptstrongWere sorry but % htmlWebpackPlugin.options.title % doesnt work properly without JavaScript enabled. Please enable it to continue./strong/noscriptdiv idapp/div!-- built files will be auto injected --/body
/html2.2 程序入口文件
main.ts是程序的入口文件主要用于加载各种公共组件和初始化Vue实例。本项目是基于Vue3开发的在入口文件中引入createApp()来创建vue实例对象。项目中的路由设置和引用的Vant UI组件库也是在该文件中定义的。代码如下
import { createApp } from vue
import App from ./App.vue
import router from ./router
import store from ./store
import Vant from vant;
import vant/lib/index.css;const app createApp(App)
app.use(store)
app.use(router)
app.use(Vant)
app.mount(#app)2.3 组件入口文件
App.vue是项目的根组件所有的页面都是在App.vue下面切换的所有的页面组件都是App.vue的子组件。在App.vue组件内只需要使用 组件作为占位符就可以实现各个页面的引入。代码如下
templaterouter-view/
/template2.4 路由文件
在src/router/index.ts文件中定义了项目的所有跳转的路由代码如下
import { createRouter, createWebHashHistory, RouteRecordRaw } from vue-routerconst routes: ArrayRouteRecordRaw [{path: /,name: Home,component: () import (/views/Home.vue)},{path: /search,name: Search,component: () import (/views/Search.vue)},{path: /details,name: Details,component: () import (/views/Details.vue)},{path: /message,name: Message,component: () import (/views/Message.vue)}
]const router createRouter({history: createWebHashHistory(),routes
})export default router3 项目组件
项目中所有页面组件都在views文件夹中定义所有的公共组件都在components文件夹中定义具体组件内容介绍如下。
3.1 公共组件
在首页新闻列表和新闻内容页中都需要使用到新闻列表的展示为了增强代码的可扩展性可以在components文件夹下创建NewsCard.vue新闻卡片的公共组件。代码如下
templatediv classnews-card clickonClickvan-row gutter20van-col span16div classnews-title{{title}}/divdiv classnews-msgspan{{author}}/spanspan{{date}}/span/div/van-colvan-col span8van-image :srcpic styleheight: 100%template v-slot:error加载失败/template/van-image/van-col/van-row/div
/templatescript
export default {props: {title: String,author: String,date: String,pic: String},setup(props,context) {//新闻点击事件const onClick () {}return {onClick}}
}
/scriptstyle scoped
.news-card{box-sizing: border-box;padding: 0px 10px;
}
.van-row{padding: 15px 0px;border-bottom: 1px solid #F7F7F7;
}
.news-title{color: #222;font-size: 18px;
}
.news-msg{font-size: 12px;color: #999;margin-top: 5px;
}
.news-msg span{margin-right: 8px;
}
/style3.2 首页导航栏
App首页汇集了整个应用的核心功能入口在头部导航栏部分主要涉及了两个功能的入口按钮分别是“私信”和“搜索”。在头部导航栏的下方设计了新闻分类的标签页按钮方便用户切换不同类别的新闻列表。效果如图4所示。 图 4 首页导航栏效果
Home.vue首页组件代码如下
templatediv classpage-body!-- 头部 --van-nav-bar fixed z-index1000template #titlespan classtop-title今日头条/spanvan-icon namereplay color#fff size18//templatetemplate #leftvan-icon nameenvelop-o color#fff size22 //templatetemplate #rightvan-icon namesearch color#fff size22 //template/van-nav-bar!-- 分类导航 --van-tabsv-model:activeactivebackground#F4F5F6stickyoffset-top46title-active-color#EE0A24van-tab v-fortab in tabsList
:keytab.key :titletab.name :nametab.keydiv classtab-views!-- 此处为新闻列表 --/div/van-tab/van-tabs/div
/template新闻类别的标签页数据使用的是本地静态数据在项目中的src/hooks文件夹下创建tabs.ts文件用于保存新闻分类的静态数据。代码如下
const tabs [{key: top,name: 推荐},{key: guonei,name: 国内},{key: guoji,name: 国际},{key: yule,name: 娱乐},{key: tiyu,name: 体育},{key: junshi,name: 军事},{key: keji,name: 科技},{key: caijing,name: 财经},{key: shishang,name: 时尚},{key: youxi,name: 游戏},{key: qiche,name: 汽车},{key: jiankang,name: 健康}
]export default tabs在Home.vue文件中进入src/hooks/tabs.ts文件并设置为响应式数据。代码如下
script langts
import { ref } from vue;
import tabs from ../hooks/tabs;
export default {name: Home,setup() {const tabsList ref(tabs);return {tabsList};},
};
/script3.3 首页新闻列表
首页新闻列表的效果如图5所示。 图5 首页新闻列表效果
在首页中引入NewsCard.vue新闻卡片的公共组件并对axios获取数据进行封装。由于本项目中使用的是“聚合数据平台”的数据接口在请求服务端接口时会出现跨域需要先配置本地服务器的请求代理。 在项目根目录下创建vue.config.js配置文件在配置文件中添加proxy的配置。代码如下
module.exports {devServer: {proxy: {/api: {target: http://v.juhe.cn,changeOrigin: true,pathRewrite: {^/api: }}}}
}封装axios请求方法在src/hooks目录下创建sendhttp.ts文件代码如下
import axios from axios;
import { ref } from vue;
import { Toast } from vant;//聚合数据上申请的用户密钥
const key xxxfunction sendhttp(api: string, query: string) {const result ref(null)//加载数据const getData (query: string, toast?: any) {axios.get(api, {params: {type: query,key}}).then(res {console.log(res.data)result.value res.data.result.dataif(toast){toast.clear()}}).catch(err{if(toast){toast.clear()}})}getData(query)//切换导航事件const tabsChange (name: string) {getData(name)}//刷新事件const replay (name: string) {const toast Toast.loading({message: 加载中...,forbidClick: true,duration: 0,loadingType: spinner,});getData(name,toast)}return {result,tabsChange,replay}
}export default sendhttp在Home.vue文件中引入src/hooks/sendhttp.ts文件并在setup()函数中发送请求将请求成功后的数据遍历在标签页中。 Home.vue文件代码如下
templatediv classpage-body!-- 头部 --van-nav-bar fixed z-index1000 click-leftonClickLeft click-rightonClickRighttemplate #titlespan classtop-title新闻头条/spanvan-icon namereplay color#fff size18 clickreplay //templatetemplate #leftvan-icon nameenvelop-o color#fff size22 //templatetemplate #rightvan-icon namesearch color#fff size22 //template/van-nav-bar!-- 分类导航 --van-tabsv-model:activeactivebackground#F4F5F6stickyoffset-top46title-active-color#EE0A24changetabsChangevan-tab v-fortab in tabsList :keytab.key :titletab.name :nametab.keydiv classtab-viewsnews-card v-fornews in result :keynews.uniquekey :titlenews.title :authornews.author_name:datenews.date:picnews.thumbnail_pic_sclickonClickNews(news.uniquekey)/news-card/div/van-tab/van-tabs/div
/templatescript langts
import { ref } from vue;
import tabs from ../hooks/tabs;
import sendhttp from ../hooks/sendhttp;
import NewsCard from ../components/NewsCard.vue;
import { useRoute, useRouter } from vue-router
export default {name: Home,components: {news-card: NewsCard},setup() {const router useRouter()const active ref(top);const tabsList ref(tabs);//获取新闻数据const {result, tabsChange, replay} sendhttp(/api/toutiao/index,active.value)//导航栏左侧按钮点击事件const onClickLeft () {router.push({path: message})}//导航栏右侧按钮点击事件const onClickRight () {router.push({path: search})}//点击新闻const onClickNews (id:string) {router.push({path: details,query: {id}})}return {active,replay,tabsList,tabsChange,result,onClickLeft,onClickRight,onClickNews};},
};
/scriptstyle scoped
.van-nav-bar {background-color: #d43d3d;
}
.top-title {font-size: 18px;font-weight: bold;color: #fff;margin-right: 5px;
}
.van-tabs{top: 46px;
}
/style3.4 新闻详情页
点击新闻列表触发NewsCard.vue新闻卡片组件上的点击事件通过useRouter路由模块将新闻的id传给Details.vue新闻详情组件。代码如下
templatediv classpage-body!-- 分类导航 --van-tabsv-model:activeactivebackground#F4F5F6stickyoffset-top46title-active-color#EE0A24changetabsChangevan-tab v-fortab in tabsList :keytab.key :titletab.name :nametab.keydiv classtab-viewsnews-card v-fornews in result :keynews.uniquekey :titlenews.title :authornews.author_name:datenews.date:picnews.thumbnail_pic_sclickonClickNews(news.uniquekey)/news-card/div/van-tab/van-tabs/div
/templatescript langts
import NewsCard from ../components/NewsCard.vue;
import { useRoute, useRouter } from vue-router
export default {name: Home,components: {news-card: NewsCard},setup() {const router useRouter()//其他代码...//点击新闻const onClickNews (id:string) {router.push({path: details,query: {id}})}return {onClickNews};},
};
/script在新闻详情页中通过useRoute组件获取参数得到新闻的id并再次发送axios请求获取当前新闻的详细数据。Details.vue组件代码如下
templatediv!-- 导航栏 --van-nav-bar left-arrow fixed click-leftonClickLefttemplate #leftvan-icon namearrow-left size16 color#999 /span stylemargin-left:10px;{{result.author_name}}/span/templatetemplate #rightvan-icon nameshare-o size20 color#999 //template/van-nav-bar!-- 正文 --div classnews-body!-- 新闻标题 --div classnews-title{{result.title}}/div!-- 新闻信息 --div classnews-msgspan{{result.author_name}}/spanspan{{result.date}}/span/div!-- 新闻内容 --div classnews-content v-htmlresult.content/div/div/div
/templatescript
import { ref } from vue;
import { useRoute } from vue-router;
import axios from axios;export default {setup() {const route useRoute();const id route.query.id;const result ref({title:,author_name: ,date: ,content: });//获取请求axios.get(/api/toutiao/content,{params: {uniquekey: id,key: 26dafe8731502872b632b9552feccf06}}).then(res{result.value res.data.result.detail}).catch(err {})//点击导航栏左侧按钮const onClickLeft () {window.history.back();};return {onClickLeft,result};},
};
/scriptstyle scoped
.news-body{margin-top: 60px ;box-sizing: border-box;padding: 0px 15px;
}
.news-title{font-size: 22px;color: #222;font-weight: bold;
}
.news-msg{font-size: 12px;color: #999;margin: 10px 0px 20px;
}
.news-msg span{margin-right: 10px;
}
/style新闻详情页的效果如图6所示。 图6 新闻详情页效果
3.5 私信留言页
点击头部导航栏的左侧图标按钮跳转到私信留言列表页面效果如图7所示。 图7 私信留言列表
Message.vue私信列表组件代码如下
templatediv!-- 导航栏 --van-nav-bartitle私信fixedleft-arrowclick-leftonClickLefttemplate #leftvan-icon namearrow-left size16 color#999 //template/van-nav-bar!-- 留言列表 --div classmessage-listvan-cell v-for(msg,index) in list :keyindex :valuemsg.date!-- 使用 title 插槽来自定义标题 --template #titlevan-badge :dot!msg.readspan classcustom-title{{msg.name}}/span/van-badge/templatetemplate #labelspan classmsg-content{{msg.content}}/span/template/van-cell/div/div
/templatescript
import { ref } from vue;
import messageData from ../hooks/messageData;
export default {setup(){const list ref(messageData)const onClickLeft () {window.history.back()}return {onClickLeft,list}}
}
/scriptstyle scoped
.message-list{margin-top: 50px ;
}
.msg-content{display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow: hidden;
}
/style本项目的私信留言使用的是本地静态数据在src/hooks目录下创建messageData.ts文件用于留言静态数据。代码如下
const messageData [{name: 独上归州,date: 2021-3-18,content: 你好你的那篇文章的链接失效了能不能再重新发布一次,read: false},{name: 椒房殿°,date: 2021-1-8,content: 前端简历的模板发一下吧,read: false},{name: 你在逗我笑i,date: 2020-12-5,content: 你好啊,read: false},{name: 猫与玫瑰 ะ,date: 2020-8-10,content: 你的文章写的很棒啊,read: true},{name: 那只小猪像你,date: 2020-8-1,content: 已转发,read: true},{name: 橙子姑娘,date: 2020-5-11,content: 已转发,read: true},{name: 忽然之间,date: 2020-3-6,content: 点个赞,read: true},{name: 配角戏,date: 2020-1-3,content: 已转发,read: true}
]export default messageData3.6 新闻搜索页面
在首页的头部导航栏点击右侧按钮跳转到新闻搜索页面效果如图8所示。 图 8 新闻搜索也效果
Search.vue新闻搜索组件代码如下
templatediv classsearch!-- 搜索框 --van-searchv-modelkeywordsshaperoundplaceholder请输入你感兴趣的show-actionaction-text搜索cancelonClickRighttemplate #leftvan-icon namearrow-left clickonClickLeft stylemargin-right:10px//template/van-search!-- 搜索记录 --div classsearch-historydiv classsearch-history-titlespan搜索记录/spanvan-icon namedelete-o clickclear //divdivvan-tag v-for(kw,index) in list :keyindex closeable sizemedium typeprimary closedelTag(index){{kw}}/van-tag/div/div/div
/templatescript
import { ref } from vue;
import { Dialog } from vant;
export default {setup() {const keywords ref()const list ref([千锋教育,前端教程])//点击导航栏左侧按钮const onClickLeft () {window.history.back()}//点击导航栏右侧搜索按钮const onClickRight () {list.value.push(keywords.value)console.log(keywords)}//删除搜索记录const delTag (index) {list.value.splice(index,1)}//清空搜索记录const clear () {Dialog.confirm({message: 确定要清空记录吗,}).then(() {list.value []}).catch(() {});}return {keywords,onClickLeft,delTag,clear,onClickRight,list}}
}
/scriptstyle scoped
.van-search{border-bottom: 1px solid #eee;
}
.search-history{box-sizing: border-box;padding: 0px 15px;margin-top: 10px ;
}
.search-history-title{height: 30px;display: flex;align-items: center;justify-content: space-between;
}
.search-history-titlespan{font-size: 14px;
}
.van-tag{margin: 6px 8px;
}
/style项目源码下载地址 https://download.csdn.net/download/p445098355/89570498