vue脚手架的从零搭建就不用了吧,官网也有详细的教程,这里就默认大家会使用vue进行开发。 还有就是建站用的是Vue3.0,它与Vue2.0大的变化就是webpack配置隐藏起来了, 它都是默认配置给你配置好了的。所以如果要更改配置的话要在根目录下新建一个 vue.config.js,在这里可以配置webpack和代理什么的。这是 Vue3.0官方配置参考中文文档。 以及后面一大片的代码可以直接跳过看解析,或者边看注释边看代码,仔细看的话还是很容易理解的, 不过还是建议先看解析再看代码,这样会有一个整体的认识。
这里用一下官方文档的一句话:"Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库"。虽然这个网站前台是vue3.0,但这并不影响与element-ui的融合。使用element-ui来构建站点可以极大的提高开发效率。 你想:遇到要写什么过渡动画,消息提醒,美观表格,导航啊。。。什么乱七八糟的,这里都有,直接Ctrl C + Ctrl V认真观看文档,然后仔细查看参数说明,最后怀着虔诚的心把代码拷过来,岂不美哉?快快用起来,一起摇摆,你就是最靓的仔!
好了,element-ui这么好用,那么如何使用它呢?进入代码环节: 使用命令行进入到你的vue项目, npm install element-ui -S,安装好之后找到vue项目下的src/main.js。在其中添加下面代码:
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
以上引入是全局引入,如果你只想要引入部分组件的话,可以这样写:
import { MessageBox,Loading } from 'element-ui';
详情请见官方文档,官方文档是最好的老师。element-ui 上手还是挺快的,花点时间就入门了。 还有就是不要乱改组件的代码,以及明白参数的意义,不然 就容易gg,你花费30分钟解决莫名其妙的bug来节约看文档的10分钟。我当时用它的表单验证时, 一开始我以为有个回调没有用,于是删掉了,然后后面即使通过验证但一直触发不了提交函数。。。 结局就是花了好一会才找到,还是太菜,让各位见笑了。
组件之间传值使用props感觉有点累,所以虽然这个网站前台并不是很复杂,但我还是选择用vuex来维护状态。 在src/store.js(没有则新建)添加以下代码:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const types = {
SET_AUTHENTICATED: "SET_AUTHENICATED",
SET_USER: "SET_USER",
SET_BLOG: "SET_BLOG",
SET_USERINFO: "SET_USERINFO"
}
const state = {
isAuthenticated: false, //授权状态
user: {}, //email,name,id
blog: {}, //请求的blog
userInfo: {} //temporarySave(暂存区),saveTime(保存时间)
}
const getters = {
isAuthenticated: state => state.isAuthenticated,
user: state => state.user,
blog: state => state.blog,
userInfo: state => state.userInfo
}
const mutations = {
//es6计算属性
[types.SET_AUTHENTICATED](state, isAuthenticated) {
isAuthenticated ? state.isAuthenticated = isAuthenticated : state.isAuthenticated = false;
//如果有授权的话就是store.isAuthenticates为true,否则为false
},
[types.SET_USER](state, user) {
user ? state.user = user : state.user = {};
},
[types.SET_BLOG](state, blog) {
blog ? state.blog = blog : state.blog = {};
},
[types.SET_USERINFO](state, userInfo) {
userInfo ? state.userInfo = userInfo : state.userInfo = {};
},
}
const actions = {
//setAuthenticated
setAuthenticated: ({
commit
}, isAuthenticated) => {
commit(types.SET_AUTHENTICATED, isAuthenticated);
},
setUser: ({
commit
}, user) => {
commit(types.SET_USER, user);
},
setBlog: ({
commit
}, blog) => {
commit(types.SET_BLOG, blog);
},
setUserInfo: ({
commit
}, userInfo) => {
commit(types.SET_USERINFO, userInfo);
},
clearCurrentState: ({
commit
}) => {
commit(types.SET_AUTHENTICATED, false);
commit(types.SET_USER, null);
commit(types.SET_USERINFO, null);
}
}
export default new Vuex.Store({
state,
getters,
mutations,
actions
})
state里的都是要维护的状态,然后在其它组件中通过getters获取, 同步修改状态使用commit提交mutation,异步修改状态使用dispatch提交action。
众所周知cookie只能存4kb,并且cookie一开始的作用是维持http状态, 让服务器通过cookie知道你是谁,后来cookie又被迫承担本地存储的担子,小小身板大能量。 后来localStorage出现了,它是用来分担和代替cookie肩上的担子的。 localStorage和cookie同样遵循浏览器的同源策略,并且存储容量可以达到5-10M。 存储在其中的数据永远也不会过期,除非使用localStorage.removeItem()或者localStorage.clear();
localStorage.setItem('name',"lap" )//存储数据
localStorage.getItem('name')//读取数据
localStorage.removeItem('name')//删除数据
localStorage.clear()//删除所有数据
现在引入axios,并对其封装拦截请求,在src下的http.js(没有的话就新建一个),下面的代码可以跳过,直接看解析。
import axios from 'axios'
import {Message,Loading} from 'element-ui'
import router from './router'
let loading;
function startLoading(){
loading = Loading.service({
lock:true,
text:'Loading...',
background:'rgb(0,0,0,0.7)'
});
}
function endLoading(){
loading.close();
}
axios.interceptors.request.use(//发送请求前拦截请求,将eleToken加入到headers.Authorization
(config)=>{
startLoading();
if(localStorage.eleToken){//第一次登录时eleTokenk肯定是空的,如果有则说明是已登录用户,已登录则要设置请求头带上token
config.headers.Authorization = localStorage.eleToken;//设置请求头带上token
}
return config;
},
(error)=>{
return Promise.reject(error);
}
)
axios.interceptors.response.use(
(response)=>{//返回拦截
endLoading();
return response;
},error=>{
endLoading();
Message.error("请求出错,请重试!");
let { status } = error.response;
if(status == 401){
Message.error("时间已过期,请重新登录!");
localStorage.removeItem("eleToken");
router.push('/login');
}
return Promise.reject(error);
}
)
export default axios;
上面出现了headers.Authorization,字段跨域存放token凭证, 服务器通过这个字段认证请求者的身份。上面代码表明axios每次发送请求 都会被拦截下来填装headers.Authorization,如果本地有eleToken说明登录了,然后把token填上去。 如果为空,说明是登录请求。当请求返回,也被axios拦截,判断返回状态,做相应处理。
重头戏来了,其实跨域这个问题大家肯定也是看了n篇文章了吧,真的是老生常谈, 但是呢这个还是需要讲一讲的。不过不是讲跨域是什么,而是讲比较我个人对跨域和代理的理解。 首先基于浏览器的同源安全策略,浏览器如果直接请求不同域的后台,那么浏览器会报错。 首先要明白跨域只会发生在浏览器,如果是不同域的服务器请求服务器则不会发生, 比如说你用php的curl,nodejs的request,postman...发送请求给服务器都不会报跨域的错。 后面会讲nginx的代理,可以解决跨域。
根本的解决办法就是在后台接受请求时设置cors,以NodeJs为例res.header("Access-Control-Allow-Origin", "*"); *说明服务器允许所有请求。一般还是得设置个白名单,只允许名单里的请求,这是给浏览器看的。其实浏览器 发送请求给服务器,即使跨域了,服务器也会处理这个请求并返回数据,只是浏览器把着关,只要response的 响应头Access-Control-Allow-Origin的值与浏览器发送请求的当前域是不同域,那么这个响应就会被浏览器挡住。 浏览器发送请求时headers会有origin字段(ajax2才有,不过现在基本上都是ajax2了),后台对其验证,通过 了,那么response响应头会有Access-Control-Allow-Origin:*或者是当前域。然后我个人感觉服务器配置好cors 才是解决跨域的根本方法,像jsonp什么的就是耍流氓,别喷我,开个玩笑,调侃一下。
另外,vue在本地开发环境时会有个devServer下的proxy配置,肯定有许多人配过这个,我也配过。不过这个东西我现在觉得 有点鸡肋,于是我把它注释掉了,照样运行。
为什么我说它用处不大呢?理由如下:
0.解决跨域只要后台cors设置好就不会有跨域的错,它这里搞个代理用处不大。
1.这个东西只有在开发环境有用,在线上的时候还是得改接口。即使上面target改成线上地址, 我npm run build后打包,axios请求的地址仍然不是线上地址。所以我想了一个办法可以解决: 在src/main.js添加下面代码
(process.env.NODE_ENV === 'production'){ // 生产环境,线上环境
Vue.prototype.host = 'http://node_api.connectyoume.top';
}else if(process.env.NODE_ENV === 'test'){ //测试环境
Vue.prototype.host = '';
}else if(process.env.NODE_ENV === 'development'){ // 开发环境
Vue.prototype.host = 'http://localhost:8009';
}
process.env.NODE_ENV有三个值'production'(生产环境),'development'(开发环境),'test'(测试环境) process.env.NODE_ENV会根据你的编译环境改变,
当你运行npm run serve时,process.env.NODE_ENV的值为'development';
当你运行npm run build时,process.env.NODE_ENV的值为'production';
process.env.NODE_ENV的值为test时我也没用过,没搞过测试。
然后Vue.prototype.host的值就会根据你执行的命令不同对应到不同的值,然后我们知道在 组件中可以用this访问Vue实例,于是axios发送请求时用this.host+接口路由,比如:
mounted(){
this.$axios.get(this.host + "/api/quote/getQuote")
.then((res)=>{
let data = res.data.data;
if(data){
this.img.content = data.content;
this.img.address = data.origin_img_urls[0];
this.img.author = data.author;
this.img.translation = data.translation;
}})
.catch((err)=>{
console.log(err);
})
}
如果是开发环境:this.host+"/api/quote/getQuote"等同于http://localhost:8009/api/quote/getQuote
如果是线上环境:this.host+"/api/quote/getQuote"等同于http://node_api.connectyoume.top/api/quote/getQuote
虽然每次要加个this.host,但是可以省去我打包后上线的接口问题。
本来这只是个解码token的,但是因为跟jsonwebtoken有关,所以还是讲一下。 因为token是有三段,由两个逗号隔开,被base64加密了一下。 里面存放的可以是用户名,用户id什么的。使用jwt-decode: 安装:npm install jwt-decode 在组件里import jwt_decode from 'jwt-decode'; 前台登录完后,后台返回token,let decoded = jwt_decode(token); 详细代码的话在Login.vue里。后面会贴出仓库地址,有兴趣的可以看一下。
个人觉得这款富文本编辑器相当精巧好看,并且还支持vue,react,angular等,挺不错的。 缺点就是加载太慢了,人家网站在国外,然后还是太慢了。。。
如何使用它呢,官方文档全是英文,考验英语水平的时候到了。英语就英语呗,还不是照样搞定它 在vue里安装和使用使用它:npm install @tinymce/tinymce-vue
在vue组件中使用它:
import Editor from '@tinymce/tinymce-vue';
export default {
components: {
'editor':Editor}
},
inymce的初始化可以好好看一下文档,定制成你想要的样式。然后就是获得编辑框的内容是通过 v-model="temporarySave.content",内容全是html字符,然后发送提交给后台,后台存数据库, 然后要用的时候再把html字符串显示出来,那么就跟编辑时的样式一样。 这里主要是讲那个api-key,没有这个api-key它会一直给你个警告并且好像一些功能也用不了, 不美观。所以要得到这个api-key,而且这个api-key还是比较容易得到的, 去官网注册一下账号(官网真好看,非常舒服),进入到右上角的My Count,然后再点那个API Key Manage,就会出现 api-key,Copy一下ok,然后事情还没完,它下面要加个域名访问权限,有这个权限的域才可以使用刚才得到 api-key。默认已经有localhost,但是如果是127.0.0.1,还是得加上去,如果是自己的域名的话也得加上去, 加子域名就行了。不然没有权限的域他还是报警告,对了,填完域还得点那个UPDATE API KEY,它得更新一下,可能要一会, 全球cdn得更新一下,官方说可能要20分钟,我倒是update之后就立马生效了 。对了我的key你们应该用不了, 因为我的域名权限只加了三个:localhost,127.0.0.1,connectyoume.top,如果是本地开发的话用我的api-key 应该没问题不过我也没试过。大家如果想试一下这个富文本编辑器的话可以试试我的apiKey="px3f3ogu2ob3hoqc6oiosfldxiju2f4br3s695fd1v4ssvi6", 如果想更方便的话还是要注册一个,反正也不是很费时间。 放个图片吧:
剩下一些杂七杂八的小物件,比如布局啊,自定义滚动条, 数据库取出博客html字符串然后显示在页面上等等。 布局我用的是flex,说起flex,我很喜欢一个文档,很舒服:http://cssreference.parryqiu.com/ 。自定义滚动条要用到三个伪类,不会很难,花几分钟就可以做好。 然后就是html字符串在页面显示。我也是用的tinymce的编辑面板,然后加个disable属性,但是由于tinymce 首部有一个插件栏,而我只需要编辑板,所以我把首部去掉了(在组件的生命周期中把首部去掉了)。还有就是css 平滑滚动,只要给目标容器加一个css属性scroll-behavior: smooth;,然后运用锚点链接就行了。
原文链接:http://lapblogs.connectyoume.top
Github:https://github.com/LAPFUTURE/LAPBlogs