因为书中的代码比较久远,许多接口、webpack配置都已更新,但这个项目还是很好玩的,本文的代码都是相对于原书代码的补充。
完整代码:https://github.com/JohnnyMu/zhihuDaily

webpack配置

虽然最新的webpack已经是4.0版本。但与书中的webpack2大多能兼容,只有几个地方稍有变化

vue-loader

vue-loader@15.x 版本相较之前需要增加一些配置

//webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin');
{...}plugins:[new VueLoaderPlugin()]
{...}
mini-css-extract-plugin

webpack4中建议使用mini-css-extract-plugin,而不是extract-text-webpack-plugin。

//webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
{...}
{test:/\.css$/,use:[{loader: MiniCssExtractPlugin.loader},'css-loader']
}
{...}
new MiniCssExtractPlugin({filename: "[name].css",chunkFilename: "[id].css"})
遇到的一个坑

因为这是一个单页应用,所以在写css的时候,我把他们全部写在app.vue文件中,这样在打包的时候,会自动的在打包后样式中加上属性选择器,就像这样

.daily-item[data-v-186c01a3]:hover{background: #e3e8ee;
}

然后坑来了,因为用的html-webpack-plugin自动生成html文件,而他的模板文件中的body、html元素不会自动生成相应的属性,打开控制台看一下Element

可以看到body,html元素均没有属性选择器,而写在vue文件的元素有,这样,我们在app.vue中的有关<html><body>的样式均无法生效。
解决:新建一个style.css文件,在main.js中引用,将body、html的样式写在里面,这样打包后的样式不会被加上属性选择器。

热门栏目功能

因为书中的主题日报所用的api已经无效,看了一下这篇文章 日报 API 分析,使用postman把里面的接口都试了一下,发现栏目的api可用,虽然是内容已经停止更新了,但作为练习的话,影响不大。
首先建立一个section的代理服务器,用来转发数据,解决跨域限制

//proxy.js
const http = require('http');
const request = require('request');const hostname = '127.0.0.1';
const sectionPort= 8012;
const sectionServer = http.createServer((req, res) => {const url = 'http://news-at.zhihu.com/api/3' + req.url;const options = {url: url};function callback (error, response, body) {if (!error && response.statusCode === 200) {// 设置编码类型,否则中文会显示为乱码res.setHeader('Content-Type', 'text/plain;charset=UTF-8');// 设置所有域允许跨域res.setHeader('Access-Control-Allow-Origin', '*');// 返回代理后的内容res.end(body);}}request.get(options, callback);
});
sectionServer.listen(sectionPort, hostname, () => {console.log(`栏目代理运行在 http://${hostname}:${sectionPort}/`)
});

增加相应的ajax模块

//util.js
import axios from 'axios';const Util = {sectionPath:'http://127.0.0.1:8012/'
};
// Ajax 通用配置
Util.ajaxSection = axios.create({baseURL: Util.sectionPath
});
// 添加响应拦截器
Util.ajaxStories.interceptors.response.use(res => {return res.data;
});
export default Util;

写上栏目的html结构,在data中加入我们需要维护的数据

//app.vue
<template>
<div><div class="daily"><div class="daily-menu">...<div class="daily-menu-item":class="{on:type==='section'}"@click="showSection = !showSection">热门栏目</div><ul v-show="showSection"><li v-for="item in sections"><a :class="{on: item.id === sectionId && type === 'section'}"@click="handleToSection(item.id)">{{ item.name}}</a></li></ul></div></div><div class="daily-list" ref="list">...<template v-if="type === 'section'"><item v-for="item in list":data="item":key="item.id"@click.native="handleClick(item.id)"></item></template></div><daily-article :id="articleId" :type="this.type"></daily-article></div>
</div>
</template>
<script>
export default {data(){return {sections:[],//保存栏目目录showSection:false,//是否显示所有栏目type:'recommend',sectionId:0,//保存栏目idlist:[],//保存访问栏目的所有文章sectionTime:0,//本次请求的时间戳}}}</script>

定义一个method,当点击栏目时,访问栏目api,获得栏目列表,并将数据写入data中

methods:{getSections(){$.ajaxSection.get('sections').then(res =>{this.sections = res.data;})}}

当点击具体某个栏目时,中间栏要显示该栏目的文章列表,定义一个method,当调用这哥method时,访问api,将数据写入data,DOM的改变让Vue去做

handleToSection(id){this.type = 'section';this.sectionId = id;this.list = [];$.ajaxSection.get('section/'+id).then(res=>{this.sectionTime = res.timestamp;this.list = res.stories;})}

为中间栏添加scroll事件

mounted() {const $list = this.$refs.list;$list.addEventListener('scroll',()=>{if(this.isloading) return;if($list.scrollTop + document.body.clientHeight >= $list.scrollHeight-100){if(this.type === 'recommend') {this.dailyTime -=86400000;this.getRecommendList();}else{this.getSectionList()}}});
}

下拉中间栏到底,自动加载更多数据

getSectionList(){this.isloading = true;$.ajaxSection.get('section/' +this.sectionId+`/before/${this.sectionTime}`).then(res=>{this.sectionTime= res.timestamp;for (const value of res.stories){this.list.push(value);}this.isloading=false;})}

栏目文章详情组件

一开始只是把日报的组件拿来用,发现直接用v-html转换的页面太难看。

正好栏目api提供了对应文章的知乎页面的url

{"timestamp": 1463148001,"stories": [{"image_hue": "0x3779b3","title": "深夜惊奇 · 要穿内衣","url": "https://daily.zhihu.com/story/8387524","date": "20160601","display_date": "6 月 1 日","images": ["http://pic3.zhimg.com/91125c9aebcab1c84f58ce4f8779551e.jpg"],"id": 8387524},

可以看到上面的stories中url就是文章对应知乎页面了,可以用一个<iframe>直接显示这个页面。但是为了尽量少动代码,还是将知乎的html源码保存下来,用v-html直接显示
增加一个stories代理服务器,与之前类似

//proxy.js
const storiesServer = http.createServer((req, res) => {const url = 'https://daily.zhihu.com/story' + req.url;const options = {url: url};function callback (error, response, body) {//......}}request.get(options, callback);
});
storiesServer.listen(storiesPort, hostname, () => {console.log(`栏目故事代理运行在 http://${hostname}:${storiesPort}/`)
});

相应的ajax模块

//util.js
import axios from 'axios';const Util = {//...storiesPath:'http://127.0.0.1:8013/'
};
Util.ajaxStories = axios.create({baseURL:Util.storiesPath
})
Util.ajaxStories.interceptors.response.use(res => {return res.data;
});
daily-article组件

props中增加一个参数type,接受父组件的信息,现在显示哪一部分,使用watch监控id与type,当他们发生改变时,调用相应方法

//daily-article.vue
<template><div class="daily-article"><div v-if="this.type === 'recommend'" class="daily-article-title">{{ data.title }}</div><div v-if="this.type === 'recommend'" class="daily-article-content" v-html="data.body"></div><div v-if="this.type === 'section'" v-html="this.htmlData"></div><div class="daily-comments" v-show="comments.length">         <!--...--></div></div>
</template>
<script>
{...}
props:{type:{type:String,default:'recommend'}},data(){return{htmlData:''}},watch:{type(val){//类型发生变化,清空数据this.data={},this.comments=[],this.htmlData=''},id(val){//文章id变化,更新文章数据if (this.type==='recommend'&&val) {this.getArticle();}else {this.getStores()}}}
getStores(){//获得html源码,将里面的图片换成代理地址$.ajaxStories.get(`${this.id}`).then(res=>{res =res.replace(/src="http/g,'src="' + $.imgPath+'http');res =res.replace(/src="https/g,'src="' + $.imgPath + 'https');this.htmlData = res;this.getComments();})}

本以为大功告成了,打开网页发现并没有显示文章,上来就是评论

打开控制台看到

看起来好像是css文件被跨域限制了,无法引用。那就用之前图片的代理服务器转发一下就好了。

//daily-article.vue
methods:{getStores(){$.ajaxStories.get(`${this.id}`).then(res=>{res =res.replace(/href="http/g,'href="' + $.imgPath+'http');res =res.replace(/href="https/g,'href="' + $.imgPath + 'https');
})}

再打开网页,确实没问题了,但是这个知乎app的提醒很烦,把它去掉。

在html里找他的类名,在后面加上display:none

//daily-article.vue
methods:{getStores(){$.ajaxStories.get(`${this.id}`).then(res=>{res =res.replace(/ZhihuDailyOIABanner"/,'ZhihuDailyOIABanner" style="display:none;"')})}

完工

《Vue.js实战》知乎日报V2.0相关推荐

  1. VUE实战知乎日报源码以及BUG分析

    源码已上传至https://github.com/anymouschina/daily, 下载后请先 npm install npm run dev 记住开启代理服务,即在当前文件下的终端下使用 no ...

  2. 热烈庆祝《Vue.js 实战教程 V2.x(一)基础篇》上线了!

    热烈庆祝<Vue.js 实战教程 V2.x(一)基础篇>上线了! 课程简介 课程地址:https://edu.csdn.net/course/detail/25641 机构名称:大华软件学 ...

  3. 《Vue.js实战》读书笔记

    嗯,加油啦!!都是书里的东西,整理了一下,以后复习的时候看. 电子档资源见评论 摘些最近看书的句子: 迪安却不一样,他为了面包和性爱在社会上使劲打拼. 我不知道自己究竟是谁了,我远离家乡,旅途劳顿,疲 ...

  4. js 查错_7年前端开发经验的我,写了本Vue.js实战开发,开源高清PDF下载

    Vue作为目前发展最迅速的前端框架越来越多的受到前端T程师青睐,Vue社区也是Web前端最活跃的社区之一. 更多的公司在转为Vue框架,但针对Vue优秀权威.实战的图书相对欠缺,梁灏著<Vue. ...

  5. [Vue.js] 一篇超级长的笔记,给《Vue.js 实战》划个重点

    本文前言 本笔记建立在书籍<Vue.js实战 / 梁灏编著>的基础上,旨在帮助有 Vue.js 基础的朋友快速回忆 Vue.js 的细碎内容.初学者建议阅读<Vue.js实战> ...

  6. vue.js实战——购物车练习(包含全选功能)

    vue.js实战第5章 54页的练习1 直接放代码好了,全选的部分搞了好久,代码好像有点啰嗦,好在实现功能了(*^▽^*) HTML: <!DOCTYPE html> <html l ...

  7. vue --- vue.js实战基础篇课后练习

    练习1:在输入框聚焦时,增加对键盘上下键按键的支持,相当于加1和减1 练习2:增加一个控制步伐的prop-step,比如设置为10,点击加号按钮,一次增加10 思路: // 考虑到子模板的复用性,即在 ...

  8. 3.Vue.js 实战 调查问卷WebApp项目

    问卷调查demo已上传,欢迎大家指正,欢迎大家下载:https://download.csdn.net/download/lzb348110175/11085995 如果您没积分的话,可以私信/评论, ...

  9. 《Vue.js实战》第七章.组件

    7.1 组件作用: 提高代码复用性,使项目易于维护 7.1 组件的使用 7.1.1 组件注册-全局注册 全局注册后,任何vue的实例都可以使用该组件. Vue.component('my-compon ...

最新文章

  1. CR--同事分享学习
  2. log4net 无法输出日志,跟踪发现IsErrorEnabled等,都是Flase
  3. mysql profile 导出_MySQL数据的导出和导入工具:mysqldump_MySQL
  4. 给1-3年的前端 6 点诚心建议
  5. 详解华为12种数据采集技术及应用实践
  6. Node.js的完全卸载与下载安装及各种npm、nvm、nrm配置(保姆式教程---提供全套安装包)---node.js的安装与配置(0)
  7. nodejs 中http请求头,响应头
  8. Visual C# 2008+SQL Server 2005 数据库与网络开发-- 5.1 计算
  9. 在mac上制作PDF的基础教程
  10. 下轮“双一流”将有高校下车?教育部最新说法来了!
  11. 薄壁轴承摩擦力矩_超薄壁球轴承的应用分析
  12. 星际争霸环境旧版本replay回放无法观看问题
  13. 【记忆化搜索/数位DP】zznu2175(长度为n的含有ACM的字符串)
  14. 基于普中A2开发板(STC80C51单片机)呈现的中断小实验代码电路及其效果。
  15. (狼人杀)游戏研究-Android
  16. 几种常用的特征选择方法
  17. ubuntu12.10安装NCL问题
  18. 免费在线客服系统排行
  19. [FlareOn6]Overlong-buuctf
  20. android 7.0 暗 主题,手机亮度调节超暗模式APP 7.0.3 安卓免ROOT

热门文章

  1. 大学信息技术基础 期末复习
  2. Cannot obtain license for Compiler (feature compiler) with license version = 2.2(转)
  3. 全面高效的SEO视频教程,优化自己搞定
  4. 我的日记本开发手记——概述
  5. 重建分区表,修复无法格式化的U盘
  6. 北大青鸟java y2_北大青鸟Y2Java3个月分结业测试题 包含源码
  7. ViewPager设置焦点的问题
  8. 用WinGrub来引导Linux的安装
  9. java拼图自动还原算法_自动解决智能拼图,A*算法+生成可解拼图(C++)
  10. 罗森伯格电子配线系统问答