使用express搭建在线便利贴

大致思路:

  • 前端:整体使用瀑布流布局,拥有对便利贴的增删改查功能,对标签的拖拽功能等。使用 MVC 设计模式,实现 js 的模块化。
  • 后端:使用 express (基于nodejs)实现后端,使用 sequelize (Node的ORM框架Sequelize操作数据库)作为本次的数据库。

流程:

准备工作

因为本次使用到 express 所以在一开始就安装 express

  1. npm 初始化
npm init -y
  1. 安装 express ,并通过 express 生成器创建应用骨架,本次使用到 ejs 模板
npm i express --save
npm install express-generator
express -f -e // 生成 ejs 模板引擎,并且在非空目录下 -f
  1. 安装依赖
npm install

注:由于本次使用 webpack (自动化构建工具,实现LESS,CSS,JS编译和压缩代码)打包,使用 less (可嵌套,定义函数的 CSS)编写样式代码,使用到 sequelize (Node的ORM框架Sequelize操作数据库)作为数据库,使用到 passport (oAuth2实现第三方登录)实现第三方登录等等,需要安装的模块不一一介绍,缺少哪一项通过 npm i module --save 本地安装即可。

  1. 在 src 目录下创建 webpack.config.js (主要打包该目录下文件)
    webpack相关
// 引入所需模块
var webpack = require('webpack')
var path = require('path') // 输出文件的目标路径,进行路径拼接防止出错
var ExtractTextPlugin = require('extract-text-webpack-plugin') // 插件,使webpack更加方便 
var autoprefixer = require('autoprefixer') // 自动补全 css3 前缀

module.exports = {
    entry: path.join(__dirname, "js/app/index.js"),
    output: {
        path: path.join(__dirname, "../public"),
        filename: "js/index.js"
    },
    module: {
        rules: [{
            test: /\.less$/,
            use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: ["css-loader", "less-loader", "postcss-loader"]
                }) //把 css 抽离出来生成一个文件
        }]
    },
    resolve: {
        alias: {
            jquery: path.join(__dirname, "js/lib/jquery-2.0.3.min.js"),
            mod: path.join(__dirname, "js/mod"),
            less: path.join(__dirname, "less")
        }
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: "jquery"
        }),
        new ExtractTextPlugin("css/index.css"),
        new webpack.LoaderOptionsPlugin({
            options: {
                postcss: [
                    autoprefixer(),
                ]
            }
        })
    ]
};
  1. 基本工作准备完成,现在开始写前端代码。
    • js 模块可以分为:便签生成、便签管理、便签的瀑布流布局、消息提醒和事件中心等五大部分
    • 便签的生成
      包含初始化(便签id、用户username),设置颜色,位置,绑定事件等(包括添加,编辑,删除)
    • 瀑布流布局:
      1. 各单位等宽不等高
      2. 第n个放置在前一行中高度最小的下方
      3. 每添加一个单位就要更新这一行的高度以确定最小高度
var WaterFall = (function(){
  var $ct
  var $items
  // 渲染函数
  function render($c){
    $ct = $c
    $items = $ct.children() // 获取到所有子元素
    var nodeWidth = $items.outerWidth(true), // 获取到外轮廓的宽度加margin
      colNum = Math.floor($(window).width()/nodeWidth), // 获取多少列
      colSumHeight = [] // 总高度

    for(var i=0;i<$items.length;i++){
      if(i<colNum){
        $($items[i]).css({
          'left': i*nodeWidth,
          'top': '0'
        })
        colSumHeight.push($($items[i]).outerHeight(true))
      }else{
        var minH=Math.min.apply(null,colSumHeight)
        var indexH=colSumHeight.indexOf(minH)
        $($items[i]).css({
          'left': indexH*nodeWidth,
          'top': minH
        })
        colSumHeight[indexH]+=$($items[i]).outerHeight(true)
      }
    }
  }
  $(window).on('resize', function(){
    render($ct)
  })
  return {
    init: render
  }
})()
module.exports = WaterFall // 使用方式 WaterFall.init()
    $noteHead.on('mousedown', function(e){ 
      var evtX = e.pageX - $note.offset().left,
          evtY = e.pageY - $note.offset().top
      $note.addClass('draggable').data('evtPos', {x:evtX, y:evtY}) 
      // 设置标签为可移动,并且记录其位置
    }).on('mouseup', function(){
      $note.removeClass('draggable').removeData('evtPos')
    })

    // 标签移动记录其位置;标签随鼠标移动
    $('body').on('mousemove', function(e){
      $('.draggable').length && $('.draggable').offset({
        top: e.pageY-$('.draggable').data('evtPos').y,
        left: e.pageX-$('.draggable').data('evtPos').x
      })
    })
  • 消息提醒模块
    使用 fadeIn()fadeOut() 的淡入淡出效果。
  • 便签管理模块
    包含初始加载,添加便签等。
  • 事件中心
    作为统一调配其他模块。类似于发布订阅模式。

前端最后一步写入口文件 app/index.js

引入其他模块,并做相应处理。

  1. 使用 sequelize(Node的ORM框架Sequelize操作数据库) 创建数据库,并连接
    数据库使用 sqlite3 一款轻型的数据库
    创建 models ,note.js 写入 sequelize 代码
    具体参考 sequelize官方文档
    此时需要创建 database 文件夹作为数据库存储。
  2. 处理 ajax 请求(该router是后端定义文件)



    约定接口(约定请求方式、请求和相应数据等):

    1. 获取所有的note: GET: /api/notes req:{} res:{ status: 0, data:[{},{}]}
      {status: 1,errorMsg:'失败的原因'}
    2. 创建一个note:POST: /api/notes/add req:{note: 'hello world'} res:{ status:0}
      {status: 1,errorMsg:'失败的原因'}
    3. 修改一个note:POST:/api/notes/edit req:{note: 'new note',id:100}
    4. 删除一个note:POST:/api/notes/detele req:{id:n}
  1. 第三方登录
    阮一峰 oauth 2.0文章

OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。 ---- 百度百科

如果需要giuhub的第三方登录就需要去该方申请
登录giuhub,然后Setting > Developer setting > OAuth applications > Register a new application ,然后填入基本的 app 信息,就会得到 Client ID/Client Secret 。
在通过 passport-github 实现第三方登录,配置如下:

var GitHubStrategy = require('passport-github').Strategy;
 // 配置基本信息
passport.use(new GitHubStrategy({
    clientID: GITHUB_CLIENT_ID,
    clientSecret: GITHUB_CLIENT_SECRET,
    callbackURL: "http://127.0.0.1:3000/auth/github/callback"
  },
  function(accessToken, refreshToken, profile, cb) {
    User.findOrCreate({ githubId: profile.id }, function (err, user) {
      return cb(err, user);
    });
  }
));

router.get('/logout', function(req, res){ // 注销
  req.session.destroy();
  res.redirect('/');
})

app.get('/auth/github', // 登录
  passport.authenticate('github'));
 
app.get('/auth/github/callback',  // 登录回调函数
  passport.authenticate('github', { failureRedirect: '/login' }),
  function(req, res) {
    // Successful authentication, redirect home.
    res.redirect('/');
  });

并且在 app.js 添加 session 中间键(此时需要安装 session 模块 npm install express-session

小工具

node 端调试工具
npm install -g node-inspector // 安装调试工具
  node-inspector  // 启动调试软件(默认占用8080端口)  
  /* 注意提示调试网址,通过该网址进行调试
  还需要开启服务器    node --debug bin/www
  刷新服务器网址,再刷新调试网站即可。
*/
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,270评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,489评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,630评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,906评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,928评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,718评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,442评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,345评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,802评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,984评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,117评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,810评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,462评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,011评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,139评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,377评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,060评论 2 355

推荐阅读更多精彩内容