七、文章详情

创建组件并配置路由

1、创建 views/article/index.vue 组件

<template><div class="article-container">文章详情</div>
</template><script>
export default {name: 'ArticleIndex',components: {},props: {articleId: {type: [Number, String],required: true}},data () {return {}},computed: {},watch: {},created () {},mounted () {},methods: {}
}
</script><style scoped lang="less"></style>

2、然后将该页面配置到根级路由

{path: '/article/:articleId',name: 'article',component: () => import('@/views/article'),// 将路由动态参数映射到组件的 props 中,更推荐这种做法props: true
}

3、通过props获取路由参数

props: {articleId: {type: [Number, String],required: true}}

官方文档:路由 props 传参

在我的article-list-item里面配置
这里面click直接点击没有用,需要click.native因为模板没有原生点击事件

 <artilce-list-itemv-for="item in list":key="item.art_id":articleItem="item"@click.native="fn(item.art_id)"/>fn(id) {// console.log(id);this.$router.push(`/article/${id}`);},

页面布局

使用到的 Vant 中的组件:

  • NavBar 导航栏

  • Loading 加载

  • Cell 单元格

  • Button 按钮

  • Image 图片

  • Divider 分割线

  • Icon 图标

<template><div class="article-container"><!-- 导航栏 --><van-nav-barclass="page-nav-bar"left-arrowtitle="头条"></van-nav-bar><!-- /导航栏 --><div class="main-wrap"><!-- 加载中 --><div class="loading-wrap"><van-loadingcolor="#3296fa"vertical>加载中</van-loading></div><!-- /加载中 --><!-- 加载完成-文章详情 --><div class="article-detail"><!-- 文章标题 --><h1 class="article-title">这是文章标题</h1><!-- /文章标题 --><!-- 用户信息 --><van-cell class="user-info" center :border="false"><van-imageclass="avatar"slot="icon"roundfit="cover"src="https://img.yzcdn.cn/vant/cat.jpeg"/><div slot="title" class="user-name">头条号</div><div slot="label" class="publish-date">14小时前</div><van-buttonclass="follow-btn"type="info"color="#3296fa"roundsize="small"icon="plus">关注</van-button><!-- <van-buttonclass="follow-btn"roundsize="small">已关注</van-button> --></van-cell><!-- /用户信息 --><!-- 文章内容 --><div class="article-content">这是文章内容</div><van-divider>正文结束</van-divider></div><!-- /加载完成-文章详情 --><!-- 加载失败:404 --><div class="error-wrap"><van-icon name="failure" /><p class="text">该资源不存在或已删除!</p></div><!-- /加载失败:404 --><!-- 加载失败:其它未知错误(例如网络原因或服务端异常) --><div class="error-wrap"><van-icon name="failure" /><p class="text">内容加载失败!</p><van-button class="retry-btn">点击重试</van-button></div><!-- /加载失败:其它未知错误(例如网络原因或服务端异常) --></div><!-- 底部区域 --><div class="article-bottom"><van-buttonclass="comment-btn"type="default"roundsize="small">写评论</van-button><van-iconname="comment-o"info="123"color="#777"/><van-iconcolor="#777"name="star-o"/><van-iconcolor="#777"name="good-job-o"/><van-icon name="share" color="#777777"></van-icon></div><!-- /底部区域 --></div>
</template><script>
export default {name: 'ArticleIndex',components: {},props: {articleId: {type: [Number, String],required: true}},data () {return {}},computed: {},watch: {},created () {},mounted () {},methods: {}
}
</script><style scoped lang="less">
.article-container {.main-wrap {position: fixed;left: 0;right: 0;top: 92px;bottom: 88px;overflow-y: scroll;background-color: #fff;}.article-detail {.article-title {font-size: 40px;padding: 50px 32px;margin: 0;color: #3a3a3a;}.user-info {padding: 0 32px;.avatar {width: 70px;height: 70px;margin-right: 17px;}.van-cell__label {margin-top: 0;}.user-name {font-size: 24px;color: #3a3a3a;}.publish-date {font-size: 23px;color: #b7b7b7;}.follow-btn {width: 170px;height: 58px;}}.article-content {padding: 55px 32px;/deep/ p {text-align: justify;}}}.loading-wrap {padding: 200px 32px;display: flex;align-items: center;justify-content: center;background-color: #fff;}.error-wrap {padding: 200px 32px;display: flex;flex-direction: column;align-items: center;justify-content: center;background-color: #fff;.van-icon {font-size: 122px;color: #b4b4b4;}.text {font-size: 30px;color: #666666;margin: 33px 0 46px;}.retry-btn {width: 280px;height: 70px;line-height: 70px;border: 1px solid #c3c3c3;font-size: 30px;color: #666666;}}.article-bottom {position: fixed;left: 0;right: 0;bottom: 0;display: flex;justify-content: space-around;align-items: center;box-sizing: border-box;height: 88px;border-top: 1px solid #d8d8d8;background-color: #fff;.comment-btn {width: 282px;height: 46px;border: 2px solid #eeeeee;font-size: 30px;line-height: 46px;color: #a7a7a7;}.van-icon {font-size: 40px;.van-info {font-size: 16px;background-color: #e22829;}}}
}
</style>

获取文章详情数据

1、封装请求文章详情方法

/*** 文章接口模块*/
import request from '@/utils/request'/*** 获取频道的文章列表*/
export const getArticleById = articleId => {return request({method: 'GET',url: '/app/v1_0/articles/' + articleId})
}

2、引入方法

import { getArticleById } from '@/api/article.js'

3、定义加载数据方法

async loadArtcileInfo () {try {const res = await getArticleById(this.articleId)console.log(res)} catch (err) {this.$toast('获取失败')}
}

关于后端返回数据中的大数字问题

之所以请求文章详情返回 404 是因为我们请求发送的文章 ID (article.art_id)不正确。

JavaScript 能够准确表示的整数范围在-2^532^53之间(不含两个端点),超过这个范围,无法精确表示这个值,这使得 JavaScript 不适合进行科学和金融方面的精确计算。

Math.pow(2, 53) // 90071992547409929007199254740992  // 9007199254740992
9007199254740993  // 9007199254740992Math.pow(2, 53) === Math.pow(2, 53) + 1
// true

上面代码中,超出 2 的 53 次方之后,一个数就不精确了。
ES6 引入了Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。

Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1
// true
Number.MAX_SAFE_INTEGER === 9007199254740991
// trueNumber.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER
// true
Number.MIN_SAFE_INTEGER === -9007199254740991
// true

上面代码中,可以看到 JavaScript 能够精确表示的极限。

后端返回的数据一般都是 JSON 格式的字符串

'{ "id": 9007199254740995, "name": "Jack", "age": 18 }'

如果这个字符不做任何处理,你能方便的获取到字符串中的指定数据吗?非常麻烦。所以我们要把它转换为 JavaScript 对象来使用就很方便了。

幸运的是 axios 为了方便我们使用数据,它会在内部使用 JSON.parse() 把后端返回的数据转为 JavaScript 对象。

// { id: 9007199254740996, name: 'Jack', age: 18 }
JSON.parse('{ "id": 9007199254740995, "name": "Jack", "age": 18 }')

可以看到,超出安全整数范围的 id 无法精确表示,这个问题并不是 axios 的错。

了解了什么是大整数的概念,接下来的问题是如何解决?

利用json-bigint处理大数字问题

json-bigint 是一个第三方包,它可以帮我们很好的处理这个问题。

使用它的第一步就是把它安装到你的项目中。

npm i json-bigint

下面是使用它的一个简单示例。

const jsonStr = '{ "art_id": 1245953273786007552 }'console.log(JSON.parse(jsonStr)) // 1245953273786007600
// JSON.stringify()// JSONBig 可以处理数据中超出 JavaScript 安全整数范围的问题
console.log(JSONBig.parse(jsonStr)) // 把 JSON 格式的字符串转为 JavaScript 对象// 使用的时候需要把 BigNumber 类型的数据转为字符串来使用
console.log(JSONBig.parse(jsonStr).art_id.toString()) // 1245953273786007552console.log(JSON.stringify(JSONBig.parse(jsonStr)))console.log(JSONBig.stringify(JSONBig.parse(jsonStr))) // 把 JavaScript 对象 转为 JSON 格式的字符串转

json-bigint 会把超出 JS 安全整数范围的数字转为一个 BigNumber 类型的对象,对象数据是它内部的一个算法处理之后的,我们要做的就是在使用的时候转为字符串来使用。

通过 Axios 请求得到的数据都是 Axios 处理(JSON.parse)之后的,我们应该在 Axios 执行处理之前手动使用 json-bigint 来解析处理。Axios 提供了自定义处理原始后端返回数据的 API:transformResponse

import axios from 'axios'import jsonBig from 'json-bigint'var json = '{ "value" : 9223372036854775807, "v2": 123 }'console.log(jsonBig.parse(json))const request = axios.create({baseURL: 'http://ttapi.research.itcast.cn/', // 接口基础路径// transformResponse 允许自定义原始的响应数据(字符串)transformResponse: [function (data) {try {// 如果转换成功则返回转换的数据结果return jsonBig.parse(data)} catch (err) {// 如果转换失败,则包装为统一数据格式并返回return {data}}}]
})export default request

修改props类型

props: {articleId: {type: [Number, String, Object],required: true}}

扩展:ES2020 BigInt

ES2020 引入了一种新的数据类型 BigInt(大整数),来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。

参考链接:

  • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt
  • http://es6.ruanyifeng.com/#docs/number#BigInt-%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B

展示文章详情

思路:

  • 找到数据接口
  • 封装请求方法
  • 请求获取数据
  • 模板绑定

一、请求并展示文章详情

1、在 api/article.js 中新增封装接口方法

/*** 根据 id 获取指定文章*/
export const getArticleById = articleId => {return request({method: 'GET',url: `/app/v1_0/articles/${articleId}`})
}

2、在组件中调用获取文章详情

+ import { getArticleById } from '@/api/article'export default {name: 'ArticlePage',components: {},props: {articleId: {type: String,required: true}},data () {return {+      article: {} // 文章详情}},computed: {},watch: {},created () {+    this.loadArticle()},mounted () {},methods: {+++    async loadArticle () {try {const { data } = await getArticleById(this.articleId)this.article = data.data} catch (err) {console.log(err)}}}
}

3、模板绑定

<!-- 加载完成-文章详情 --><div class="article-detail"><!-- 文章标题 --><h1 class="article-title">{{ article.title }}</h1><!-- /文章标题 --><!-- 用户信息 --><van-cell class="user-info" center :border="false"><van-imageclass="avatar"slot="icon"roundfit="cover":src="article.aut_photo"/><div slot="title" class="user-name">{{ article.aut_name }}</div><div slot="label" class="publish-date">{{ article.pubdate | relativeTime }}</div><van-buttonclass="follow-btn"type="info"color="#3296fa"roundsize="small"icon="plus">关注</van-button><!-- <van-buttonclass="follow-btn"roundsize="small">已关注</van-button> --></van-cell><!-- /用户信息 --><!-- 文章内容 --><div class="article-content" v-html="article.content"></div><van-divider>正文结束</van-divider></div><!-- /加载完成-文章详情 -->

处理内容加载状态

需求:

  • 加载中,显示 loading
  • 加载成功,显示文章详情
  • 加载失败,显示错误提示
    • 如果 404,提示资源不存在
    • 其它的,提示加载失败,用户可以点击重试重新加载
<!-- 加载中 -->
<div class="loading-wrap" v-if="isLoading">
<!-- 加载完成-文章详情 -->
<div v-else-if="article.title" class="article-detail">
<!-- 加载失败:404 -->
<div v-else-if="errStatus === 404" class="error-wrap">
<!-- 加载失败:其它未知错误(例如网络原因或服务端异常) -->
<div v-else class="error-wrap">
async loadArticleInfo () {try {// 随机错误thorw Error()const { data } = await getArticleInfo(this.articleId)this.article = data.data} catch (err) {// 加载失败 404if (err.response && err.response.status === 404) {this.errStatus = 404}this.$toast('获取失败')}// 加载完成this.isLoading = false
}

点击重新加载

<!-- 加载失败:其它未知错误(例如网络原因或服务端异常) -->
<div v-else class="error-wrap"><van-icon name="failure" /><p class="text">内容加载失败!</p><van-button @click="loadArtcileInfo" class="retry-btn">点击重试</van-button>
</div>

在loadArtcileInfo中重新显示加载loading

关于文章正文的样式

文章正文包括各种数据:段落、标题、列表、链接、图片、视频等资源。

  • 将 github-markdown-css 样式文件下载到项目中

  • 导入

    import './github-markdown.css'
    
  • 添加类名

    <div class="article-content markdown-body" v-html="article.content"></div>
    
  • 配置不要转换样式文件中的字号

    'postcss-pxtorem': {rootValue ({ file }) {return file.indexOf('vant') !== -1 ? 37.5 : 75},propList: ['*'],exclude: 'github-markdown'}
    

图片点击预览

一、ImagePreview 图片预览 的使用

1、导入

import { ImagePreview } from 'vant';

2、使用

ImagePreview({images: ['https://img.yzcdn.cn/vant/apple-1.jpg','https://img.yzcdn.cn/vant/apple-2.jpg'],// 预览图片的起始位置startPosition: 1,// 点击关闭onClose () {// do something}
})

二、处理图片点击预览

思路:140967 带图片

1、页面渲染完成从文章内容中获取到所有的 img DOM 节点

async loadArticleInfo () {try {thorwError()const { data } = await getArticleInfo(this.articleId)this.article = data.data// 数据加载完成setTimeout(() => {this.previewImg()}, 10)} catch (err) {if (err.response && err.response.status === 404) {this.errStatus = 404}this.$toast('获取失败')}this.isLoading = false}
previewImg () {const contentEl = this.$refs.contentRefconst allImg = contentEl.querySelectorAll('img')
}

2、获取文章内容中所有的图片地址

previewImg () {const contentEl = this.$refs.contentRefconst allImg = contentEl.querySelectorAll('img')console.log(allImg)
}

3、遍历所有 img 节点,给每个节点注册点击事件

previewImg () {const contentEl = this.$refs.contentRefconst allImg = contentEl.querySelectorAll('img')const images = []allImg.forEach((element, index) => {images.push(element.src)element.onclick = () => {}})
}

4、在 img 点击事件处理函数中,调用 ImagePreview 预览

previewImg () {const contentEl = this.$refs.contentRefconst allImg = contentEl.querySelectorAll('img')const images = []allImg.forEach((element, index) => {images.push(element.src)element.onclick = () => {ImagePreview({images,startPosition: index})}})
}

关注用户

思路:

  • 给按钮注册点击事件
  • 在事件处理函数中
    • 如果已关注,则取消关注
    • 如果没有关注,则添加关注

下面是具体实现。

视图处理

功能处理

  • 找到数据接口
  • 封装请求方法
  • 请求调用
  • 视图更新

1、在 api/user.js 中添加封装请求方法

/*** 添加关注*/
export const addFollow = userId => {return request({method: 'POST',url: '/app/v1_0/user/followings',data: {target: userId}})
}/*** 取消关注*/
export const deleteFollow = userId => {return request({method: 'DELETE',url: `/app/v1_0/user/followings/${userId}`})
}

2、给关注/取消关注按钮注册点击事件

3、在事件处理函数中

import { addFollow, deleteFollow } from '@/api/user'
async onFollow () {// 开启按钮的 loading 状态this.isFollowLoading = truetry {// 如果已关注,则取消关注const authorId = this.article.aut_idif (this.article.is_followed) {await deleteFollow(authorId)} else {// 否则添加关注await addFollow(authorId)}// 更新视图this.article.is_followed = !this.article.is_followed} catch (err) {console.log(err)this.$toast.fail('操作失败')}// 关闭按钮的 loading 状态this.isFollowLoading = false
}

最后测试。

loading 效果

两个作用:

  • 交互反馈
  • 防止网络慢用户多次点击按钮导致重复触发点击事件

组件封装

组件封装

1、封装组件

<template><van-buttonclass="follow-btn"type="info"color="#3296fa"roundv-if="!is_followed"size="small"icon="plus":loading="isFollowLoading"@click="follow">关注</van-button><van-buttonv-elseclass="follow-btn"round:loading="isFollowLoading"size="small"@click="follow">已关注</van-button>
</template><script>
import { addFollow, deleteFollow } from '@/api/user'
export default {name: 'follow-user',data () {return {isFollowLoading: false}},props: {is_followed: {type: Boolean,required: true},user_id: {type: [Number, String, Object],required: true}},created () {},methods: {// 关注用户async follow () {this.isFollowLoading = truetry {// 如果已关注,则取消关注const authorId = this.user_idif (this.is_followed) {await deleteFollow(authorId)} else {// 否则添加关注await addFollow(authorId)}// 更新视图this.$emit('update-follow', !this.is_followed)} catch (err) {console.dir(err)if (err.response && err.response.status === 400) {return this.$toast.fail('不能关注自己')}this.$toast.fail('操作失败')}// 关闭按钮的 loading 状态this.isFollowLoading = false}}
}
</script><style scoped lang='less'></style>

2、引入组件

import FollowUser from '@/components/follow-user'
components: {FollowUser
}

3、使用组件

<follow-user:is_followed="article.is_followed":user_id="article.aut_id"@update-follow="article.is_followed = $event"
</follow-user>

使用v-model

<follow-userv-model="article.is_followed":user_id="article.aut_id"></follow-user>

组件内部添加model

model: {prop: 'is_followed',event: 'update-follow'
}

文章收藏

该功能和关注用户的处理思路几乎一样,建议由学员自己编写。

封装组件

处理视图

1、封装组件

<template><van-iconcolor="#777"name="star-o"/>
</template><script>
export default {name: 'collectArticle',
}
</script><style scoped lang='less'></style>

2、使用组件

<van-iconname="comment-o"info="123"color="#777"/>
<CollectArticle />
<van-iconcolor="#777"name="good-job-o"/>

2、传递数据处理视图

<collect-article v-model="article.is_collected" />
<template><van-icon:color="value ? '#ffa500' : ''":name="value?'star':'star-o'"/>
</template><script>
export default {name: 'CollectArticle',props: {value: {type: Boolean,required: true}}
}
</script>

功能处理

思路:

  • 给收藏按钮注册点击事件
  • 如果已经收藏了,则取消收藏
  • 如果没有收藏,则添加收藏

下面是具体实现。

1、在 api/article.js 添加封装数据接口

/*** 收藏文章*/
export const addCollect = target => {return request({method: 'POST',url: '/app/v1_0/article/collections',data: {target}})
}/*** 取消收藏文章*/
export const deleteCollect = target => {return request({method: 'DELETE',url: `/app/v1_0/article/collections/${target}`})
}

2、给收藏按钮注册点击事件

<van-icon
color="#ffa500"
:name="value?'star':'star-o'"
@click="onCollect"
:loading="loading"
/>

3、处理函数

async onCollect () {// 开始请求this.loading = truetry {// 是否收藏if (this.value) {// 父组件 传递articleIdawait deleteCollect(this.articleId)} else {await addCollect(this.articleId)}// 更新视图this.$emit('input', !this.value)this.$toast.success(this.value ? '取消收藏' : '收藏成功')} catch (err) {this.$toast('操作失败,请重试')}// 请求结束this.loading = false
}

4、 父组件传递文章id

<collect-article :article-id="article.art_id" v-model="article.is_followed" />

5、将底部区域调整到正文下面

文章点赞

1、封装组件

<template><van-icon:color="value === 1 ? 'red' : ''":name="value === 1?'good-job':'good-job-o'"/>
</template><script>
export default {data () {return {}},props: {value: {type: Number,required: true}},created () {},methods: {}
}
</script><style scoped lang='less'></style>

2、使用组件

import likeArticle from '@/components/like-article'components: {FollowUser,CollectArticle,likeArticle
}<likeArticle v-model="article.attitude" />

该功能和关注用户的处理思路几乎一样,建议由学员自己编写。

article 中的 attitude 表示用户对文章的态度

  • -1 无态度
  • 0 不喜欢
  • 1 已点赞

思路:

  • 给点赞按钮注册点击事件
  • 如果已经点赞,则请求取消点赞
  • 如果没有点赞,则请求点赞

1、添加封装数据接口

/*** 点赞*/
export const addLike = articleId => {return request({method: 'POST',url: '/app/v1_0/article/likings',data: {target: articleId}})
}/*** 取消点赞*/
export const deleteLike = articleId => {return request({method: 'DELETE',url: `/app/v1_0/article/likings/${articleId}`})
}

2、给点赞按钮注册点击事件

3、处理函数

async onLike () {// 两个作用:1、交互提示 2、防止网络慢用户连续不断的点击按钮请求this.$toast.loading({duration: 0, // 持续展示 toastmessage: '操作中...',forbidClick: true // 是否禁止背景点击})try {// 如果已经点赞,则取消点赞if (this.article.attitude === 1) {await deleteLike(this.articleId)this.article.attitude = -1this.$toast.success('取消点赞')} else {// 否则添加点赞await addLike(this.articleId)this.article.attitude = 1this.$toast.success('点赞成功')}} catch (err) {console.log(err)this.$toast.fail('操作失败')}
}

Vue移动端系列 => [07] 文章详情相关推荐

  1. Vue移动端系列 => [06] 文章搜索

    六.文章搜索 6.1 创建组件并配置路由 1.给搜索按钮添加to属性 <!-- 导航栏 --><van-nav-bar class="page-nav-bar" ...

  2. 基于SpringBoot + Vue的个人博客系统07——文章列表和文章详情

    简介 由于本人不是专业的前端,所以写出来的界面可能会稍微有些丑陋,甚至有些地方的写法不是很专业,还请大家见谅 主界面 JS 部分 首先是 js 逻辑部分 我们先在@/http/request.js中定 ...

  3. 小案例:实现http://www.alloyteam.com/page/0/移动端效果,博客文章列表和文章详情页面

    一:案例要求和数据: (1)移动端适配 (2)列表跳详情 (3)回到顶部 (4)上下页 (5)时间格式 (6)解决接口跨域请求访问问题 (7)路由跳转无bug 接口路径均以 http://118.19 ...

  4. InfoQ网站作者的文章列表文章详情获取-Java网络爬虫系统性学习与实战系列(13)

    InfoQ网站作者的文章列表&文章详情获取-Java网络爬虫系统性学习与实战系列(13) 文章目录 联系方式 概述 分析 配置好Xpath规则 selenium工具类 获取InfoQ文章列表 ...

  5. Vue.js 实战系列之实现视频类WebApp的项目开发——6. 首页视频详情实现

    如果想看该实战系列的其他内容,请移步至 Vue.js 实战系列之实现视频类WebApp的项目开发. 项目仓库地址,欢迎 Star 实现效果 功能实现 视频详情页基本实现 创建 InfoBar.vue ...

  6. VUE—移动端手机号正则验证,不正确显示‘请输入正确手机号’,若正确跳转到发送验证码(图文详情)

    VUE-移动端手机号正则验证,不正确显示'请输入正确手机号',若正确跳转到发送验证码 先看效果图 第一步:写布局 <input type="text" placeholder ...

  7. Vue.js入门 0x13 实战:知乎日报项目开发-文章详情页

    加载内容 右侧的文章内容区域封装成了一个组件.在components目录下新建daily-article.vue组件,它唯一接收唯一的一个prop:id,也就是文章的id,如果id变化了,就说明切换了 ...

  8. JavaScript - Vue经典教程系列-李游Leo-专题视频课程

    JavaScript - Vue经典教程系列-1114人已学习 课程介绍         Vue.JS 是目前火的前端框架之一,是一个构建数据驱动的 web 界面的渐进式框架. Vue.JS 的目标是 ...

  9. 手摸手,带你用vue撸后台 系列一(基础篇) - 掘金

    完整项目地址:vue-element-admin 系列文章: 手摸手,带你用 vue 撸后台 系列一(基础篇) 手摸手,带你用 vue 撸后台 系列二(登录权限篇) 手摸手,带你用 vue 撸后台 系 ...

最新文章

  1. 医疗影像处理:去除医疗影像中背景的影响2D/3D【numpy-code】| CSDN博文精选
  2. labview 随笔记录
  3. IntelliJ IDEA 2020.1 EAP2 发布:新增禅模式和 LightEdit 模式
  4. CSP认证201409-4 最优配餐[C++题解]:bfs、多源bfs、最短路、图论
  5. Serverless 时代 DevOps 的最佳打开方式
  6. 笔记-项目整体管理-监控项目工作主要做的工作
  7. LeetCode 16 最接近的三数之和
  8. JAVA语言程序设计课后习题----第四单元解析(仅供参考)
  9. 【渝粤题库】国家开放大学2021春1376机械制造装备及设计题目
  10. Cisco Nexus 1000V
  11. 主成分分析碎石图_ISLR读书笔记十九:主成分分析(PCA)
  12. 两个摄像头合成一路_小米手机成功开发出伸缩式摄像头,秒变单反,这次雷军又火了...
  13. 为什么你总感觉情绪低落心情颓废?
  14. java proguard 反混淆_JAVA之代码混淆proguard
  15. FC SAN、IP SAN、IB SAN
  16. Android 发短信功能实现
  17. vue开发必备神器:vue-devtools
  18. vue中views新建文件夹的代码规范
  19. 图像和音频格式解析一览
  20. 期权:短期交易日内波动为主 静待市场情绪拐点

热门文章

  1. 基于模糊控制的Simulink仿真详解
  2. Android项目实战系列—基于博学谷(四)我的模块(上)
  3. 软件测试工程师的简历项目经验该怎么写?
  4. python编程工具-7款Python开发工具介绍,你最中意哪一款
  5. Adam优化算法中的指数移动平均
  6. vue实现组件隔代通信(在孙组件调用爷组件的方法)
  7. 学计算机选择什么编程语言好一些?
  8. 基于stm32的智能小车(远程控制、避障、循迹)
  9. 大数问题:大数加法 与 大数乘法 最简单大数乘法
  10. 太阳能路灯c语言程序,基于单片机的智能太阳能路灯控制系统的设计方案