2020年7月

一、前言

各位FEer,大家好。最近呢,公司项目没有之前那么紧了,我就在自己驱动学习下其他周边知识,因为想做一个全栈型的开发者,所以我就着手学习了Nodejs做后端接口和MongoDB做数据库存储这样一个架构。写了一个原生的移动App。今天我们来分享下MongoDB数据库的学习新得。

二、数据库初识

众所周知,数据库的存在对于技术开发者来说,就好比是仓库,用来存储信息的仓库。而一般数据库又分为关系型数据库和非关系型数据库。关系型数据库比较常见的是Mysql和Oracle,非关系数据库比较常见的是memcached(key-value),redis(key-value),和mongoDB(Document-oriented)等等很多NoSQL数据库。

三、MongoDB的特点

MongoDB是一个介于关系型数据库和非关系型数据库之间的产品,是非关系型数据库当中功能最丰富,最像关系数据库的。他支持的数据库结构非常松散,类似json的bjson格式,因此可以存储比较复杂的数据类型。Mongodb最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

特点

  • 高性能
  • 易部署
  • 易使用
  • 存储数据非常方便

    主要功能特性

  • 面向集合存储,易存储对象类型的数据 “面向集合”(Collenction-Orented)意思是数据库被分组存储在数据集中,被称为一个集合(Collenction)每个 集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档,集合的概念类似关系型数据库(RDBMS)里的表(table)不同的是它不需要定义任何模式(schema)
  • 模式自由 模式自由(schema-free)意为着存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。
  • 支持动态查询
  • 支持完全索引,包含内部对象
  • 支持查询
  • 支持复制和故障恢复
  • 使用高效的二进制数据存储,包括大型对象
  • 自动处理碎片、以支持云计算层次的扩展性

学习细节

1、启动mongoDB数据库

xuhao@localhost private-code$ cd MongoDB-Project/
xuhao@localhost MongoDB-Project$ mongod

2、进入命令行操作

xuhao@localhost MongoDB-Project$ mongo
MongoDB shell version v4.0.13
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("ccf999e2-2300-4438-acef-4a8bb23862f5") }
MongoDB server version: 4.0.13

3、mongo命令行模式下,练习基本操作命令

> var a = 5
> print a
2019-12-09T22:24:39.248+0800 E QUERY    [js] SyntaxError: missing ; before statement @(shell):1:6
> print(a)
5
> function sum(x,y){
... return x+y;
... }
> sum(5,6)
11
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
> use weichuang
switched to db weichuang
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
> db
weichuang
> show collections
> db.user.insert({"name":"xuhao"})
WriteResult({ "nInserted" : 1 })
> db.user.find()
{ "_id" : ObjectId("5dee5a2df4dd815948930114"), "name" : "xuhao" }
> db.user.insert({"name":"luolanyu"})
WriteResult({ "nInserted" : 1 })
> db.user.find()
{ "_id" : ObjectId("5dee5a2df4dd815948930114"), "name" : "xuhao" }
{ "_id" : ObjectId("5dee5a75f4dd815948930115"), "name" : "luolanyu" }
> db.user.findOne()
{ "_id" : ObjectId("5dee5a2df4dd815948930114"), "name" : "xuhao" }
> db.user.remove({"name":"xuhao"})
WriteResult({ "nRemoved" : 1 })
> db.user.find()
{ "_id" : ObjectId("5dee5a75f4dd815948930115"), "name" : "luolanyu" }
> db.user.drop()
true
> db.user.find()
> load('./1.js')
connecting to: mongodb://127.0.0.1:27017/weichuang
Implicit session: session { "id" : UUID("a2e0831a-e3ee-449d-98bc-62ab536381e3") }
MongoDB server version: 4.0.13
Insert Success!
true

// 清空数据库
> db.user.drop()
true
// 查询数据库(此时为空)
> db.user.find()
> 

// 插入多个数据
> load('2.js')
connecting to: mongodb://127.0.0.1:27017/weichuang
Implicit session: session { "id" : UUID("f3d004c8-20d0-4d0e-a5e9-0ec57b273d8a") }
MongoDB server version: 4.0.13
Insert Success!
true

> db.user.find()
{ "_id" : ObjectId("5dee627166e1e1543cfcf6b9"), "name" : "xutiantian", "age" : 11, "hobby" : [ "画画", "弹琴", "民族舞" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5dee627166e1e1543cfcf6ba"), "name" : "wangqianqian", "age" : 12, "hobby" : [ "毛笔字", "弹琴", "民族舞" ], "piano" : { "brand" : "Fazioli", "price" : 110000 } }
{ "_id" : ObjectId("5dee627166e1e1543cfcf6bb"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "吃饭", "弹琴", "民族舞" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// 更新数据库中的数据(错误方式,会覆盖并丢数据)
> db.user.update({name:'xutiantian'},{age:10})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5dee627166e1e1543cfcf6b9"), "age" : 10 }
{ "_id" : ObjectId("5dee627166e1e1543cfcf6ba"), "name" : "wangqianqian", "age" : 12, "hobby" : [ "毛笔字", "弹琴", "民族舞" ], "piano" : { "brand" : "Fazioli", "price" : 110000 } }
{ "_id" : ObjectId("5dee627166e1e1543cfcf6bb"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "吃饭", "弹琴", "民族舞" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// 某一条数据更新(正确方式,但不方便)
> db.user.update({ name: 'xutiantian' }, {
...   name: 'xutiantian',
...   age: 10,
...   hobby: ['画画', '弹琴', '民族舞'],
...   piano: {
...     brand: 'Bluthner',
...     price: 140000
...   }
... })
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5dee649f66e1e1543cfcf6bf"), "name" : "xutiantian", "age" : 10, "hobby" : [ "画画", "弹琴", "民族舞" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5dee649f66e1e1543cfcf6c0"), "name" : "wangqianqian", "age" : 12, "hobby" : [ "毛笔字", "弹琴", "民族舞" ], "piano" : { "brand" : "Fazioli", "price" : 110000 } }
{ "_id" : ObjectId("5dee649f66e1e1543cfcf6c1"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "吃饭", "弹琴", "民族舞" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// // 某一条数据更新(正确方式,方便)
> db.user.update({name:'xutiantian'},{$set:{age: 11.5}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5dee649f66e1e1543cfcf6bf"), "name" : "xutiantian", "age" : 11.5, "hobby" : [ "画画", "弹琴", "民族舞" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5dee649f66e1e1543cfcf6c0"), "name" : "wangqianqian", "age" : 12, "hobby" : [ "毛笔字", "弹琴", "民族舞" ], "piano" : { "brand" : "Fazioli", "price" : 110000 } }
{ "_id" : ObjectId("5dee649f66e1e1543cfcf6c1"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "吃饭", "弹琴", "民族舞" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

> db.user.drop()
true
> db.user.find()
> load('2.js')
connecting to: mongodb://127.0.0.1:27017/weichuang
Implicit session: session { "id" : UUID("a391815d-fd2a-4012-819f-b488ecbfb648") }
MongoDB server version: 4.0.13
Insert Success!
true
> db.user.find()
{ "_id" : ObjectId("5defb269af75827244d1f227"), "name" : "xutiantian", "age" : 11, "hobby" : [ "画画", "弹琴", "民族舞" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5defb269af75827244d1f228"), "name" : "wangqianqian", "age" : 12, "hobby" : [ "毛笔字", "弹琴", "民族舞" ], "piano" : { "brand" : "Fazioli", "price" : 110000 } }
{ "_id" : ObjectId("5defb269af75827244d1f229"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "吃饭", "弹琴", "民族舞" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// 删除一条数据中的某个值(unset)
> db.user.update({name:'wangqianqian'},{$unset:{'hobby':''}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5defb269af75827244d1f227"), "name" : "xutiantian", "age" : 11, "hobby" : [ "画画", "弹琴", "民族舞" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5defb269af75827244d1f228"), "name" : "wangqianqian", "age" : 12, "piano" : { "brand" : "Fazioli", "price" : 110000 } }
{ "_id" : ObjectId("5defb269af75827244d1f229"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "吃饭", "弹琴", "民族舞" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// upsert: 如果有某一个属性,则去更新,如果没有这个属性,则插入这个属性
> db.user.update({name:'xutiantian'},{$set: {age: 10}},{upsert: true})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5defb269af75827244d1f227"), "name" : "xutiantian", "age" : 10, "hobby" : [ "画画", "弹琴", "民族舞" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5defb269af75827244d1f228"), "name" : "wangqianqian", "age" : 12, "piano" : { "brand" : "Fazioli", "price" : 110000 } }
{ "_id" : ObjectId("5defb269af75827244d1f229"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "吃饭", "弹琴", "民族舞" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// multi  给每条数据的某个属性统一为一个值, 如果没有multi: true,则只会作用于第一条数据
> db.user.update({}, {$set: {hobby:['弹琴']}}, {multi: true})
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
> db.user.find()
{ "_id" : ObjectId("5defb269af75827244d1f227"), "name" : "xutiantian", "age" : 10, "hobby" : [ "弹琴" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5defb269af75827244d1f228"), "name" : "wangqianqian", "age" : 12, "piano" : { "brand" : "Fazioli", "price" : 110000 }, "hobby" : [ "弹琴" ] }
{ "_id" : ObjectId("5defb269af75827244d1f229"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "弹琴" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// push 在某条数据中给数组格式的数据属性中添加一个新的值
> db.user.update({name: 'liangyunwei'}, {$push:{hobby: '玩游戏'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5defb269af75827244d1f227"), "name" : "xutiantian", "age" : 10, "hobby" : [ "弹琴" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5defb269af75827244d1f228"), "name" : "wangqianqian", "age" : 12, "piano" : { "brand" : "Fazioli", "price" : 110000 }, "hobby" : [ "弹琴" ] }
{ "_id" : ObjectId("5defb269af75827244d1f229"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "弹琴", "玩游戏" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// addToSet 查找某条数据中数组格式的数据属性中是否有这个属性值(检查),如果不存在,则插入
// 如果是push,并不会进行检查,则插入的数据可能会重复
> db.user.update({name: 'xutiantian'}, {$addToSet: {hobby: '睡觉'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5defb269af75827244d1f227"), "name" : "xutiantian", "age" : 10, "hobby" : [ "弹琴", "睡觉" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5defb269af75827244d1f228"), "name" : "wangqianqian", "age" : 12, "piano" : { "brand" : "Fazioli", "price" : 110000 }, "hobby" : [ "弹琴" ] }
{ "_id" : ObjectId("5defb269af75827244d1f229"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "弹琴", "玩游戏" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// each 把好几个属性每一个都插入到数据库中
> var newHobby = ['吃零食','出去玩','学习'];
> db.user.update({name: 'xutiantian'}, {$addToSet: {hobby:{$each: newHobby}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5defb269af75827244d1f227"), "name" : "xutiantian", "age" : 10, "hobby" : [ "弹琴", "睡觉", "吃零食", "出去玩", "学习" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5defb269af75827244d1f228"), "name" : "wangqianqian", "age" : 12, "piano" : { "brand" : "Fazioli", "price" : 110000 }, "hobby" : [ "弹琴" ] }
{ "_id" : ObjectId("5defb269af75827244d1f229"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "弹琴", "玩游戏" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// 把某个属性中的值(按照下标)修改
> db.user.update({name: 'xutiantian'}, {$set: {'hobby.0':'看动画片'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5defb269af75827244d1f227"), "name" : "xutiantian", "age" : 10, "hobby" : [ "看动画片", "睡觉", "吃零食", "出去玩", "学习" ], "piano" : { "brand" : "Bluthner", "price" : 140000 } }
{ "_id" : ObjectId("5defb269af75827244d1f228"), "name" : "wangqianqian", "age" : 12, "piano" : { "brand" : "Fazioli", "price" : 110000 }, "hobby" : [ "弹琴" ] }
{ "_id" : ObjectId("5defb269af75827244d1f229"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "弹琴", "玩游戏" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

//findAndModify 应答式的,会返回成功或失败的结果 
// 3.js
var modify = {
  findAndModify: 'user',
  query: {name: 'xutiantian'},
  update: {$set: {age: 11}},
  new: true
};

var result = db.runCommand(modify);
printjson(result);

> load('3.js')
{
        "lastErrorObject" : {
                "n" : 1,
                "updatedExisting" : true
        },
        "value" : {
                "_id" : ObjectId("5defb269af75827244d1f227"),
                "name" : "xutiantian",
                "age" : 11,
                "hobby" : [
                        "看动画片",
                        "睡觉",
                        "吃零食",
                        "出去玩",
                        "学习"
                ],
                "piano" : {
                        "brand" : "Bluthner",
                        "price" : 140000
                }
        },
        "ok" : 1
}
true

> db.user.drop()
> load('2.js')

// 按条件范围查询查找 大于等于12 小于等于15
> db.user.find( 
...   {age: {$gte:12, $lte: 15}}
... )
{ "_id" : ObjectId("5df4b5da39980975e9ca7b9a"), "name" : "wangqianqian", "age" : 12, "hobby" : [ "毛笔字", "弹琴", "民族舞" ], "piano" : { "brand" : "Fazioli", "price" : 110000 } }
{ "_id" : ObjectId("5df4b5da39980975e9ca7b9b"), "name" : "liangyunwei", "age" : 12, "hobby" : [ "吃饭", "弹琴", "民族舞" ], "piano" : { "brand" : "C. Bechstein", "price" : 310000 } }

// 按条件范围查找,大于10,小于14
> db.user.find( 
...   {age: {$gt:10, $lt: 14}}, 
...   {name: true, age: true}
... )
{ "_id" : ObjectId("5e0aacf66ad7fc9f6c8bc5b8"), "name" : "xutiantian", "age" : 11 }

// 按条件查找,含某些条件
> db.user.find(
...   {age: {$in: [10,11]}},
...   {name: true, age: true, _id: false}
... )
{ "name" : "xutiantian", "age" : 11 }
>

// “或”逻辑,按条件查找,满足其一就行
> db.user.find({
...   $or: [
...     {age: {$gte: 18}},
...     {'piano.brand': 'Fazioli'}
...   ]},  
...   {name: true, age: true, _id: false}
... )
{ "name" : "wangqianqian", "age" : 14 }
{ "name" : "liangyunwei", "age" : 18 }

// “与”逻辑,全部条件同时满足进行查询
// db.user.find({
//   $and: [
//     {age: {$gte: 18}},
//     {'piano.brand': 'Fazioli'}
//   ]},   
//   {name: true, age: true, _id: false}
// )
// 无数据满足

// “非逻辑”,查找不是当前条件的数据项 not

// 精确匹配 必须全部满足
// 如果有[],则表示数据要完全一致,才能被查到
> db.user.find(
...  {hobby: ['毛笔字', '弹琴', '民族舞']},
...  {name: true, age: true, _id: false}
...)
{ "name" : "wangqianqian", "age" : 14 }

// 模糊查询,
// 没有[], 只要含这个条件,则筛选出所有数据
> db.user.find(
...  {hobby: '弹琴'},
...  {name: true, age: true, _id: false}
...)

// 数组查询 ,$all, 需要这些条件都存在,才符合条件 
> db.user.find(
...   {hobby: {$all: ['画画', '弹琴']}},
...   {name: true, age: true, _id: false}
... )
{ "name" : "xutiantian", "age" : 11 }

// 数组查询 ,$in, 需要这些条件符合一个,即可
> db.user.find(
...   {hobby: {$in:['画画', '吃饭']}}, 
...   {name: true, age: true, _id: false}
... )
{ "name" : "xutiantian", "age" : 11 }
{ "name" : "liangyunwei", "age" : 18 }

// 数组查询 ,可根据某个数据项的个数去筛选
> db.user.find(
...   {hobby: {$size:3}}, 
...   {name: true, age: true, _id: false}
... )
{ "name" : "xutiantian", "age" : 11 }
{ "name" : "wangqianqian", "age" : 14 }
{ "name" : "liangyunwei", "age" : 18 }

// 分页查询,
其中limit代表每次显示几条数据,
skip代表跳过几条数据,
sort代表排序【-1是降序,1是升序】
> db.user.find(
...   {},
...   {name: true, age: true, _id: false}
... ).limit(1).skip(0).sort({age: -1})
{ "name" : "liangyunwei", "age" : 18 }

四、总结

前端技术庞而杂,所以我们需要不断的精进,提高技术的深度和广度。谢谢各位同学,如果这篇文章对您有用的话,麻烦记得点赞收藏哦!

一、前言

各位FEer,你们好! 在我们的前端开发生涯中,有着许许多多的细枝末节,有的需要兼容低版本ie浏览器,有的是因为需要有更好的用户体验。最近呢,我们公司要为产品中心设计一个官方推广网站,其中的Select下拉框就因为设计师的交互靠原生不能很好的实现,以及效果,所以我就对Select进行了模拟的实现,一起来看看吧。

二、实现细节

涉及到的技术

考虑到兼容型以及最轻量化,我们就没有引用Jquery等,使用原生Javascript和Css来实现select的模拟。

效果展示

模拟select_1.jpeg 模拟select_2.jpeg 模拟select_3.jpeg 模拟select_4.jpeg 模拟select_5.jpeg 模拟select_6.png 模拟select_7.png

三、代码展示

Html结构

<div class="select-box">
    <input type="text" class="select-input" value="" readonly placeholder="地区 省" />
    <ul class="options-box hide">
      <li value="1">北京市</li>
      <li value="2">上海市</li>
      <li value="3">天津市</li>
      <li value="4">重庆市</li>
      <li value="5">河北省</li>
      <li value="6">河南省</li>
      <li value="6">江苏省</li>
      <li value="6">云南省</li>
    </ul>
  </div>

Css结构

/* 公共样式 */
    *,
    body {
      padding: 0;
      margin: 0;
      list-style: none;
      font-size: 14px;
      user-select: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
    }

    .hide {
      display: none;
    }

    /* 模拟下拉框 */
    .select-box {
      position: relative;
      margin: 50px 0 0 100px;
    }

    .select-box .select-input {
      line-height: 20px;
      border: 1px solid #d6d6d6;
      cursor: pointer;
      width: 170px;
      height: 50px;
      border: 1px solid transparent;
      outline: none;
      border-radius: 30px;
      -webkit-border-radius: 30px;
      -moz-border-radius: 30px;
      text-indent: 30px;
      font-size: 16px;
      font-weight: 400;
      /* color: rgba(187, 187, 187, 1); */
      color: rgba(34, 34, 34, 1);
      line-height: 22px;
      margin: 0;
      background: rgba(247, 247, 247, 1) url('./static/imgs/arrow-down.png') no-repeat scroll 130px center;
      background-size: 20px 20px;
      cursor: pointer;
      box-sizing: border-box;
    }

    /** input placeholder颜色改变 **/
    .select-box .select-input::-webkit-input-placeholder {
      /* WebKit browsers */
      color: rgba(187, 187, 187, 1);
    }

    .select-box .select-input:-moz-placeholder {
      /* Mozilla Firefox 4 to 18 */
      color: rgba(187, 187, 187, 1);
    }

    .select-box .select-input::-moz-placeholder {
      /* Mozilla Firefox 19+ */
      color: rgba(187, 187, 187, 1);
    }

    .select-box .select-input:-ms-input-placeholder {
      /* Internet Explorer 10+ */
      color: rgba(187, 187, 187, 1);
    }

    .select-box .select-input.isActive {
      background-color: #ffffff;
      border: 1px solid rgba(204, 204, 204, 1);
      background-image: url(./static/imgs/arrow-up.png);
    }

    .select-box .options-box {
      position: absolute;
      top: 55px;
      left: 0;
      width: 170px;
      overflow-y: scroll;
      overflow-x: hidden;
      width: 170px;
      height: 225px;
      background: rgba(255, 255, 255, 1);
      box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.25);
      border-radius: 5px;
    }

    .select-box .options-box li {
      width: 170px;
      height: 45px;
      text-indent: 30px;
      cursor: pointer;
      font-size: 16px;
      font-weight: 400;
      color: rgba(34, 34, 34, 1);
      line-height: 45px;
      background: rgba(255, 255, 255, 1);
    }

    .select-box .options-box li.active {
      background-color: rgba(247, 247, 247, 1);
      color: rgba(2, 176, 159, 1)
    }

JavaScript结构

window.onload = function () {
    // 判断是否有某个class
    function hasClass(ele, cls) {
      return ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
    }
    // //为指定的dom元素添加样式
    function addClass(ele, cls) {
      if (!hasClass(ele, cls)) ele.className += " " + cls;
    }
    // //删除指定dom元素的样式
    function removeClass(ele, cls) {
      if (hasClass(ele, cls)) {
        var reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
        ele.className = ele.className.replace(reg, " ");
      }
    }
    // //如果存在(不存在),就删除(添加)一个样式
    // function toggleClass(ele, cls) {
    //   if (hasClass(ele, cls)) {
    //     removeClass(ele, cls);
    //   } else {
    //     addClass(ele, cls);
    //   }
    // }

    document.getElementsByClassName('select-input')[0].onclick = function () {
      var optionsBox = document.getElementsByClassName('options-box')[0];
      var selectInput = document.getElementsByClassName('select-input')[0];
      // 这里最好用children,不要用childNode, 否则会有多余的text节点
      var lis = optionsBox.children;
      if (hasClass(optionsBox, 'hide')) { // 如果当前不是正在打开选项状态
        removeClass(optionsBox, 'hide')
        addClass(selectInput, 'isActive')
        for (var i = 0; i < lis.length; i++) {
          if (lis[i].innerHTML == selectInput.value) { // 如果之前已经选择过,将之前的选项激活状态
            addClass(lis[i], 'active')
          } else {
            removeClass(lis[i], 'active')
          }
        }
      } else {
        addClass(optionsBox, 'hide');
        removeClass(selectInput, 'isActive');
      }
    }

    document.getElementsByClassName('options-box')[0].onclick = function (e) {
      var optionsBox = document.getElementsByClassName('options-box')[0];
      var selectInput = document.getElementsByClassName('select-input')[0];
      //这一行及下一行是为兼容IE8及以下版本
      e = e || window.event;
      var target = e.target || e.srcElement;
      if (target.tagName.toLowerCase() === "li") {
        // 将选中的值赋值给展示框文本
        selectInput.value = target.innerHTML;
        // 关闭选择列表
        addClass(optionsBox, 'hide');
        // 取消展示框的激活状态
        removeClass(selectInput, 'isActive');
      }
    }

    // 列表中选项滑过效果
    document.getElementsByClassName('options-box')[0].onmouseover = function (e) {
    // 事件代理
      var optionsBox = document.getElementsByClassName('options-box')[0];
      var selectInput = document.getElementsByClassName('select-input')[0];
      e = e || window.event;
      var target = e.target || e.srcElement;
      if (target.tagName.toLowerCase() === "li") {
        if (target.innerHTML != selectInput.value) { //如果滑过的不是已经选中的,给予暂时的滑过效果
          addClass(target, 'active');
        }
      }
    }

    document.getElementsByClassName('options-box')[0].onmouseout = function (e) {
      var optionsBox = document.getElementsByClassName('options-box')[0];
      var selectInput = document.getElementsByClassName('select-input')[0];
      //这一行及下一行是为兼容IE8及以下版本
      e = e || window.event;
      var target = e.target || e.srcElement;
      if (target.tagName.toLowerCase() === "li") {
        if (target.innerHTML != selectInput.value) { // 如果滑出的不是已经选中的,将滑过的效果取消
          removeClass(target, 'active');
        }
      }
    }
  }

总结

用原生JavsScript去实现效果的时候,可能有时候会比较麻烦,但是这是根本,其他的框架也好,第三方插件也罢,其实都可以理解为基于它而衍生的语法糖或者简化调用的集合。所谓万变不离其宗,谢谢各位同学,如果这篇文章对您有用的话,麻烦记得点赞收藏哦!

一、前言

作为一个开发者,在我们的工作中,经常会想要维护一个自己的代码库和工作中用的代码库,但是配置它们又是一项比较复杂麻烦的事情,下面分享给大家一些自己配置过程中的步骤以及注意事项。

二、配置步骤

生成SSH密钥 & 配置

  1. 在Terminal终端中使用ssh-keygen -t rsa -C "公司邮箱地址"生成对应的gitlab密钥:id_rsa和id_rsa.pub
  2. 将gitlab公钥即id_rsa.pub中的内容配置到公司的gitlab上
  3. 在Terminal终端中使用ssh-keygen -t rsa -C "github地址" -f ~/.ssh/github_rsa生成对应的github密钥:github_rsa和github_rsa.pub
  4. 将github公钥即github_rsa.pub中的内容配置到自己的github上
  5. 进入密钥生成的位置,创建一个config文件,添加配置:

我们在Terminal终端对Git进行了一系列的配置:

// 进入ssh文件夹
xuhao@bogon ~$ cd ~
xuhao@bogon ~$ cd .ssh
xuhao@bogon .ssh$ ssh-keygen -t rsa -C "你的工作邮箱"
// 两次回车直接生成工作邮箱相关密钥
xuhao@bogon .ssh$ ls
id_rsa     id_rsa.pub

xuhao@bogon .ssh$ ssh-keygen -t rsa -C "你的个人邮箱" -f ~/.ssh/github_rsa
// 两次回车直接生成个人邮箱相关密钥
xuhao@bogon .ssh$ ls
github_rsa     github_rsa.pub id_rsa         id_rsa.pub

// 创建 & 配置 config文件,管理ssh会话
xuhao@bogon .ssh$ open ./
xuhao@bogon .ssh$ vim config
// config文件主要内容:
# gitlab
Host gitlab 别名
    HostName  你的工作代码库的host域名
    User git
    IdentityFile ~/.ssh/id_rsa
# github
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/github_rsa

xuhao@bogon .ssh$ ls
config         github_rsa     github_rsa.pub id_rsa         id_rsa.pub

二、测试SSH连接

xuhao@bogon .ssh$ ssh -T git@github.com
The authenticity of host 'github.com (xxxxxxxxxxxx)' can't be established.
RSA key fingerprint is SHA256: xxxxxxxxxxxxxxxxxxxxxxxxxx
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,xxxxxxxxxxx' (RSA) to the list of known hosts.
Hi 你的github账号名! You've successfully authenticated, but GitHub does not provide shell access.
xuhao@bogon .ssh$ ssh -T git@github.com
Hi 你的github账号名! You've successfully authenticated, but GitHub does not provide shell access.
xuhao@bogon .ssh$ 
// 恭喜你!你的github的密钥已经配置 & 联通成功。

xuhao@bogon .ssh$ ssh -T git@gitlab
The authenticity of host '你的工作代码库域名,你的工作代码库ip地址' can't be established.
RSA key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '你的工作代码库域名,你的工作代码库ip地址' (RSA) to the list of known hosts.
Welcome to GitLab, 你的工作代码库账号名!
xuhao@bogon .ssh$ ssh -T git@gitlab
Welcome to GitLab, 你的工作代码库账号名!
// 恭喜你!你的gitlab工作代码库的密钥已经配置 & 联通成功。

三、本地配置

// 全局配置
$ git config --global user.name 'gitlab账号名'   
$ git config --global user.email '公司账号邮箱' 

// 本地配置
$ git config --local user.name '个人github账号名' 
$ git config --local user.email '个人github账号邮箱'

总结

至此,你的电脑上已经完成了对gitlab和github的配置联通工作。是不是,其实也没有那么麻烦呢,哈哈哈~ 亲爱的小伙伴们,如果觉得对你开发工作有帮助的话,请记得收藏点赞哦~