p-note是一个比较完善的前后端项目,也算是对最近WEB相关知识学习交的一次作业。页面内容还不尽完善,已经转入了迭代维护的模式,这里先贴一下项目的链接。可以感受一下。
功能介绍呢?就是一个实现了阅后即焚的站点。这个项目是仿写的,原项目 vua.sh。模仿了UI设计,方案和后段内容是自己设计。
技术简介
技术栈
这个项目目前使用到的技术,以及技术栈,都向最新看齐,来实现快速学习和快速成长。
使用的技术栈:
- Serverless 函数服务部署
- git integration 实现push 后的自动部署
- 基于 Vue 的 Element 实现前端页面设计
- Nodejs 的 Koa 后端
- Mongo Altas 数据库API服务
设计原理
前端通过 RSAnode 库来生成 RAS 密钥对,通过公钥来进行内容加密。加密内容通过 POST 传递到后端(注,后端不做解密操作),后端直接以 key:cipher
的方式来进行入库。直到内容再被请求的时候,查库得到结果之后删除数据,返回加密数据,前端使用 密钥来进行解密。得到原始数据,完成阅后即焚。
前端设计
前端使用的是 vur + element ui 这套常见的方案来实现的开发,这里主要对其中的一些点来进行总结。
个人理解的vue
这里先从总的触发器说说自己理解中的VUE和 MVVM 模型。VUE 较比之前写的一些前端的内容,其最大的优势,目前感觉就是 MVVM 的方式(当然,可能是我目前接触较浅)。 与之前使用 JQuery 不同的是,JQuery 需要不断的去查询数据,和写数据来写或者读DOM的值。
但是这些在 VUE中已经使用了 VM层(viewmodel)层来把数据进行了双向的绑定:JS中的变量改变会使得DOM更新,反正JS中的变量值也会更新。实例代码如下所示:
<el-card shadow="never">
<p style="overflow-wrap:break-word">{{host}}</p>
</el-card>
<script>
data() { return {
get origin() {return location.origin; },
get host() {return location.origin + "/#/" + this.cipherB64;}
}}
</script>
view 与 components
view 可以理解为页面内容,而Component是在各个vue中复用的。
APP.vue 中引用各个 view 可以根据 vue-router来SPA来达到多页面的效果。
view 中 可以复用各个 Component 来避免重复造轮子。
在vue 中,两个东西引入的方式很类似,引入代码如下:
<template>
<div id="app">
<!-- 这里引入了插件 -->
<Pnote />
</div>
</template>
<script>
import Pnote from "@/views/Pnote.vue";
export default {
name: "app",
components: {
Pnote
}
};
</script>
条件渲染
VUE 可以通过 v-if 的语句来实现动态的条件渲染,来决定渲染那些内容,在v-if 块里面支持 js 的条件语句
<div v-if="sentStatus == Status.EDIT">
<el-button type="primary" style="width:100%; height:70px" v-on:click="postData">Submit it</el-button>
</div>
<div v-else-if="sentStatus == Status.MSG">
<el-button type="primary" style="width:100%; height:70px" v-on:click="goHome">Delete it</el-button>
</div>
<div v-else>
<el-button type="primary" style="width:100%; height:70px" v-clipboard:success="copy2board" v-clipboard:copy="host">Copy it</el-button>
</div>
容器布局
element ui 可以使用 容器布局 来进行快速的常规布局。
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
mount 只执行一次
mount 在页面渲染的时候会执行,但是当页面dom 发生变化的时候,mount 也会被调用。所以就需要设置一个标志位,使得这一段只执行一次。
data() { return { firstPlayFlag: true };},
mounted() {
if(this.firstPlayFlag) {
this.showMsg();
this.firstPlayFlag = false;
}
}
VueClipboard
点击快速的复制vue变量的值到剪切板,success 里面的是回调函数,copy 是vue的namespace 的host。
<div v-else><el-button type="primary" style="width:100%; height:70px" v-clipboard:success="copy2board" v-clipboard:copy="host">Copy it</el-button>
element 通知框
element UI 可以快速的使用预置的通知框,具体的弹出代码如下
that.$notify({ type: 'success', title: 'success', message: 'Submit Successfully'});
that.$notify.error({title: 'error', message: 'Submit failed'});
RSA 密钥对生成
使用 RSAnode 来实现密钥生成,以及加解密函数。
rsa: function() {
const key = new NodeRSA({ b: 512 });
let publicKey = key.exportKey("pkcs1-public-pem"); //公钥
let privateKey = key.exportKey("pkcs1-private-pem"); //私钥
return {
RSAencrypt: function(pas) {
console.log("encrypt user data");
console.log(this.GetPrivateKeyB64());
return key.encrypt(pas, "base64");
},
importPrivateKeyB64: function(privateKeyB64) {
const privateKey = new Buffer(privateKeyB64, "base64").toString(
"ascii"
);
key.importKey(privateKey, "pkcs1-private-pem");
},
//解密方法
RSAdecrypt: function(pas) {
return key.decrypt(pas, "utf-8");
},
GetPrivateKey: function() {
return privateKey;
},
GetPubilcKey: function() {
return privateKey;
},
GetPubilcKeyB64: function() {
let publicKeyB64 = new Buffer(publicKey).toString("base64");
return publicKeyB64;
},
GetPrivateKeyB64: function() {
let privateKeyB64 = new Buffer(privateKey).toString("base64");
return privateKeyB64;
}
};