import Nav from "@/components/nav.vue"; // @ is an alias to /src
import Slider from "@/components/slider.vue"; // @ is an alias to /src
import Footer from "@/components/footer.vue"; // @ is an alias to /src
import ArrowUp from "@/components/arrowUp.vue"; // @ is an alias to /src
import { isMobileOrPc } from "@/utils/utils";
前言
本文讲解如何在 Vue 项目中使用 TypeScript 来搭建并开发项目,并在此过程中踩过的坑 。
TypeScript 具有类型系统,且是 JavaScript 的超集,TypeScript 在 2018年 势头迅猛,可谓遍地开花。
Vue3.0 将使用 TS 重写,重写后的 Vue3.0 将更好的支持 TS。2019 年 TypeScript 将会更加普及,能够熟练掌握 TS,并使用 TS 开发过项目,将更加成为前端开发者的优势。
所以笔者就当然也要学这个必备技能,就以 边学边实践 的方式,做个博客项目来玩玩。
此项目是基于 Vue 全家桶 + TypeScript + Element-UI 的技术栈,且已经开源,github 地址 blog-vue-typescript 。
因为之前写了篇纯 Vue 项目搭建的相关文章 基于vue+mint-ui的mobile-h5的项目说明 ,有不少人加我微信,要源码来学习,但是这个是我司的项目,不能提供原码。
所以做一个不是我司的项目,且又是 vue 相关的项目来练手并开源吧。
1. 效果
效果图:
完整效果请看:https://biaochenxuying.cn
2. 功能
已经完成功能
待优化或者实现
3. 前端主要技术
所有技术都是当前最新的。
4. 5 分钟上手 TypeScript
如果没有一点点基础,可能没学过 TypeScript 的读者会看不懂往下的内容,所以先学点基础。
TypeScript 的静态类型检查是个好东西,可以避免很多不必要的错误, 不用在调试或者项目上线的时候才发现问题 。
TypeScript 里的类型注解是一种轻量级的为函数或变量添加约束的方式。变量定义时也要定义他的类型,比如常见的 :
以上是最简单的一些知识点,更多知识请看 TypeScript 中文官网
5. 5 分钟上手 Vue +TypeScript
vue-class-component 对
Vue
组件进行了一层封装,让Vue
组件语法在结合了TypeScript
语法之后更加扁平化:上面的代码跟下面的代码作用是一样的:
vue-property-decorator 是在
vue-class-component
上增强了更多的结合Vue
特性的装饰器,新增了这 7 个装饰器:@Emit
@Inject
@Model
@Prop
@Provide
@Watch
@Component
(从vue-class-component
继承)在这里列举几个常用的
@Prop/@Watch/@Component
, 更多信息,详见官方文档上面的代码相当于:
vue-class-component
写法中 绑定vuex
。6. 用 vue-cli 搭建 项目
笔者使用最新的 vue-cli 3 搭建项目,详细的教程,请看我之前写的 vue-cli3.x 新特性及踩坑记,里面已经有详细讲解 ,但文章里面的配置和此项目不同的是,我加入了 TypeScript ,其他的配置都是 vue-cli 本来配好的了。详情请看 vue-cli 官网 。
6.1 安装及构建项目目录
安装的依赖:
安装过程选择的一些配置:
搭建好之后,初始项目结构长这样:
奔着 大型项目的结构 来改造项目结构,改造后 :
tsconfig.json 文件中指定了用来编译这个项目的根文件和编译选项。 本项目的 tsconfig.json 配置如下 :
更多配置请看官网的 tsconfig.json 的 编译选项
本项目的 vue.config.js:
6.2 安装 element-ui
本来想搭配 iview-ui 来用的,但后续还想把这个项目搞成 ssr 的,而 vue + typescript + iview + Nuxt.js 的服务端渲染还有不少坑, 而 vue + typescript + element + Nuxt.js 对 ssr 的支持已经不错了,所以选择了 element-ui 。
安装:
按需引入, 借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
然后,将 babel.config.js 修改为:
接下来,如果你只希望引入部分组件,比如 Button 和 Select,那么需要在 main.js 中写入以下内容:
6.3 完善项目目录与文件
route
使用路由懒加载功能。
utils
如果你的生产环境也要 github 登录授权的话,请在 github 上申请一个 Oauth App ,把你的 redirect_uri,client_id,client_secret 的信息填在 config 里面即可。具体详情请看我写的这篇文章 github 授权登录教程与如何设计第三方授权登录的用户表
utils/urls.ts 请求接口地址,统一管理。
utils/https.ts axios 请求的封装。
把 urls 和 https 挂载到 main.ts 里面的 Vue 的 prototype 上面。
然后就可以统一管理接口,而且调用起来也很方便啦。比如下面 文章列表的请求。
store ( Vuex )
一般大型的项目都有很多模块的,比如本项目中有公共信息(比如 token )、 用户模块、文章模块。
7. markdown 渲染
markdown 渲染效果图:
markdown 渲染 采用了开源的 marked, 代码高亮用了 highlight.js 。
用法:
第一步:npm i marked highlight.js --save
第二步: 导入封装成 markdown.js,将文章详情由字符串转成 html, 并抽离出文章目录。
marked 的封装 得感谢这位老哥。
第三步: 使用
第四步:引入 monokai_sublime 的 css 样式
第五步:对 markdown 样式的补充
如果不补充样式,是没有黑色背景的,字体大小等也会比较小,图片也不会居中显示
8. 注意点
对于 关于 的页面,其实是一篇文章来的,根据文章类型 type 来决定的,数据库里面 type 为 3 的文章,只能有一篇就是 博主介绍 ;达到了想什么时候修改内容都可以。
所以当 当前路由 === '/about' 时就是请求类型为 博主介绍 的文章。
如上:通过查询屏幕宽度,动态的设置 html 的 font-size 值,移动端的设计稿大多以宽为 750 px 来设置的。
比如在设计图上一个 150 * 250 的盒子(单位 px):
原本在 css 中的写法:
通过上述换算后,在 css 中对应的 rem 值只需要写:
如果你的移动端的设计稿是以宽为 1080 px 来设置的话,就用 window.screen.width / 10.8 吧。
9. 踩坑记
然而当你在组件中直接 this.$http 或者 this.$urls 时会报错的,那是因为 $http 和 $urls 属性,并没有在 vue 实例中声明。
之前用法如下图:
然而还是会报错的。
再比如 监听路由的变化:
只是这样写的话,监听 $route 还是会报错的。
想要以上三种做法都正常执行,就还要补充如下内容:
在 src 下的 shims-vue.d.ts 中加入要挂载的内容。 表示 vue 里面的 this 下有这些东西。
比如 在组件里面使用 window.document 或者 document.querySelector 的时候会报错的,npm run build 不给通过。
再比如:按需引用 element 的组件与动画组件:
npm run serve 时可以执行,但是在 npm run build 的时候,会直接报错的,因为没有声明。
正确做法:
我在 src 下新建一个文件 shime-global.d.ts ,加入内容如下:
当然,这个文件你加在其他地方也可以,起其他名字都 OK。
但是即使配置了以上方法之后,有些地方使用 document.XXX ,比如 document.title 的时候,npm run build 还是通过不了,所以只能这样了:
比如之前的 事件的节流(throttle)与防抖(debounce)方法:
function 里面的 this 在 npm run serve 时会报错的,因为 tyescript 检测到它不是在类(class)里面。
正确做法:
在根目录的 tsconfig.json 里面加上 "noImplicitThis": false ,忽略 this 的类型检查。
import .vue 的文件的时候,要补全 .vue 的后缀,不然 npm run build 会报错的。
比如:
要修改为:
报错。
以下才是正确,因为这里的 Vue 是从 vue-property-decorator import 来的。
vue-class-component 官网里面的路由的导航钩子的用法是没有效果的 Adding Custom Hooks
路由的导航钩子不属于 Vue 本身,这会导致 class 组件转义到配置对象时导航钩子无效,因此如果要使用导航钩子需要在 router 的配置里声明(网上别人说的,还没实践,不确定是否可行)。
7. tsconfig.json 的 strictPropertyInitialization 设为 false,不然你定义一个变量就必须给它一个初始值。
position: sticky;
本项目中的文章详情的目录就是用了 sticky。
position:sticky 是 css 定位新增属性;可以说是相对定位 relative 和固定定位 fixed 的结合;它主要用在对 scroll 事件的监听上;简单来说,在滑动过程中,某个元素距离其父元素的距离达到 sticky 粘性定位的要求时(比如 top:100px );position:sticky 这时的效果相当于 fixed 定位,固定到适当位置。
用法像上面那样用即可,但是有使用条件:
1、父元素不能 overflow:hidden 或者 overflow:auto 属性。 2、必须指定 top、bottom、left、right 4 个值之一,否则只会处于相对定位 3、父元素的高度不能低于 sticky 元素的高度 4、sticky 元素仅在其父元素内生效
App.vue 中只是写了引用文件而已,而且 webpack 和 tsconfig.josn 里面已经配置了别名了的。
但是,还是会报如下的错:
只是代码不影响文件的打包,而且本地与生产环境的代码也正常,没报错而已。
这个 eslint 的检测目前还没找到相关的配置可以把这些错误去掉。
因为文章详情页面有目录,点击目录时定位定相应的内容,但是这个目录定位内容是根据锚点来做的,如果路由模式为 hash 模式的话,本来文章详情页面的路由就是 #articleDetail 了,再点击目录的话(比如 #title2 ),会在 #articleDetail 后面再加上 #title2,一刷新会找不到这个页面的。
10. Build Setup
如果要看有后台数据完整的效果,是要和后台项目 blog-node 一起运行才行的,不然接口请求会失败。
虽然引入了 mock 了,但是还没有时间做模拟数据,想看具体效果,请稳步到我的网站上查看 https://biaochenxuying.cn
11. 项目地址与系列相关文章
基于 Vue + TypeScript + Element 的 blog-vue-typescript 前台展示: https://github.com/biaochenxuying/blog-vue-typescript
基于 react + node + express + ant + mongodb 的博客前台,这个是笔者之前做的,效果和这个类似,地址如下: blog-react 前台展示: https://github.com/biaochenxuying/blog-react
推荐阅读 :
本博客系统的系列文章:
12. 最后
笔者也是初学 TS ,如果文章有错的地方,请指出,感谢。
一开始用 Vue + TS 来搭建时,我也是挺抵触的,因为踩了好多坑,而且很多类型检查方面也挺烦人。后面解决了,明白原理之后,是越用越爽,哈哈。
权衡
如何更好的利用 JS 的动态性和 TS 的静态特质,我们需要结合项目的实际情况来进行综合判断。一些建议:
至于到底用不用TS,还是要看实际项目规模、项目生命周期、团队规模、团队成员情况等实际情况综合考虑。
其实本项目也是小项目来的,其实并不太适合加入 TypeScript ,不过这个项目是个人的项目,是为了练手用的,所以就无伤大大雅。
未来,class-compoent 也将成为主流,现在写 TypeScript 以后进行 3.0 的迁移会更加方便。
每天下班后,用几个晚上的时间来写这篇文章,码字不易,如果您觉得这篇文章不错或者对你有所帮助,请给个赞或者星吧,你的点赞就是我继续创作的最大动力。
参考文章:
vue + typescript 项目起手式
TypeScript + 大型项目实战