正文
sharedb结合elementUi编写的实时小工具
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
我是使用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>
第一次写博客,可能有些地方写的不是很完整,欢迎大家提出意见!