我是使用sharedb 作为后端 ,然后前端使用的elementUI样式,编写的一个值班小工具。接下来,让我们先来了解一下sharedb是什么吧?
- sharedb工具
github地址:https://github.com/share/sharedb.git。
官方概念:ShareDB是基于JSON文档的操作转换(OT)的实时数据库后端。它是DerbyJS Web应用程序框架的实时后端。
特征:
- 实时同步任何JSON文档
- 并发多用户协作
- 具有异步最终一致性的同步编辑API
- 实时查询订阅
- 与任何数据库轻松集成-MongoDB,PostgresQL(实验性)
- 通过发布/订阅集成可水平扩展
- 从文档和操作中选择所需字段的投影
- 用于实现访问控制和自定义扩展的中间件
- 非常适合在浏览器或服务器上使用
- 重新连接后脱机更改同步
- 用于单元测试的数据库和pub / sub的内存中实现
在这里,我只列出sharedb的概念以及特征,其中的其他特性(包括中间件等等),大家可以自行去github上去看。
对于我来说,我是把github上的代码克隆下来,然后选择了其中的counter作为例子模板,去编写工具代码,首先对其中的server.js进行更改.
在server.js中,我只改了 doc.create({ name1: [], date: [] }, callback);这一行代码,在sharedb文档中doc.create(data[, type][, options][, function(err) {...}])
在本地创建文档,然后将创建操作发送到服务器。因为对于我的需求,就是要将名字,以及对应名字所选的日期发送到服务器上,所以在这里我创建了这个对象。
server.js
var http = require('http'); var express = require('express'); var ShareDB = require('sharedb'); var WebSocket = require('ws'); var WebSocketJSONStream = require('websocket-json-stream'); var backend = new ShareDB(); createDoc(startServer); // Create initial document then fire callback function createDoc(callback) { var connection = backend.connect(); var doc = connection.get('examples', 'counter'); doc.fetch(function (err) { if (err) throw err; if (doc.type === null) { doc.create({ name1: [], date: [] }, callback); return; }; callback(); }); } function startServer() { // Create a web server to serve files and listen to WebSocket connections var app = express(); app.use(express.static('static')); var server = http.createServer(app); // Connect any incoming WebSocket connection to ShareDB var wss = new WebSocket.Server({ server: server }); wss.on('connection', function (ws, req) { var stream = new WebSocketJSONStream(ws); backend.listen(stream); }); server.listen(8080); console.log('Listening on http://localhost:8080'); }
client.js代码:
var sharedb = require('sharedb/lib/client'); // Open WebSocket connection to ShareDB server var socket = new WebSocket('ws://' + window.location.host); var connection = new sharedb.Connection(socket); // Create local Doc instance mapped to 'examples' collection document with id 'counter' var doc = connection.get('examples', 'counter'); // 获取文档的初始值并订阅更改 doc.subscribe(showNames); doc.subscribe(dateRanges); // 当文档更改时(由此客户端或任何其他客户端或服务器), // 更新页面上的名字以及日期范围 doc.on('op', showNames); doc.on('op', dateRanges);
function dateRanges() { app.$data.items = doc.data.date[0]; }; function showNames() { app.$data.messages1 = doc.data.name1[0] ? doc.data.name1[0] : []; }; // 当点击提交名字的时候,更改本地的名字,并将同步更改服务器和其它链接的客户端//提交日期 function submite() { doc.submitOp([{ p: ['date', 0], li: app.$data.items }]); }; //提交名字 function display() { doc.submitOp([{ p: ['name1', 0], li: app.$data.messages1 }]); }; // Expose to index.html global.display = display; global.submite = submite;
html代码
这个代码就没什么好说的啦,主要功能 就是可以先输入名字,然后再选择想要进行值班的日期。而输入的名字不可以有重复的,主要是靠一个复选框实现的,以及日期选择器,感兴趣的同学可以看看哦!,大家也可以看到这里面引用的js是bundle.js,所以我们要把写在client.js中的代码,复制到bundle.js中才可以实现哦。
<!DOCTYPE html> <meta charset="utf-8"> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <link rel="icon" href="1.ico"> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <title>值班小工具</title> <body> <div id="app" > <router-view> </router-view> </div> </body> <script src="dist/bundle.js"></script> <script> const inputName = { template: `<div> <el-header> <el-input id="date" placeholder="请输入用户名" name="date" v-model="message"></el-input> <el-button v-on:click="display1" type="primary">提交 名字</el-button> </el-header> <el-main> <span class="date">日 期</span> <span class="name">姓 名</span> <el-checkbox-group v-model="checked" > <li v-for="(item,index) in $root.items" :key="item.checked"> <el-checkbox v-on:change="checked1(index,checked)" :label="item" name="item" > {{item}} <span class="messages">{{[$root.messages1[index]].join("|")}}</span> </el-checkbox> </li> </el-checkbox-group> </el-main> </div>` , data() { name: inputName; return { message: '', messages1: [], checked: [] } }, methods: { checked1: function () { }, display1: function (index, checked) { var a = document.getElementsByName('item'); this.messages1 = this.$root.messages1; var cashName = document.getElementById("date").value; var result = cashName.match(/[\s`~!@#¥$%^&*()_+<>?:"{},.\/;'[\]\w]/im); for (var i = 0; i < a.length; i++) { if (result !== null) { this.$message({ message: '请输入正确的名字哦!', type: 'warning' }); break } if (a[i].checked && this.messages1[i] == null) { this.messages1[i] = new Array; } if (a[i].checked && this.messages1[i] !== null && this.messages1[i][0] !== this.message) { this.messages1[i].push(this.message); } if (a[i].checked && this.messages1[i] !== null && this.messages1[i].length > 2) { this.messages1[i].pop(this.message); this.$message({ message: '前面已经有两人选择了哦,请选择其它日期吧!', type: 'warning' }); } } display() } } }; const inputDate = { template: `<div> <el-header> <el-date-picker v-model="value" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" format="yyyy年M月d日" value-format="yyyy-MM-dd" v-on:change="change1" > </el-date-picker> <el-button onclick="submite()" type="primary">提交 日期</el-button> </el-header> <el-main> <span class="date">日 期</span> <span class="name">姓 名</span> <li v-for="(item,index) in $root.items" :key="item.index"> {{item}} <span class="messages1">{{[$root.messages1[index]].join('&')}}</span> </li> </el-main> </div>`, data() { name: inputDate; return { items: [], value: '', } }, methods: { change1(value) { var begin = value[0]; var end = value[1]; var item = new Array(); app.$data.items = item; var ab = begin.split("-"); var ae = end.split("-"); var db = new Date(); db.setUTCFullYear(ab[0], ab[1] - 1, ab[2]); var de = new Date(); de.setUTCFullYear(ae[0], ae[1] - 1, ae[2]); var unixDb = db.getTime(); var unixDe = de.getTime(); for (var k = unixDb; k <= unixDe;) { item.push(new Date(parseInt(k)).format().toString()); k = k + 24 * 60 * 60 * 1000; } } } }; const routes = [ { path: '/inputDate', component: inputDate }, { path: '/inputName', component: inputName } ]; const router = new VueRouter({ routes }); Date.prototype.format = function () { var s = ""; s += this.getFullYear() + "-"; s += this.getMonth() + 1 + "-"; s += this.getDate(); return s; }; var app = new Vue({ router, data() { return { value6: '', items: [], checked: [], message: '', messages1: [], checked: [] } } }).$mount('#app'); </script> <style scoped> #app { /* width: 1200px; height: 848px; */ background-position: center; padding-top: 0%; } body { margin: 0%; } .el-checkbox__label { display: inline-block; padding-left: 10px; line-height: 19px; font-size: 14px; width: 100%; } .el-date-picker { width: 30%; } h3 { margin: 40px 0 0; } a { color: #42b983; } .el-header { color: #333; text-align: center; line-height: 88px; } li { padding-top: 2%; list-style-image: url('./4.ico'); } p { font-size: 20px; font-family: 'Segoe UI', Tahoma, Verdana, sans-serif } .date { padding-left: 10%; } .name { padding-left: 40%; } .el-main { padding-top: 1%; padding-left: 35%; width: 70%; height: 550px; } .el-input { width: 30%; } .messages1 { float: right; padding-right: 27%; text-decoration: underline; } .messages { float: right; padding-right: 24%; text-decoration: underline; } .el-checkbox { width: 80%; color: black; } </style>
第一次写博客,可能有些地方写的不是很完整,欢迎大家提出意见!