SuellaSun / simpleBlog

0 stars 0 forks source link

AngularJS学习之路 #3

Open SuellaSun opened 6 years ago

SuellaSun commented 6 years ago

2018/7/10

AngularJS之事件

SuellaSun commented 6 years ago

https://blog.csdn.net/qq_17371033/article/details/49248791

SuellaSun commented 6 years ago

https://www.cnblogs.com/koleyang/p/4566434.html

SuellaSun commented 6 years ago

AngularJS指令进阶 – ngModelController详解 在自定义Angular指令时,其中有一个叫做require的字段,这个字段的作用是用于指令之间的相互交流。举个简单的例子,假如我们现在需要编写两 个指令,在linking函数中有很多重合的方法,为了避免重复自己(著名的DRY原则),我们可以将这个重复的方法写在第三个指令的 controller中,然后在另外两个需要的指令中require这个拥有controller字段的指令,最后通过linking函数的第四个参数就 可以引用这些重合的方法。代码的结构大致如下: var app = angular.modeule('myapp',[]);

app.directive('common',function(){ return { ... controller: function($scope){ this.method1 = function(){ }; this.method2 = function(){ }; }, ... } });

app.directive('d1',function(){ return { ... require: '?^common', link: function(scope,elem,attrs,common){ scope.method1 = common.method1; .. }, ... } });

app.directive('d2',function(){ return { ... require: '?^common', link: function(scope,elem,attrs,common){ scope.method1 = common.method1; .. }, ... } }); 当然,上面例子只是指令中controller用法的一种。虽然一般来说,使用controller字段的机会不是很多,但是想要写好AngularJS的指令,这是必须要掌握的一点。 显然,controller的用法分为两种情形,一种是require自定义的controller,由于自定义controller中的属性方法都由自 己编写,使用起来比较简单;另一种方法则是require AngularJS内建的指令,其中大部分时间需要require的都是ngModel这个指令。很多时候,由于我们对ngModel中内建的方法和属性 不熟悉,在阅读和编写代码时会有一些困难。今天我们的目的就是详细的介绍ngModel中的内建属性和方法,相信在认真的阅读完本文之后,你一定能够熟练 的在指令中require ngModel。 在Angular应用中,ng-model指令时不可缺少的一个部分,它用来将视图绑定到数据,是双向绑定魔法中重要的一环。 ngModelController则是ng-model指令中所定义的controller。这个controller包含了一些用于数据绑定,验 证,CSS更新,以及数值格式化和解析的服务。它不用来进行DOM渲染或者监听DOM事件。与DOM相关的逻辑都应该包含在其他的指令中,然后让这些指令 来试用ngModelController中的数据绑定功能。 下面,我们将用一个例子来说明如何在自定义指令中require ngModel。在这里例子中,我们使用HTML5中的contenteditable属性来制作了一个简单的编辑器指令,同时将在指令定义中require了ngModel来进行数据绑定。 HTML部分

Change me!
Required!

指令定义部分 angular.module('customControl', []). directive('contenteditable', function() { return { restrict: 'A', // 作为元素属性 require: '?ngModel', // 获取ngModelController link: function(scope, element, attrs, ngModel) { if(!ngModel) return; // 如果没有ng-model则什么都不做 // 指定UI的更新方式 ngModel.$render = function() { element.html(ngModel.$viewValue || ''); };

// 监听change事件来开启绑定
element.on('blur keyup change', function() {
  scope.$apply(read);
});
read(); // 初始化

// 将数据写入model
function read() {
  var html = element.html();
  // 当我们清空div时浏览器会留下一个<br>标签
  // 如果制定了strip-br属性,那么<br>标签会被清空
  if( attrs.stripBr && html == '<br>' ) {
    html = '';
  }
  ngModel.$setViewValue(html);
}

} }; }); ngModelController方法 $render(); 当视图需要更新的时候会被调用。使用ng-model的指令应该自行实现这个方法。 $isEmpty(value); 该方法用于判断输入值是否为空。 例如,使用ngModelController的指令需要判断其中是否有输入值的时候会使用该方法。该方法可用来判断值是否为undefined,'',null或者NaN。 你可以根据自己的需要重载该方法。 $setValidity(validationErrorKey, isValid); 该方法用于改变验证状态,以及在控制变化的验证标准时通知表格。 这个方法应该由一个验证器来调用。例如,一个解析器或者格式化函数。 $setPristine(); 该方法用于设置控制到原始状态。 该方法可以移除'ng-dirty'类并将控制恢复到原始状态('ng-pristine'类)。 $cancelUpdate(); 该方法用于取消一次更新并重置输入元素的值以防止$viewCalue发生更新,它会由一个pending debounced事件引发或者是因为input输入框要等待一些未来的事件。 如果你有一个使用了ng-model-options指令的输入框,并为它设置了debounced事件或者是类似于blur的事件,那么你可能会碰到在某一段时间内输入框中值和ngModel的$viewValue属性没有保持同步的情况。 在这种情况下,如果你试着在debounced/future事件发生之前更新ngModel的$modelValue,你很有可能遇到困难,因为AngularJS的dirty cheching机制实际上并不会分辨一个模型究竟有没有发生变化。 $cancelUpdate()方法应该在改变一个输入框的model之前被调用。记住,这很重要因为这能够确保输入字段能够被新的model值更新,而pending操作将会被取消。下面是一个例子: HTML部分

With $cancelUpdate()


myValue: "{{ myValue }}"

Without $cancelUpdate()


myValue: "{{ myValue }}"


JS部分 angular.module('cancel-update-example', [])

.controller('CancelUpdateCtrl', function($scope) { $scope.resetWithCancel = function (e) { if (e.keyCode == 27) { $scope.myForm.myInput1.$cancelUpdate(); $scope.myValue = ''; } }; $scope.resetWithoutCancel = function (e) { if (e.keyCode == 27) { $scope.myValue = ''; } }; });
$setViewValue(value, trigger)方法 该方法用来更新视图值。这个方法应该在一个视图值发生变化时被调用,一般来说是在一个DOM事件处理函数中。例如,input和select指令就调用了这个函数。 这个方法将会更新$viewValue属性,然后在$pasers中通将这个值传递给每一个函数,其中包括了验证器。这个值从$parsers输出后,将会被用于$modelValue以及ng-model属性中的表达式。 最后,所有位于$viewChangeListeners列表中注册的监听器将会被调用。

ngModelController中的属性 $viewValue 视图中的实际值 $modelValue model中的值,它金额控制器绑定在一起 $parsers 将要执行的函数的数组,无论什么时候控制器从DOM中读取了一个值,它都将作为一个管道。其中的函数依次被调用,并将结果传递给下一个。最后出来的 值将会被传递到model中。其中将包括验证和转换值的过程。对于验证步骤,这个解析器将会使用$setValidity方法,对于不合格的值将返回 undefined。 $formatters 一个包含即将执行函数的数组,无论什么时候model的值发生了变化,它都会作为一个管道。其中的每一个函数都被依次调用,并将结果传递给下一个函数。该函数用于将模型传递给视图的值进行格式化。 $viewChangeListeners 只要视图的值发生变化,其中的函数就会被执行。其中的函数执行并不带参数,它的返回值也会被忽略。它可以被用在额外的#watches中。 $error 一个包含所有error的对象 $pristine 如果用户还没有进行过交互,值是true。 $dirty 如果用户已经进行过交互,值是true。 $valid 如果没有错误,值是true。 $invalid 如果有错误,值是true。

SuellaSun commented 6 years ago

https://blog.csdn.net/tanglei6636/article/details/52183758

SuellaSun commented 6 years ago
var http = require('http');
var url = require('url');
var path = require('path');
var static = require('./lib/stReqHandler');
var dynamic = require('./lib/dyReqHandler');

var PORT = 3000;

//添加MIME类型
var MIME_TYPE = {
    "css": "text/css",
    "gif": "image/gif",
    "html": "text/html",
    "ico": "image/x-icon",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "js": "text/javascript",
    "json": "application/json",
    "pdf": "application/pdf",
    "png": "image/png",
    "svg": "image/svg+xml",
    "swf": "application/x-shockwave-flash",
    "tiff": "image/tiff",
    "txt": "text/plain",
    "wav": "audio/x-wav",
    "wma": "audio/x-ms-wma",
    "wmv": "video/x-ms-wmv",
    "xml": "text/xml"
};

var server = http.createServer(onRequest);
//服务器监听程序
function onRequest(req, res) {

    var pathname = url.parse(req.url).pathname;

    //获取后缀名并解析为相应的文件类型
    var suffix = path.extname(pathname);
    //根据后缀名区分静态资源和动态资源请求
    if (suffix != null && suffix.trim() != "") {
        var contentType = MIME_TYPE[suffix.slice(1)] || "text/plain";
        //static.staticReqHandler(pathname, contentType,suffix, res);
        static.staticReqHandler(pathname, contentType,suffix, res);
    } else {
        dynamic.dynamicReqHandler(pathname, req, res);
    }

}//onRequest

server.listen(PORT);
console.log("Server runing at port: " + PORT + ".");
SuellaSun commented 6 years ago
fs = require('fs');

//渲染页面
function sendPage(pathname, contentType, res) {
    fs.exists(pathname, function (err) {
        if (!err) {
            send404(res);
        } else {
            fs.readFile(pathname, function (err, data) {
                if (err) {
                    send500(res);
                } else {
                    res.writeHead(200, { 'content-type': contentType });
                    res.end(data.toString());
                }
            });
        }
    });//path.exists
}

function send404(res) {
    res.writeHead(404, { 'content-type': 'text/html; charset = utf-8' });
    res.end("<h1>404</h1><p>file not found</p>");
}
function send500(res) {
    res.writeHead(500, { 'content-type': 'text/html; charset = utf-8' });
    res.end("<h1>404</h1><p>server error</p>");
}

exports.sendPage = sendPage;
exports.send404 = send404;
exports.send500 = send500;
var fs = require('fs');
var send = require('./sendPages');

//静态资源处理
function staticReqHandler(pathname, contentType, suffix, res) {
    //由于所有的html文件放在views文件夹下,页面加载css等非html文件时,
    //请求的css等文件都会加上该html页面所在的父目录也即views,所以要
    // // 将这个父目录去掉,后面的目录才是文件所在的目录
    console.log(pathname);
    // if (pathname.slice(1, 7) === 'public' || pathname === "/index.js") {
    //     pathname = '.' + pathname;
    // }
    // else {
        pathname = './public' + pathname;
    // }
    console.log(pathname);
    send.sendPage(pathname, contentType, res);
}//staticReqHandler

exports.staticReqHandler = staticReqHandler;
send = require('./sendPages');
fs = require('fs');
//动态请求处理
function dynamicReqHandler(pathname, req, res) {
    switch (pathname) {
        case "/":
            pathname = "./public/views/index.html";
            send.sendPage(pathname, 'text/html', res);
            break;
        // case "/login":
        //     login(req,res);
        case "/login":
            login(req, res);
            break;
        case "/getBlogList":
            getList(req, res);
            break;
        default:
            res.writeHead(500, { 'content-type': 'text/html; charset = utf-8' });
            res.end("<h1>500</h1><p>file not found</p>");
    }//switch
}

// function login(req,res){
//     console.log("request handler 'login' was called.");
//     pathname = './public/views/login.html';
//     send.sendPage(pathname, 'text/html', res);
// }
//用户登录验证
function login(req, res) {
    console.log("Request handler 'login' was called.");
    //处理post请求
    // 定义了一个post变量,用于暂存请求体的信息
    var postData = '';
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到postData变量中
    req.on('data', function (chunk) {
        postData += chunk;
    });
    // 在end事件触发后然后向客户端返回。
    req.on('end', function () {

        postData = JSON.parse(postData);//解析接收的浏览器请求
        console.log(postData);
        //返回给客户端的状态数据
        var reslut = {};
        if (postData.username == "2910776796@qq.com" && postData.password == "12345678") {
            reslut = {
                'code': 1,
                'msg': 'sucess'
            };
            console.log(reslut);
        } else {
            reslut = {
                'code': 0,
                'msg': 'false'
            };
            console.log(reslut);
        }
        res.writeHead(200, { 'content-Type': 'text/plain' });
        res.end(JSON.stringify(reslut));
    });
}

//读取JSON数据
function getList(req, res) {
    console.log("Request handler 'getList' was called.");
    fs.readFile('./public/json/blogItem.json', 'utf-8', function (err, blogData) {
        if (err)
            send.send404(res);

        res.writeHead(200, { 'content-type': 'application/json;charset=utf-8;' });
        res.end(blogData);
    });

    return;
}
exports.dynamicReqHandler = dynamicReqHandler;
SuellaSun commented 6 years ago
var app = angular.module('myApp', ['ngRoute']);

// 路由控制
app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider
    .when('/login',{
        controller: 'loginCrtl',   
        templateUrl: '../views/login.html'   
    })
        .when('/bloghome', {            
            controller: 'blogListCtrl',   
            templateUrl: '../views/blogHome.html'   
        })
        .otherwise({
            redirectTo: '/'
        });

}]);

// 主页控制器
app.controller("homeCtrl", ['$scope','$http', '$location', function ($scope, $http, $location) {

    $scope.login = function () {

       $location.path('/login').replace();  

   }

}]);

// 登录页控制器
app.controller("loginCrtl", ['$scope','$http','$location', function ($scope,$http,$location) {
    $scope.isLogout = true;
    $scope.isLogin = false; 

    $scope.dataSumbit = function () {
        if ($scope.myForm.$valid) {
        $http({
            method: 'post',
            url: '/login',
            data: $scope.user
        }).then(function (res) {

            if (res.data.code == 1) {
                $scope.isLogout = false; 
                $scope.isLogin = true; 
                 $location.path('/bloghome'); 

            }
            else {
                alert('用户名或密码错误!请重新输入');
                $location.path('/login').replace();

            }
        });
     }

   }

}]);

// 博客列表页控制器
app.controller('blogListCtrl', ['$scope', '$http', function ( $scope, $http) {

    $http({//与后端交互,获取数据
        method: 'GET',
        url: '/getBlogList'
    }).then(function (res) {
        if (res.status !== 200)
            alert(res.status + "状态,出错啦!");
        $scope.heads = res.data.bloghead;
        $scope.blogItems = res.data.blogitem;
    });

    //利用事件委托实现事件绑定一次
    var myUL = document.getElementById("blogList");
    var myLI = myUL.getElementsByClassName("listItem");

    $scope.blogClickHandler = function ($event) {
        var event = $event || window.event;
        var target = event.target || event.srcElement;// 兼容IE和Firefox

        target = getParentByClassName(target, "listItem");
        if (target.classList.contains("listItem")) {
            for (var i = 0; i < myLI.length; i++) {
                if (myLI[i] === target) {
                    var children = target.children;
                    alert(children[1].innerHTML);// 这里目前用的还是DOM
                }
            }
        }
    }

    $scope.changeOver = function ($event) {
        var event = $event || window.event;
        var target = event.target || event.srcElement;//兼容IE和Firefox

        target = getParentByClassName(target, "listItem");
        if (target.classList.contains("listItem")) {
            for (var i = 0; i < myLI.length; i++) {
                if (myLI[i] === target) {
                    target.style.backgroundColor = "WhiteSmoke";// 这里目前用的还是DOM
                }
            }
        }
    }
    $scope.changeOut = function ($event) {
        var event = $event || window.event;
        var target = event.target || event.srcElement;//兼容IE和Firefox

        target = getParentByClassName(target, "listItem");
        if (target.classList.contains("listItem")) {
            for (var i = 0; i < myLI.length; i++) {
                if (myLI[i] === target) {
                    target.style.backgroundColor = "";// 这里目前用的还是DOM
                }
            }
        }
    }
}]);

// 自定义验证用户名的指令
app.directive("usernameValidate", function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {

            var uNameRegexp = /^(?![0-9]+$)[a-zA-Z_][a-zA-Z_0-9]{8,20}$/;//不能以数字开头,可包含数字字母下划线,长度6-20位
            var phoneRegexp = /^1[3|5|8][0-9]\d{4,8}$/;//
            var emailRegexp = /^([a-z0-9]*[-_.]?[a-z0-9]+)+@([a-z0-9]*[-_]?[a-z0-9]+)+[\.][a-z]{2,3}([\.][a-z]{2})?$/;
            var isPhone = /^\d{11,11}$/;//11位的纯数字
            var isEmail = /[\@]/;//包含@

            ctrl.$parsers.unshift(function (viewValue) {
                if (isPhone.test(viewValue)) {//纯数字
                    if (phoneRegexp.test(viewValue))
                        ctrl.$setValidity('formatValid', true);
                    else
                        ctrl.$setValidity('formatValid', false);
                } else if (isEmail.test(viewValue)) {
                    if (emailRegexp.test(viewValue))
                        ctrl.$setValidity('formatValid', true);
                    else
                        ctrl.$setValidity('formatValid', false);
                } else {
                    if (uNameRegexp.test(viewValue))
                        ctrl.$setValidity('formatValid', true);
                    else
                        ctrl.$setValidity('formatValid', false);
                }
                return viewValue;
            });
            ctrl.$render = function () { };
        }
    }
});

// 判断祖先元素是否为指定元素(一级级向上查找,直到找到或者到body元素)
function getParentByClassName(child, parentClass) {
    var parent;
    // 如果当前元素为要找的元素,则返回当前元素
    // if (child.className === parentClass)//修改前
    if (child.classList.contains(parentClass))//修改后获取所有类名列表,查看列表中是否包含
        parent = child;
    else {// 否则,查看其父元素是否为要找的元素,一直向上查询直到找到或者到达body,也就是没找到
        while (!(child.parentNode.classList.contains(parentClass)) && child.parentNode.tagName != "body") {
            child = child.parentNode;
        }
        parent = child.parentNode;
    }
    return parent;
}
SuellaSun commented 6 years ago
<div class="wrapper1">
        <form name="myForm" class="parent" ng-submit="dataSumbit()" novalidate>
            <div class="login-header">
                <h3>用户登录</h3>
            </div>
            <input class="child" type="text" name="userName" placeholder="用户名/手机号/邮箱" ng-model="user.username" username-Validate required>
            </input>
            <span ng-show="myForm.userName.$dirty && myForm.userName.$touched">
                <span class="showError" ng-show="myForm.userName.$error.required">用户名不能为空</span>
                <span class="showError" ng-show="myForm.userName.$error.formatValid">用户名格式错误。</span>

            </span>
            <br>
            <input class="child" type="password" name="password" placeholder="密码" ng-model="user.password" required>
            </input>
            <span class="showError" style="color:red" ng-show="myForm.password.$dirty && myForm.password.$touched">
                <span class="showError" ng-show="myForm.password.$error.required">密码不能为空</span>

            </span>
            <br>
            <input id="chk" type="checkbox" name="autologin" value="no">
            <span class="chbx">下一次自动登录</span>
            <br>
            <button type="submit" class="child btnlogin" name="login">登录</button>
            <br>
        </form>

</div>
SuellaSun commented 6 years ago

HTTP 400 - 请求无效 HTTP 401.1 - 未授权:登录失败 HTTP 401.2 - 未授权:服务器配置问题导致登录失败 HTTP 401.3 - ACL 禁止访问资源 HTTP 401.4 - 未授权:授权被筛选器拒绝 HTTP 401.5 - 未授权:ISAPI 或 CGI 授权失败 HTTP 403 - 禁止访问 HTTP 403 - 对 Internet 服务管理器 的访问仅限于 Localhost HTTP 403.1 禁止访问:禁止可执行访问 HTTP 403.2 - 禁止访问:禁止读访问 HTTP 403.3 - 禁止访问:禁止写访问 HTTP 403.4 - 禁止访问:要求 SSL HTTP 403.5 - 禁止访问:要求 SSL 128 HTTP 403.6 - 禁止访问:IP 地址被拒绝 HTTP 403.7 - 禁止访问:要求客户证书 HTTP 403.8 - 禁止访问:禁止站点访问 HTTP 403.9 - 禁止访问:连接的用户过多 HTTP 403.10 - 禁止访问:配置无效 HTTP 403.11 - 禁止访问:密码更改 HTTP 403.12 - 禁止访问:映射器拒绝访问 HTTP 403.13 - 禁止访问:客户证书已被吊销 HTTP 403.15 - 禁止访问:客户访问许可过多 HTTP 403.16 - 禁止访问:客户证书不可信或者无效 HTTP 403.17 - 禁止访问:客户证书已经到期或者尚未生效 HTTP 404.1 - 无法找到 Web 站点 HTTP 404- 无法找到文件 HTTP 405 - 资源被禁止 HTTP 406 - 无法接受 HTTP 407 - 要求代理身份验证 HTTP 410 - 永远不可用 HTTP 412 - 先决条件失败 HTTP 414 - 请求 - URI 太长 HTTP 500 - 内部服务器错误 HTTP 500.100 - 内部服务器错误 - ASP 错误 HTTP 500-11 服务器关闭 HTTP 500-12 应用程序重新启动 HTTP 500-13 - 服务器太忙 HTTP 500-14 - 应用程序无效 HTTP 500-15 - 不允许请求 global.asa Error 501 - 未实现 HTTP 502 - 网关错误 用户试图通过 HTTP 或文件传输协议 (FTP) 访问一台正在运行 Internet 信息服务 (IIS) 的服务器上的内容时,IIS 返回一个表示该请求的状态的数字代码。该状态代码记录在 IIS 日志中,同时也可能在 Web 浏览器或 FTP 客户端显示。状态代码可以指明具体请求是否已成功,还可以揭示请求失败的确切原因。 日志文件的位置 在默认状态下,IIS 把它的日志文件放在 %WINDIRSystem32Logfiles 文件夹中。每个万维网 (WWW) 站点和 FTP 站点在该目录下都有一个单独的目录。在默认状态下,每天都会在这些目录下创建日志文件,并用日期给日志文件命名(例如,exYYMMDD.log)。 HTTP 1xx - 信息提示 这些状态代码表示临时的响应。客户端在收到常规响应之前,应准备接收一个或多个 1xx 响应。 • 100 - 继续。 • 101 - 切换协议。 2xx - 成功 这类状态代码表明服务器成功地接受了客户端请求。 • 200 - 确定。客户端请求已成功。 • 201 - 已创建。 • 202 - 已接受。 • 203 - 非权威性信息。 • 204 - 无内容。 • 205 - 重置内容。 • 206 - 部分内容。 3xx - 重定向 客户端浏览器必须采取更多操作来实现请求。例如,浏览器可能不得不请求服务器上的不同的页面,或通过代理服务器重复该请求。 • 302 - 对象已移动。 • 304 - 未修改。 • 307 - 临时重定向。 4xx - 客户端错误 发生错误,客户端似乎有问题。例如,客户端请求不存在的页面,客户端未提供有效的身份验证信息。 • 400 - 错误的请求。 • 401 - 访问被拒绝。IIS 定义了许多不同的 401 错误,它们指明更为具体的错误原因。这些具体的错误代码在浏览器中显示,但不在 IIS 日志中显示: • 401.1 - 登录失败。 • 401.2 - 服务器配置导致登录失败。 • 401.3 - 由于 ACL 对资源的限制而未获得授权。 • 401.4 - 筛选器授权失败。 • 401.5 - ISAPI/CGI 应用程序授权失败。 • 401.7 – 访问被 Web 服务器上的 URL 授权策略拒绝。这个错误代码为 IIS 6.0 所专用。 • 403 - 禁止访问:IIS 定义了许多不同的 403 错误,它们指明更为具体的错误原因: • 403.1 - 执行访问被禁止。 • 403.2 - 读访问被禁止。 • 403.3 - 写访问被禁止。 • 403.4 - 要求 SSL。 • 403.5 - 要求 SSL 128。 • 403.6 - IP 地址被拒绝。 • 403.7 - 要求客户端证书。 • 403.8 - 站点访问被拒绝。 • 403.9 - 用户数过多。 • 403.10 - 配置无效。 • 403.11 - 密码更改。 • 403.12 - 拒绝访问映射表。 • 403.13 - 客户端证书被吊销。 • 403.14 - 拒绝目录列表。 • 403.15 - 超出客户端访问许可。 • 403.16 - 客户端证书不受信任或无效。 • 403.17 - 客户端证书已过期或尚未生效。 • 403.18 - 在当前的应用程序池中不能执行所请求的 URL。这个错误代码为 IIS 6.0 所专用。 • 403.19 - 不能为这个应用程序池中的客户端执行 CGI。这个错误代码为 IIS 6.0 所专用。 • 403.20 - Passport 登录失败。这个错误代码为 IIS 6.0 所专用。 • 404 - 未找到。 • 404.0 -(无) – 没有找到文件或目录。 • 404.1 - 无法在所请求的端口上访问 Web 站点。 • 404.2 - Web 服务扩展锁定策略阻止本请求。 • 404.3 - MIME 映射策略阻止本请求。 • 405 - 用来访问本页面的 HTTP 谓词不被允许(方法不被允许) • 406 - 客户端浏览器不接受所请求页面的 MIME 类型。 • 407 - 要求进行代理身份验证。 • 412 - 前提条件失败。 • 413 – 请求实体太大。 • 414 - 请求 URI 太长。 • 415 – 不支持的媒体类型。 • 416 – 所请求的范围无法满足。 • 417 – 执行失败。 • 423 – 锁定的错误。 5xx - 服务器错误 服务器由于遇到错误而不能完成该请求。 • 500 - 内部服务器错误。 • 500.12 - 应用程序正忙于在 Web 服务器上重新启动。 • 500.13 - Web 服务器太忙。 • 500.15 - 不允许直接请求 Global.asa。 • 500.16 – UNC 授权凭据不正确。这个错误代码为 IIS 6.0 所专用。 • 500.18 – URL 授权存储不能打开。这个错误代码为 IIS 6.0 所专用。 • 500.100 - 内部 ASP 错误。 • 501 - 页眉值指定了未实现的配置。 • 502 - Web 服务器用作网关或代理服务器时收到了无效响应。 • 502.1 - CGI 应用程序超时。 • 502.2 - CGI 应用程序出错。application. • 503 - 服务不可用。这个错误代码为 IIS 6.0 所专用。 • 504 - 网关超时。 • 505 - HTTP 版本不受支持。 常见的 HTTP 状态代码及其原因 • 200 - 成功。 此状态代码表示 IIS 已成功处理请求。 • 304 - 未修改。客户端请求的文档已在其缓存中,文档自缓存以来尚未被修改过。客户端使用文档的缓存副本,而不从服务器下载文档。 • 401.1 - 登录失败。 登录尝试不成功,可能因为用户名或密码无效。 • 401.3 - 由于 ACL 对资源的限制而未获得授权。 这表示存在 NTFS 权限问题。即使您对试图访问的文件具备相应的权限,也可能发生此错误。例如,如果 IUSR 帐户无权访问 C:WinntSystem32Inetsrv 目录,您会看到这个错误。 有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章: 187506 INFO: IIS 4.0 的基础 NTFS 权限 • 403.1 - 执行访问被禁止。 下面是导致此错误信息的两个常见原因: • 您没有足够的执行许可。例如,如果试图访问的 ASP 页所在的目录权限设为“无”,或者,试图执行的 CGI 脚本所在的目录权限为“只允许脚本”,将出现此错误信息。若要修改执行权限,请在 Microsoft 管理控制台 (MMC) 中右击目录,然后依次单击属性和目录选项卡,确保为试图访问的内容设置适当的执行权限。 • 您没有将试图执行的文件类型的脚本映射设置为识别所使用的谓词(例如,GET 或 POST)。若要验证这一点,请在 MMC 中右击目录,依次单击属性、目录选项卡和配置,然后验证相应文件类型的脚本映射是否设置为允许所使用的谓词。 • 403.2 - 读访问被禁止。验证是否已将 IIS 设置为允许对目录进行读访问。另外,如果您正在使用默认文件,请验证该文件是否存在。有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章: 247677 错误信息:403.2 Forbidden:Read Access Forbidden(403.2 禁止访问:读访问被禁止) • 403.3 - 写访问被禁止。 验证 IIS 权限和 NTFS 权限是否已设置以便向该目录授予写访问权。有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章: 248072 错误信息:403.3 Forbidden:Write Access Forbidden(403.3 禁止访问:写访问被禁止) • 403.4 - 要求 SSL。禁用要求安全通道选项,或使用 HTTPS 代替 HTTP 来访问该页面。如果没有安装证书的 Web 站点出现此错误,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章: 224389 错误信息:HTTP 错误 403、403.4、403.5 禁止访问:要求 SSL • 403.5 - 要求 SSL 128。禁用要求 128 位加密选项,或使用支持 128 位加密的浏览器以查看该页面。如果没有安装证书的 Web 站点出现此错误,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章: 224389 错误信息:HTTP 错误 403、403.4、403.5 禁止访问:要求 SSL • 403.6 - IP 地址被拒绝。您已把您的服务器配置为拒绝访问您目前的 IP 地址。有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章: 248043 错误信息:403.6 - Forbidden:IP Address Rejected(403.6 - 不可用:IP 地址被拒绝) • 403.7 - 要求客户端证书。您已把您的服务器配置为要求客户端身份验证证书,但您未安装有效的客户端证书。有关其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章: 190004 错误 403.7 或“Connection to Server Could Not Be Established”(无法建立与服务器的连接) 186812 PRB:错误信息:403.7 Forbidden:Client Certificate Required(403.7 禁止访问:要求客户端证书) • 403.8 - 站点访问被拒绝。您已为您用来访问服务器的域设置了域名限制。有关如何解决此问题的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中相应的文章: 248032 错误信息:Forbidden:Site Access Denied 403.8(禁止访问:站点访问被拒绝 403.8) • 403.9 - 用户数过多。与该服务器连接的用户数量超过了您设置的连接限制。有关如何更改此限制的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章: 248074 错误信息:Access Forbidden:Too Many Users Are Connected 403.9(禁止访问:连接的用户太多 403.9) 注意:Microsoft Windows 2000 Professional 和 Microsoft Windows XP Professional 自动设置了在 IIS 上最多 10 个连接的限制。您无法更改此限制。 • 403.12 - 拒绝访问映射表。 您要访问的页面要求提供客户端证书,但映射到您的客户端证书的用户 ID 已被拒绝访问该文件。有关其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章: 248075 错误信息:HTTP 403.12 - Access Forbidden:Mapper Denied Access(HTTP 403.12 - 禁止访问:映射表拒绝访问) • 404 - 未找到。 发生此错误的原因是您试图访问的文件已被移走或删除。如果在安装 URLScan 工具之后,试图访问带有有限扩展名的文件,也会发生此错误。这种情况下,该请求的日志文件项中将出现“Rejected by URLScan”的字样。 • 500 - 内部服务器错误。 很多服务器端的错误都可能导致该错误信息。事件查看器日志包含更详细的错误原因。此外,您可以禁用友好 HTTP 错误信息以便收到详细的错误说明。 有关如何禁用友好 HTTP 错误信息的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章: 294807 如何在服务器端禁用 Internet Explorer 5 的“显示友好 HTTP 错误信息”功能 • 500.12 - 应用程序正在重新启动。 这表示您在 IIS 重新启动应用程序的过程中试图加载 ASP 页。刷新页面后,此信息即会消失。如果刷新页面后,此信息再次出现,可能是防病毒软件正在扫描 Global.asa 文件。有关其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章: 248013 错误信息:HTTP Error 500-12 Application Restarting(HTTP 错误 500-12 应用程序正在重新启动) • 500-100.ASP - ASP 错误。 如果试图加载的 ASP 页中含有错误代码,将出现此错误信息。若要获得更确切的错误信息,请禁用友好 HTTP 错误信息。默认情况下,只会在默认 Web 站点上启用此错误信息。有关如何在非默认的 Web 站点上看到此错误信息的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章: 261200 显示 HTTP 500 错误信息,而不显示 500-100.asp 的 ASP 错误信息 • 502 - 网关错误。 如果试图运行的 CGI 脚本不返回有效的 HTTP 标头集,将出现此错误信息。 FTP 1xx - 肯定的初步答复 这些状态代码指示一项操作已经成功开始,但客户端希望在继续操作新命令前得到另一个答复。 • 110 重新启动标记答复。 • 120 服务已就绪,在 nnn 分钟后开始。 • 125 数据连接已打开,正在开始传输。 • 150 文件状态正常,准备打开数据连接。 2xx - 肯定的完成答复 一项操作已经成功完成。客户端可以执行新命令。 • 200 命令确定。 • 202 未执行命令,站点上的命令过多。 • 211 系统状态,或系统帮助答复。 • 212 目录状态。 • 213 文件状态。 • 214 帮助消息。 • 215 NAME 系统类型,其中,NAME 是 Assigned Numbers 文档中所列的正式系统名称。 • 220 服务就绪,可以执行新用户的请求。 • 221 服务关闭控制连接。如果适当,请注销。 • 225 数据连接打开,没有进行中的传输。 • 226 关闭数据连接。请求的文件操作已成功(例如,传输文件或放弃文件)。 • 227 进入被动模式 (h1,h2,h3,h4,p1,p2)。 • 230 用户已登录,继续进行。 • 250 请求的文件操作正确,已完成。 • 257 已创建“PATHNAME”。 3xx - 肯定的中间答复 该命令已成功,但服务器需要更多来自客户端的信息以完成对请求的处理。 • 331 用户名正确,需要密码。 • 332 需要登录帐户。 • 350 请求的文件操作正在等待进一步的信息。 4xx - 瞬态否定的完成答复 该命令不成功,但错误是暂时的。如果客户端重试命令,可能会执行成功。 • 421 服务不可用,正在关闭控制连接。如果服务确定它必须关闭,将向任何命令发送这一应答。 • 425 无法打开数据连接。 • 426 Connection closed; transfer aborted. • 450 未执行请求的文件操作。文件不可用(例如,文件繁忙)。 • 451 请求的操作异常终止:正在处理本地错误。 • 452 未执行请求的操作。系统存储空间不够。 5xx - 永久性否定的完成答复 该命令不成功,错误是永久性的。如果客户端重试命令,将再次出现同样的错误。 • 500 语法错误,命令无法识别。这可能包括诸如命令行太长之类的错误。 • 501 在参数中有语法错误。 • 502 未执行命令。 • 503 错误的命令序列。 • 504 未执行该参数的命令。 • 530 未登录。 • 532 存储文件需要帐户。 • 550 未执行请求的操作。文件不可用(例如,未找到文件,没有访问权限)。 • 551 请求的操作异常终止:未知的页面类型。 • 552 请求的文件操作异常终止:超出存储分配(对于当前目录或数据集)。 • 553 未执行请求的操作。不允许的文件名。 常见的 FTP 状态代码及其原因 • 150 - FTP 使用两个端口:21 用于发送命令,20 用于发送数据。状态代码 150 表示服务器准备在端口 20 上打开新连接,发送一些数据。 • 226 - 命令在端口 20 上打开数据连接以执行操作,如传输文件。该操作成功完成,数据连接已关闭。 • 230 - 客户端发送正确的密码后,显示该状态代码。它表示用户已成功登录。 • 331 - 客户端发送用户名后,显示该状态代码。无论所提供的用户名是否为系统中的有效帐户,都将显示该状态代码。 • 426 - 命令打开数据连接以执行操作,但该操作已被取消,数据连接已关闭。 • 530 - 该状态代码表示用户无法登录,因为用户名和密码组合无效。如果使用某个用户帐户登录,可能键入错误的用户名或密码,也可能选择只允许匿名访问。如果使用匿名帐户登录,IIS 的配置可能拒绝匿名访问。 • 550 - 命令未被执行,因为指定的文件不可用。例如,要 GET 的文件并不存在,或试图将文件 PUT 到您没有写入权限的目录。

SuellaSun commented 6 years ago

angualrJS 的依赖注入 服务等:https://www.cnblogs.com/zzcit/p/7808531.html 模块:https://blog.csdn.net/woxueliuyun/article/details/50962645

SuellaSun commented 6 years ago

https://blog.csdn.net/dm_vincent/article/details/52137733

SuellaSun commented 6 years ago

image

SuellaSun commented 6 years ago

dy.js

var send = require('./send-page');
var fs = require('fs');
var write = require('./write-data');
var path = require('path');

//动态请求处理
function dynamicReqHandler(pathname, req, res) {
    switch (pathname) {
        case "/":
            pathname = "./public/views/index.html";
            send.sendPage(pathname, 'text/html', res);
            break;
        case "/login":
            login(req, res);
            break;
        case "/signup":
            signup(req, res);
            break;
        case "/uniqueValidate":
            uniqueValidate(req, res);
            break;
        case "/postBlogs":
            postBlog(req, res);
            break;
        case "/getBlogList":
            getList(res);
            break;
        case "/getPersonalhome":
            getPersonalHomePage(req, res);
            break;
        case "/getArticleDetails":
            getArticleDetails(req, res);
            break;

        default:
            send.send500(res);
    }//switch
}

// 用户登录验证
function login(req, res) {
    console.log("Request handler 'login' was called.");

    var postData = '';
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到postData变量中
    req.on('data', function (chunk) {
        postData += chunk;
    });
    // 在end事件触发后然后向客户端返回。
    req.on('end', function () {

        postData = JSON.parse(postData);// 解析接收的浏览器请求
        console.log(postData);

        // 返回给客户端的状态数据
        var reslut = { 'status': '' };
        fs.readFile('./public/json/user-infomation.json', function (err, userInfo) {
            if (err)
                send.send500(res);
            else {
                userInfo = JSON.parse(userInfo);
                var flag = userExists(userInfo, postData);
                if (flag >= 0) {
                    reslut.status = 200;
                }
                else {
                    reslut.status = 401.1;
                }
                res.writeHead(200, { 'content-Type': 'text/plain' });
                res.end(JSON.stringify(reslut));
            }
        });
    });
}

// 注册
function signup(req, res) {
    console.log("Request handler 'signup' was called.");
    pathname = './public/json/user-infomation.json';
    write.writeData(pathname, req, res);
}

// 验证用户名是否唯一
function uniqueValidate(req, res) {
    console.log("Request handler 'uniqueValidate' was called.");
    var postData = '';
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到postData变量中
    req.on('data', function (chunk) {
        postData += chunk;
    });
    // 在end事件触发后然后向客户端返回。
    req.on('end', function () {

        postData = JSON.parse(postData);// 解析接收的浏览器请求
        console.log(postData);

        // 返回给客户端的状态数据
        var reslut = { 'isUnique': '' };
        fs.readFile('./public/json/user-infomation.json', function (err, userInfo) {
            if (err)
                send.send500(res);
            else {
                userInfo = JSON.parse(userInfo);
                var flag = false;
                for (var i = 0; i < userInfo.length; i++) {
                    if (userInfo[i].username === postData.username) {
                        flag = true;
                    }
                }
                if (flag) { // 存在,不唯一
                    reslut.isUnique = false;
                }
                else {  // 不存在,唯一
                    reslut.isUnique = true;
                }
                res.writeHead(200, { 'content-Type': 'text/plain' });
                res.end(JSON.stringify(reslut));
            }
        });
    });
}

// 提交博客数据
function postBlog(req, res) {
    console.log("Request handler 'postBlogs' was called.");

    var postData = '';

    req.on('data', function (chunk) {
        postData += chunk;
    });

    req.on('end', function () {
        postData = JSON.parse(postData);

        fs.readFile('./public/json/user-infomation.json', function (err, userInfo) {
            if (err)
                send.send500(res);
            else {
                var pathname = getPath(userInfo, postData.user);
                postData = {
                    "title": postData.blog.title,
                    "content": postData.blog.content,
                    "date": postData.blog.date,
                    "username": postData.user.username
                }
                postData = JSON.stringify(postData);
                write.insertData1(pathname, postData, res);
            }
        });
    });

}
// 首页读取JSON数据,显示博客列表(修改,显示所有用户的最新10条)
function getList(res) {
    console.log("Request handler 'getList' was called.");

    dirname = path.join(__dirname, '/../public/json/blog-information/');
    let fileNames = findSync(dirname);
    var datas = [];
    // 获取/blog-information/下的所有json文件
    for (let i = 0; i < fileNames.length; i++) {
        datas[i] = fs.readFileSync(fileNames[i], 'utf-8');
    }
    // 获取非空文件列表
    var copyDatas = getNotNullFile(datas);

    // 读取所有非空文件中的数据(注意格式)
    var blogData = "";
    if (copyDatas.length != 0) {
        var blogData = copyDatas[0].slice(0, copyDatas[0].length - 1);
        for (var i = 1; i < copyDatas.length; i++) {
            blogData += ',' + copyDatas[i].slice(1, copyDatas[i].length - 1);
        }
        blogData += ']';

        // 以date降序重新排列blogData
        blogData = JSON.parse(blogData);
        blogData = blogData.sort(keySort("date"));

        res.writeHead(200, { 'content-Type': 'application/json' });
        res.end(JSON.stringify(blogData));
    }
    else {
        // 空json数组
        blogData = "[]";

        res.writeHead(200, { 'content-Type': 'application/json' });
        res.end(blogData);
    }
}

// 读取个人主页数据
function getPersonalHomePage(req, res) {
    console.log("Request handler 'getPersonalHomePage' was called.");

    var postData = '';
    req.on('data', function (chunk) {
        postData += chunk;
    });
    // 在end事件触发后然后向客户端返回。
    req.on('end', function () {
        postData = JSON.parse(postData);// 解析接收的浏览器请求

        // 返回给客户端的状态数据
        var reslut = { 'status': '' };
        fs.readFile('./public/json/user-infomation.json', function (err, userInfo) {
            if (err)
                send.send500(res);
            else {
                var pathname = getPath(userInfo, postData);
                send.sendPage(pathname, "application/json", res);
            }
        });
    });
}

// 获取博客详情
function getArticleDetails(req, res) {
    console.log("Request handler 'getArticleDetails' was called.");

    var postData = '';
    req.on('data', function (chunk) {
        postData += chunk;
    });
    // 在end事件触发后然后向客户端返回。
    req.on('end', function () {
        postData = JSON.parse(postData);// 解析接收的浏览器请求'
        pathname = './public/json/blog-information/' + postData.username + '.json';
        data = JSON.parse(fs.readFileSync(pathname, 'utf-8'));

        // 获取对应id的博客
        var resData = data[data.length-postData.id];  

        res.writeHead(200, { 'content-type': "application/json" });
        res.end(JSON.stringify(resData));
    });
}

// 获取非空文件列表
function getNotNullFile(arr) {
    var copyArr = [];
    for (let i = 0, j = 0; i < arr.length; i++) {
        if (arr[i] !== "") {
            copyArr[j++] = arr[i];
        }
    }
    return copyArr;
}

// 根据JSON对象的属性值降序排序
function keySort(property){
    return function(obj1,obj2){
        var value1 = obj1[property];
        var value2 = obj2[property];
        // 降序 return 1,降序 return-1
        return value2 - value1;
    }
}

// 查看用户是否存在
function userExists(userInfo, postData) {
    var flag = -1;

    for (var i = 0; i < userInfo.length; i++) {
        if (userInfo[i].username === postData.username && userInfo[i].password === postData.password) {
            flag = i;
        }
    }
    return flag;
}

// 获取对应用户的存储路径
function getPath(userInfo, postData) {
    userInfo = JSON.parse(userInfo);

    var flag = userExists(userInfo, postData);
    if (flag >= 0) {
        console.log(userInfo);
        pathname = './public/json/blog-information/' + userInfo[flag].username + '.json';
    }
    return pathname;
}

// 获取指定目录下的文件名
function findSync(startPath) {
    let result = [];
    function finder(path) {
        let files = fs.readdirSync(path);
        files.forEach((val, index) => {
            let fPath = path + val;
            let stats = fs.statSync(fPath);
            if (stats.isDirectory()) finder(fPath);
            if (stats.isFile()) result.push(fPath);
        });

    }
    finder(startPath);
    return result;
}

exports.dynamicReqHandler = dynamicReqHandler;
SuellaSun commented 6 years ago

mine

// 获取资源类型
var MIME_TYPE = {
    "css": "text/css",
    "gif": "image/gif",
    "html": "text/html",
    "ico": "image/x-icon",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "js": "text/javascript",
    "json": "application/json",
    "pdf": "application/pdf",
    "png": "image/png",
    "svg": "image/svg+xml",
    "swf": "application/x-shockwave-flash",
    "tiff": "image/tiff",
    "txt": "text/plain",
    "wav": "audio/x-wav",
    "wma": "audio/x-ms-wma",
    "wmv": "video/x-ms-wmv",
    "xml": "text/xml"
};

function getContentType(suffix) {
    var contentType = MIME_TYPE[suffix.slice(1)] || "text/plain";
    return contentType;  
}

exports.getContentType = getContentType;

send.js

fs = require('fs');

//渲染页面
function sendPage(pathname, contentType, res) {
    fs.exists(pathname, function (err) {
        if (!err) {
            send404(res);
        } else {
            fs.readFile(pathname, function (err, data) {
                if (err) {
                    send500(res);
                } else {
                    res.writeHead(200, { 'content-type': contentType });
                    res.end(data.toString());
                }
            });
        }
    });//path.exists
}

function send404(res) {
    res.writeHead(404, { 'content-type': 'text/html; charset = utf-8' });
    res.end("<h1>404</h1><p>file not found</p>");
}
function send500(res) {
    res.writeHead(500, { 'content-type': 'text/html; charset = utf-8' });
    res.end("<h1>500</h1><p>server error</p>");
}

exports.sendPage = sendPage;
exports.send404 = send404;
exports.send500 = send500;

static

var fs = require('fs');
var send = require('./send-page');

//静态资源处理
function staticReqHandler(pathname, contentType, res) {
    console.log("receive:" + pathname);

    pathname = './public' + pathname;

    console.log("realpath:" + pathname);

    send.sendPage(pathname, contentType, res);
}//staticReqHandler

exports.staticReqHandler = staticReqHandler;

write

var fs = require('fs');
var path = require('path');
var send = require('./send-page');

function writeData(pathname, req, res) {
    var postData = '';

    req.on('data', function (chunk) {
        postData += chunk;
    });

    req.on('end', function () {

        insertData(pathname, postData, res)
    });
}

function insertData(pathname, postData, res) {

    var reslut = { "status": "" };

    var username = JSON.parse(postData).username;

    // 查看源文件中是否有内容
    fs.readFile(pathname, function (err, data) {
        if (err)
            send.send500(res);
        else {
            if (data == "") { // 如果文件为空,则写入格式如下
                postData = '[' + postData + ']';
            }
            else { // 如果文件不为空,则在将待写入的数据加在最后一个元素后面
                var buf = new Buffer(data);
                postData = buf.slice(0, buf.length - 1) + ',' + postData + ']';
            }
            fs.writeFile(pathname, postData, 'utf8', function (err) {
                if (err) {
                    console.log('保存失败');
                    reslut.status = 403.3;
                }
                else {
                    // 保存完成后的回调函数
                    console.log("保存完成");
                    reslut.status = 200;
                    //fs.mkdir('../public/json/blog-information/');
                    // var filename = path.join(__dirname, '/../public/json/blog-information/'+username+'.json');
                    // fs.mkdir(filename,function (err) {});
                }
                res.writeHead(200, { 'content-Type': 'text/plain' });
                res.end(JSON.stringify(reslut));

            });
        }
    });
}

function insertData1(pathname, postData, res) {

    var reslut = { "status": "" };

    // 查看源文件中是否有内容
    fs.readFile(pathname, function (err, data) {
        if (err)
            send.send500(res);
        else {

            if (data == "") { // 如果文件为空,则写入格式如下

                postData = JSON.parse(postData);
                postData = {
                    "id":1,
                    "title":postData.title,
                    "content":postData.content,
                    "date":postData.date,
                    "username":postData.username
                }
                postData = '[' + JSON.stringify(postData) + ']';
            }
            else { // 如果格式不为空,则在将待写入的数据加在最后一个元素后面
                data = JSON.parse(data);
                postData = JSON.parse(postData);
                postData = {
                    "id":data.length+1,
                    "title":postData.title,
                    "content":postData.content,
                    "date":postData.date,
                    "username":postData.username
                }
                data = JSON.stringify(data);
                postData = '['+JSON.stringify(postData)+ ',' +data.slice(1, data.length);

            } 
            fs.writeFile(pathname, postData, 'utf8', function (err) {
                if (err) {
                    console.log('保存失败');
                    reslut.status = 403.3;
                }
                else {
                    // 保存完成后的回调函数
                    console.log("保存完成");
                    reslut.status = 200;
                }
                res.writeHead(200, { 'content-Type': 'text/plain' });
                res.end(JSON.stringify(reslut));

            });
        }
    });
}

exports.writeData = writeData;
exports.insertData = insertData;
exports.insertData1 = insertData1;
SuellaSun commented 6 years ago

index.js

var app = angular.module('myApp', ['ngRoute']);

// 路由控制
app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider
        .when('/', {
            controller: 'blogListCtrl',
            templateUrl: '../views/blog-list.html'
        })
        .when('/login', {
            controller: 'loginCrtl',
            templateUrl: '../views/login.html'
        })
        .when('/signup', {
            controller: 'signupCrtl',
            templateUrl: '../views/signup.html'
        })
        .when('/bloglist', {
            controller: 'blogListCtrl',
            templateUrl: '../views/blog-list.html'
        })
        .when('/personalhome', {
            controller: 'personalCtrl',
            templateUrl: '../views/personal-homepage.html'
        })
        .when('/getArticleDetails/:articleInfo', {
            controller: 'articleDetailCtrl',
            templateUrl: '../views/blog-item.html'
        })
        .when('/writeblog', {
            controller: 'writeBlogCtrl',
            templateUrl: '../views/write-blog.html'
        })
        .otherwise({
            redirectTo: '/'
        });

}]);

// 主页控制器
app.controller("homeCtrl", ['$scope', '$rootScope', '$location', function ($scope, $rootScope, $location) {

    // 一些标记,记录状态
    $rootScope.isLogout = true;
    $rootScope.isLogin = false;
    $rootScope.isMyblog = false;

    // 点击登陆按钮登陆
    $scope.login = function () {
        $location.path('/login').replace();
    }

    // 注册按钮 
    $scope.signup = function () {
        $location.path('/signup').replace();
    }

    // 退出按钮
    $scope.logout = function () {
        alert('确定退出');
        $rootScope.isLogout = true;
        $rootScope.isLogin = false;
        $location.path('/').replace();

    }
}]);

// 登录页控制器
app.controller("loginCrtl", ['$scope', '$rootScope', '$http', '$location', function ($scope, $rootScope, $http, $location) {
    $scope.dataSumbit = function () {
        if ($scope.myForm.$valid) { // 表单验证成功
            $http({
                method: 'post',
                url: '/login',
                data: $scope.user
            }).success(function (data, status, header, cfg) {
                if (data.status == 200) { // 验证成功

                    $rootScope.isLogout = false;
                    $rootScope.isLogin = true;
                    $rootScope.user = $scope.user;

                    $location.path('/').replace();
                }
                else if (data.status == 401.1) { // 验证失败

                    alert('用户名或密码错误!请重新输入');
                    $location.path('/login').replace();
                }
            }).error(function (data, status, header, cfg) {
                alert(status);
            });
        }
    }
}]);

// 注册页控制器(待实现。。。)
app.controller("signupCrtl", ['$scope', '$http', '$location', function ($scope, $http, $location) {
    $scope.signUserInfo = {
        "username": "",
        "password": "",
        "confirmPassword": ""
    }
    $scope.dataSumbit = function () {
        if ($scope.myForm.$valid) { // 表单验证成功
            $http({
                method: 'post',
                url: '/signup',
                data: { "username": $scope.signUserInfo.username, "password": $scope.signUserInfo.password }
            }).success(function (data, status, header, cfg) {
                if (data.status == 200) { // 注册成功
                    alert('注册成功');
                    $location.path('/login').replace();
                }
                else if (data.status == 403.3) { // 注册失败

                    alert('注册失败');
                    $location.path('/signup').replace();
                }
            }).error(function (data, status, header, cfg) {
                alert(status);
            });
        }
    }
}]);

// 首页控制器
app.controller('blogListCtrl', ['$scope', '$rootScope', '$http', '$location', '$filter', function ($scope, $rootScope, $http, $location, $filter) {
    $rootScope.isMyblog = false;
    $http({// 与后端交互,获取数据
        method: 'GET',
        url: '/getBlogList'
    }).success(function (data, status, header, cfg) {
        $scope.blogItems = data;
        if ($scope.blogItems.length === 0)
            $scope.isNull = true;
        else {
            $scope.isNull = false;
            for (var i = 0; i < $scope.blogItems.length; i++) {
                // 简单处理:显示博客部分内容 ,日期进行格式化
                $scope.blogItems[i].content = $scope.blogItems[i].content.slice(0, 10) + "...";
                $scope.blogItems[i].date = $filter('date')($scope.blogItems[i].date, "yyyy-MM-dd hh:mm:ss");
            }
        }
    }).error(function (data, status, header, cfg) {
        alert(status);
    });

    //与个人主页页面逻辑相同
    $scope.blogClickHandler = function (index) {
        if ($rootScope.isLogin && !$rootScope.isLogout) {
            $scope.user = $rootScope.user;
            $rootScope.isMyblog = true;

            var articleInfo = $scope.blogItems[index].id + '|' + $scope.blogItems[index].username;
            $location.path('/getArticleDetails/' + articleInfo);
        }
        else {
            alert('您还未登录,请先登录');
            $location.path('/login').replace();
        }
    }

    $scope.changeOver = function (index) {
        $scope.over = index;
    }
}]);

// 个人主页控制器
app.controller('personalCtrl', ['$scope', '$rootScope', '$http', '$location', '$filter', function ($scope, $rootScope, $http, $location, $filter) {
    if ($rootScope.isLogin && !$rootScope.isLogout) {
        $scope.user = $rootScope.user;
        $rootScope.isMyblog = true;

        $http({// 与后端交互,获取数据
            method: 'post',
            url: '/getPersonalhome',
            data: $scope.user
        }).success(function (data, status, header, cfg) {
            $scope.blogItems = data;
            if ($scope.blogItems.length == 0)
                $scope.isNull = true;
            else {
                $scope.isNull = false;
                for (var i = 0; i < $scope.blogItems.length; i++) {
                    // 简单处理:显示博客部分内容 ,日期进行格式化
                    $scope.blogItems[i].content = $scope.blogItems[i].content.slice(0, 10) + "...";
                    $scope.blogItems[i].date = $filter('date')($scope.blogItems[i].date, "yyyy-MM-dd hh:mm:ss");
                }
            }

        }).error(function (data, status, header, cfg) {
            alert(status);
        });

        $scope.blogClickHandler = function (index) {
            var articleInfo = $scope.blogItems[index].id + '|' + $scope.blogItems[index].username;
            $location.path('/getArticleDetails/' + articleInfo);
        }

        $scope.changeOver = function (index) {
            $scope.over = index;
        }

        $scope.btnWtieBlogs = function () {
            $location.path('/writeblog').replace();
        }
    } else {
        alert('您还未登录,请先登录');
        $location.path('/login').replace();
    }
}]);

// 博客详情页
app.controller('articleDetailCtrl', ['$scope', '$routeParams', '$http', '$filter', function ($scope, $routeParams, $http, $filter) {
    $scope.articleInfo = $routeParams.articleInfo;
    var info = $scope.articleInfo.split('|');

    $scope.postData = {
        "id": info[0],
        "username": info[1]
    }

    $http({// 与后端交互,获取数据
        method: 'post',
        url: '/getArticleDetails',
        data: $scope.postData
    }).success(function (data, status, header, cfg) {
        $scope.article = data;
        $scope.article.date = $filter('date')($scope.article.date, "yyyy-MM-dd hh:mm:ss");
    }).error(function (data, status, header, cfg) {
        alert(status);
    });

}]);

// 写博客页面
app.controller('writeBlogCtrl', ['$scope', '$rootScope', '$http', '$location', '$interval', function ($scope, $rootScope, $http, $location, $interval) {
    if ($rootScope.isLogin && !$rootScope.isLogout) {

        $rootScope.isMyblog = true;
        $scope.user = $rootScope.user;

        // 需要初始化,不然在第一次提交时,若博客标题或者内容为空,会出现title未定义的错误
        $scope.blog = {
            "title": "",
            "content": "",
            "date": ""
        }

        $scope.blog.date = Date.parse(new Date());
        $interval(function () {
            $scope.blog.date = Date.parse(new Date());
        }, 1000);

        $scope.blogPublish = function () {
            if ($scope.blog.title !== "" && $scope.blog.content !== "") {
                $http({
                    method: 'post',
                    url: '/postBlogs',
                    data: { user: $scope.user, blog: $scope.blog }
                }).success(function (data, status, header, cfg) {
                    if (data.status === 200) {
                        alert('提交成功');
                        $location.path('/writeblog').replace();
                    }
                    else if (data.status === 403.3) {
                        alert('提交失败');
                        $location.path('/writeblog').replace();
                    }
                }).error(function (data, status, header, cfg) {
                    alert(status);
                });
            }
            else {
                alert("博客标题或者内容不能为空");
            }
        }
        $scope.blogListReview = function () {
            $location.path('/personalhome').replace();
        }
    }
    else {
        alert('您还未登录,请先登录');
        $location.path('/login').replace();
    }
}]);

// 自定义验证用户名的指令
app.directive("usernameValidate", function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {

            var uNameRegexp = /^(?![0-9]+$)[a-zA-Z_][a-zA-Z_0-9]{8,20}$/; // 不能以数字开头,可包含数字字母下划线,长度6-20位
            var phoneRegexp = /^1[3|5|8][0-9]\d{4,8}$/; // 11位手机号
            var emailRegexp = /^([a-z0-9]*[-_.]?[a-z0-9]+)+@([a-z0-9]*[-_]?[a-z0-9]+)+[\.][a-z]{2,3}([\.][a-z]{2})?$/;
            var isPhone = /^\d{11,11}$/; // 11位的纯数字
            var isEmail = /[\@]/; // 包含@

            // 正则验证
            ctrl.$parsers.unshift(function (viewValue) {
                if (isPhone.test(viewValue)) {//纯数字
                    if (phoneRegexp.test(viewValue))
                        ctrl.$setValidity('formatValid', true);
                    else
                        ctrl.$setValidity('formatValid', false);
                } else if (isEmail.test(viewValue)) {
                    if (emailRegexp.test(viewValue))
                        ctrl.$setValidity('formatValid', true);
                    else
                        ctrl.$setValidity('formatValid', false);
                } else {
                    if (uNameRegexp.test(viewValue))
                        ctrl.$setValidity('formatValid', true);
                    else
                        ctrl.$setValidity('formatValid', false);
                }
                return viewValue;
            });
            ctrl.$render = function () { };
        }
    }
});
// 自定义用户名唯一性验证指令
app.directive("usernameUnique", function ($http) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            scope.$watch(attrs.ngModel, function (viewValue) {
                $http({
                    method: 'post',
                    url: '/uniqueValidate',
                    data: { "username": viewValue }
                }).success(function (data, status, header, cfg) {
                    ctrl.$setValidity('unique', data.isUnique);
                }).error(function (data, status, header, cfg) {
                    ctrl.$setValidity('unique', false);
                });

            });
        }
    }
});

// 自定义密码一致性验证指令
app.directive("passwordRepeat", function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            var otherInput = elem.inheritedData("$formController")[attrs.passwordRepeat];
            ctrl.$parsers.push(function (value) {
                if (value === otherInput.$viewValue) {
                    ctrl.$setValidity("repeat", true);
                    return value;
                }
                ctrl.$setValidity("repeat", false);
            });
            otherInput.$parsers.push(function (value) {
                ctrl.$setValidity("repeat", value === ctrl.$viewValue);
                return value;

            });
        }
    }
});

userinfo.json

[{"username":"2910776796@qq.com","password":"12345678"},{"username":"suella123","password":"12345678"},{"username":"zhangsan123","password":"12345678"}]

blog-item.css

.article-title {
    font-size: 22px;
    font-weight: 700;
    margin: 8px 0;
    display: inline-block;
    vertical-align: bottom;
    width: 75%;
    line-height: 130%;
}
.info{
    font-size: 12px;
    color: #838383;
}
.info:before {
    content: "•";
}
.article-content{
    margin: 0 10px;
    line-height: 2em;
    font-family: "Helvetica Neue","Luxi Sans","DejaVu Sans",Tahoma,"Hiragino Sans GB",STHeiti,sans-serif!important;
    font-size: 14px;
    word-break: break-word;
    overflow: auto;
}
hr{        
    background: rgb(236, 235, 235);        
    border: none;        
    height: 1px;    
}

index.css

html{
    height:100%;
    font-size: 62.5%;
    -webkit-tap-highlight-color: rgba(0,0,0,0);
}
body .toolbar .container {
    width: 100%;
}
body,ul,p,span,div,a,input,button{
    margin:0;
    padding:0;
    box-sizing:border-box;
    -moz-box-sizing:border-box;
    -webkit-box-sizing:border-box
}
li{
    padding: 18px,24px;
    list-style: none;
}
body{
    min-width:1116px;
    line-height:24px;
    font-size:16px;
    background:white;
}

.toolbar {
    font-family: 'PingFang SC','Microsoft YaHei',SimHei,Arial,SimSun;
    font-size: 1em;
    color: #333;
    line-height: 1.5em;
    background: #fff;
    box-shadow: 0 2px 4px 0 rgba(0,0,0,.05);
    min-width: 1200px;
    width: 100%;
    height: 50px;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
}
.nav-pagebar{
    float:left;
    width: 40%;
    position: relative;
    margin-top: 13px;

}
.pagebar{
    margin-left: 10px;
    margin-right: 10px;
    list-style:none;
    display:inline;
}
.user-infomation{
    position: relative;
    float: left;
    margin-left: 10px;
    margin-top: 10px;
    width: 40%;

}
.infomation{
    margin:-1px;
}
.logarea{
    float: right;
    width: 10%;
}
.logbutton,.loginfo{
    position: relative;
    float: right;
    text-align: right;
    font-size: 0.75em;
}
.btnlogin,.btnsignup,.btnlogout{
    border:0;
    background-color:#fff; 

}
.container{
    background-color: #f5f6f7;
    width: 100%;
    height: 1000px;

}
.nav-menu {
    float: left;
    width: 10%;
    position: relative;
    padding: 10px;
    margin: 10px;
    /* background-color: #fff; */
    text-align: center;
    line-height: 32px;
    /* -webkit-box-shadow: 0 1px 2px 0 rgba(0,0,0,0.04);
    box-shadow: 0 1px 2px 0 rgba(0,0,0,0.04);     */
}

.main-content{
    float: left;
    width: 69%;
    position: relative;
    margin:10px;
    background: #fff;
    -webkit-box-shadow: 0 1px 2px 0 rgba(0,0,0,0.04);
    box-shadow: 0 1px 2px 0 rgba(0,0,0,0.04); 
    height: 100%;

}
.right-box {
    position: relative;
    float: right;
    width: 16%;
    padding: 10px;
    margin-top: 10px;
    margin-right: 10px;
    margin-bottom: 10px;
    /* background: #fff; */
    /* -webkit-box-shadow: 0 1px 2px 0 rgba(0,0,0,0.04);
    box-shadow: 0 1px 2px 0 rgba(0,0,0,0.04); */

}

.container::after{
    content: '.';
    height: 0;
    visibility: hidden;
    display: block;
    clear: both;
} 

a{
    outline:none;
    text-decoration:none;  
}
a:link,a:visited{
    color:#0f0f0f;
}
a:hover,a:active,a:focus{
    color:red;
}
.wrapper1,.wrapper11,.form-wrapper,.parent,.child{
    margin: 0px;
    padding: 0px; 
}
.wrapper1{  
    float: left;
    position: relative;  
    left: 30%;
    top: 20%;
    width:40%;
    height:400px;
}
.wrapper11{
    position: relative;
    width: 100%;
    height: 100%;
    background-color:rgba(238, 236, 222, 0.897); 
    border: 1px solid rgb(239, 241, 241);  
}
.form-wrapper{
    position: relative; 
    width:80%;
    height: 80%;
    top:50%;
    left:50%;
}
.parent{ 
    position: relative; 
    width:100%;
    height: 100%;
    top:-50%;
    left:-50%;  
    background-color:white;   
}
.child{
    position: relative;
    width:90%; 
    height: 55px;
    margin-bottom: 5px;
}
.login-header{
    text-align: center;
}

.p-login-header{
    position: relative;
    top:25%;
    font-size: 1.4em;
}

.showError{
    margin-top: 0;
    margin-bottom: 0;
    padding: 0;
    font-size: 11px;
    color: red;
    line-height: 0;
}
.chbx{
    height: 13px;
    font-size: 8px;
    color: darkgray;
}
.child,.btn-login,.showError {
    margin-left:15px;
    margin-right:15px;
}
.chk{
    margin-left:15px;
}
.btn-login {
    box-sizing: content-box;
    border: 2px solid #3762bc;
    padding: 0;
    background-color: #4a77d4;
    color: white;
}

person

.p-list-item{
    margin-bottom:-1px;
    /* height: 120px;  */
    border-bottom: 1px dotted lightgrey;
    border-top: 1px dotted lightgrey;

}
.list-head,.list-body,.list-foot{
    margin-top:8px;
    margin-bottom:8px; 
    margin-left: 10px;
    margin-right:0px;
}
.name{
    position: relative;
    float: left;
}
.p-list-username,.p-list-publish-time{
    font-size: 0.7em;
}
.p-list-publish-time{
    text-align: end;
}
.null-show{
    position: relative;
    width: 100%;
    height: 1000px;
    text-align: center;
}
.null-show-info{
    margin:0;
    margin-top:50px;
    margin-bottom:50px;
    position: relative;
    width:100%;
    text-align: center;
    font-size: 16px;
}
.btn-write-blogs{
    position: relative;
    width: 40%;
    height: 5%;
    display: inline-block;
    font-weight: 400;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    border: 1px solid transparent;
    padding: .375rem .75rem;
    font-size: 1em;
    line-height: 1.5;
    border-radius: .25rem;
    transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
    color: #6c757d;
    background-color: transparent;
    background-image: none;
    border-color: #6c757d;
    margin-left: 0;
}

signup

.wrapper2,.wrapper22,.form-wrapper2,.parent2,.child2{
    margin: 0px;
    padding: 0px; 
}
.wrapper2{  
    float: left;
    position: relative;  
    left: 20%;
    top: 15%;
    width:60%;
    height:500px;
}
.wrapper22{
    position: relative;
    width: 100%;
    height: 100%;
    background-color:rgba(238, 236, 222, 0.897); 
    border: 1px solid rgb(239, 241, 241);  
}
.form-wrapper2{
    position: relative; 
    width:80%;
    height: 80%;
    top:50%;
    left:50%;
}
.parent2{ 
    position: relative; 
    width:100%;
    height: 100%;
    top:-50%;
    left:-50%;  
    background-color:white;   
}
.child2{
    position: relative;
    width:90%; 
    height: 55px;
    margin-bottom: 5px;
}
.login-header2{
    text-align: center;
}

.p-login-header2{
    position: relative;
    top:25%;
    font-size: 1.4em;
}
.showError2{
    margin-top: 0;
    margin-bottom: 0;
    padding: 0;
    font-size: 11px;
    color: red;
    line-height: 0;
}
.child2,.btn-login2,.showError2 {
    margin-left:15px;
    margin-right:15px;
}
.btn-signup2{
    margin-top: 5px;
    box-sizing: content-box;
    border: 2px solid #3762bc;
    padding: 0;
    background-color: #4a77d4;
    color: white;
}

writeblog

.write-blog-wrapper{
    position: relative;
    width: 100%;
}
.blog-box-title,.blog-box-content,.blog-box-button{
    position: relative;
    width: 95%;
    margin-left:20px; 
    margin-right:20px; 
    margin-bottom:20px; 

}
.blog-box-title{
    margin-top: 20px;
    height: 40px;
    border: 1px solid transparent;
}
.blog-box-content{
    height: 400px;
    border: 1px solid transparent;
}
.txt-blog-title,.txt-blog-content{
    position: relative;
    width: 100%;
    height: 100%;
}
.blog-box-button{
    text-align: center;
    height: 50px;
}
.btnblog{
    position: relative;
    width: 15%;
    height: 100%;
    display: inline-block;
    font-weight: 400;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    border: 1px solid transparent;
    padding: .375rem .75rem;
    font-size: 1em;
    line-height: 1.5;
    border-radius: .25rem;
    transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
    color: #6c757d;
    background-color: transparent;
    background-image: none;
    border-color: #6c757d;
    margin-left: 10px;
    margin-right: 10px;
}

blog-item

<div class="header">
    <div class="title">
        <span class ="article-title">{{article.title}}</h3>
    </div>
    <div class = "auth-info">
        <span class="info">发布时间:{{article.date}}</span>
        <span class="info">作者:{{article.username}}</spanclass>
    </div>
</div>
<hr>
<div class="content">
    <div>
        <p class = "article-content">{{article.content}}</p>
    </div>
</div>

blog-list

<div class="wrapper3">
    <ul class="p-blog-list">
        <li class="p-list-item" ng-repeat="content in blogItems" ng-click="blogClickHandler($index)" ng-mousemove="changeOver($index)"
            ng-class="{over:$index==over}">
            <div class = "list-head">
                <h3 class="p-list-title">{{content.title}}</h3>
            </div>
            <div class="list-body">
                <p class="p-list-body">{{content.content}}</p>
            </div>

            <div class = "list-foot">
                <div class="name"><p class="p-list-username">用户:{{content.username}}</p></div>
                <div class="date"><p class="p-list-publish-time">{{content.date}}</p></div>
            </div>

        </li>
    </ul>
    <div class="null-show" ng-show="isNull">
        <p class="null-show-info">暂无内容</p>
    </div>

</div>

index

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>BlogSystem</title>

    <link rel="stylesheet" href="../stylesheets/index.css " type="text/css" />
    <link rel="stylesheet" href="../stylesheets/login.css " type="text/css" />
    <link rel="stylesheet" href="../stylesheets/sigup.css " type="text/css" />
    <link rel="stylesheet" href="../stylesheets/write-blog.css " type="text/css" />
    <link rel="stylesheet" href="../stylesheets/personal-homepage.css " type="text/css" />
    <link rel="stylesheet" href="../stylesheets/blog-item.css " type="text/css" />

    <script src="../javascripts/angular.js"></script>
    <script src="../javascripts/angular-route.js"></script>

</head>

<body ng-app="myApp">

    <div class="toolbar" ng-controller="homeCtrl">
        <div class="nav-pagebar">
            <ul>
                <li class="active pagebar">
                    <a href="#/bloglist">首页</a>
                </li>
                <li class="pagebar">
                    <a href="#/personalhome">个人主页</a>
                </li>
                <li class="pagebar">
                    <a href="#/writeblog">写博客</a>
                </li>
            </ul>
        </div>
        <div class="user-infomation" ng-show="isMyblog && isLogin">
            <h3 class="infomation">{{user.username}}的个人主页</h3>
        </div>
        <div class="user-infomation" ng-show="!isMyblog || !isLogin">
            <h3 class="infomation">简易博客系统</h3>
        </div>
        <div class="logarea">
            <div class="logbutton">
                [
                <!-- <a href="#/login">登陆</a> -->
                <button class="btnlogin" type="button" ng-click="login()" ng-disabled="isLogin">登陆</button>
                .
                <!-- <a href="#/signup">注册</a> -->
                <button class="btnsignup" type="button" ng-click="signup()" ng-disabled="isLogin">注册</button>
                .
                <button class="btnlogout" type="button" ng-click="logout()" ng-disabled="isLogout">退出</button>
                ]
            </div>
            <div class="loginfo">
                [
                <label class="" ng-show="isLogout" style="color: red">抱歉,您未登录</label>
                <label class="" ng-show="isLogin">欢迎,您已登录</label>
                ]
            </div>
        </div>
    </div>
    <div class="container clearfix">
        <nav class="nav-menu">
        </nav>
        <div ng-view class="main-content"></div>
        <div class="right-box">
        </div>
        <script src="../javascripts/index.js"></script>
</body>

</html>

login

<div class="wrapper1">
    <div class="wrapper11">
        <div class="form-wrapper">
            <form name="myForm" class="parent" ng-submit="dataSumbit()" novalidate>
                <div class="child login-header">    
                    <p class="p-login-header">用户登录</p>
                </div>
                <input class="child userinfo" type="text" name="userName" placeholder="用户名/手机号/邮箱" ng-model="user.username" username-Validate required>
                </input>
                <span class="showError" ng-show="myForm.userName.$dirty && myForm.userName.$touched">
                    <span  ng-show="myForm.userName.$error.required">用户名不能为空</span>
                    <span  ng-show="myForm.userName.$error.formatValid">用户名格式错误。</span>
                </span>
                <br>

                <input class="child userinfo" type="password" name="password" placeholder="密码" ng-model="user.password" required>
                </input>
                <span class="showError"  ng-show="myForm.password.$dirty && myForm.password.$touched">
                    <span ng-show="myForm.password.$error.required">密码不能为空</span>
                </span>

                <br>
                <input class="chk" type="checkbox" name="autologin" value="no">
                <span class="chbx">下一次自动登录</span>
                <br>
                <button type="submit" class="child btn-login" name="login">登录</button>
                <br>
            </form>
        </div>
    </div>

</div>

person

<div class="wrapper3">
    <ul class="p-blog-list">
        <li class="p-list-item" ng-repeat="content in blogItems" ng-click="blogClickHandler($index)" ng-mousemove="changeOver($index)"
            ng-class="{over:$index==over}">
            <div class="list-head">
                <h3 class="p-list-title">{{content.title}}</h3>
            </div>
            <div class="list-body">
                <p class="p-list-body">{{content.content}}</p>
            </div>

            <div class="list-foot">
                <div class="name">
                    <p class="p-list-username">用户:{{content.username}}</p>
                </div>
                <div class="date">
                    <p class="p-list-publish-time">{{content.date}}</p>
                </div>
            </div>

        </li>
    </ul>
    <div class="null-show" ng-show="isNull">
        <p class="null-show-info">空空如也~ 快写你的第一个博客吧</p>
        <input class="btn-write-blogs" type="button" ng-click="btnWtieBlogs()" value="写博客" />
    </div>

</div>

sigup

<div class="wrapper2">
    <div class="wrapper22">
        <div class="form-wrapper2">
            <form name="myForm" class="parent2" ng-submit="dataSumbit()" novalidate>
                <div class="child2 login-header2">
                    <p class="p-login-header2">用户注册</p>
                </div>
                <input class="child2 userinfo2" type="text" name="userName" placeholder="用户名/手机号/邮箱" ng-model="signUserInfo.username" username-Validate
                    username-Unique required />

                <span class="showError2" ng-show="myForm.userName.$dirty && myForm.userName.$touched">
                    <span ng-show="myForm.userName.$error.required">用户名不能为空</span>
                    <span ng-show="myForm.userName.$error.formatValid">用户名格式错误。</span>
                    <span ng-show="myForm.userName.$error.unique">用户名已存在</span>
                </span>
                <br>
                <input id="password" class="child2 userinfo2" type="password" name="password" placeholder="请输入密码" ng-model="signUserInfo.password"
                    required />
                <span class="showError2" ng-show="myForm.password.$dirty && myForm.password.$touched">
                    <span ng-show="myForm.password.$error.required">密码不能为空</span>
                </span>
                <br>

                <input id="confirmPassword" class="child2 userinfo2" type="password" name="confirmPassword" placeholder="再次输入密码" ng-model="signUserInfo.confirmPassword"
                    password-Repeat="password" required>
                </input>
                <span class="showError" ng-show="myForm.confirmPassword.$dirty && myForm.confirmPassword.$touched">
                    <span ng-show="myForm.confirmPassword.$error.required">密码不能为空</span>
                    <span ng-show="myForm.confirmPassword.$error.repeat">两次密码不一致</span>
                </span>
                <br>
                <button type=" submit " class="child2 btn-signup2" name="sigunup ">注册</button>
                <br>
            </form>
        </div>
    </div>

</div>

write

<div class="write-blog-wrapper">
    <div class="blog-box-title">
        <input class="txt-blog-title" type="text" placeholder="请输入文章标题" ng-model="blog.title" />
    </div>
    <div  class="blog-box-content">
        <textarea class="txt-blog-content" clos=",50" rows="5" warp="virtual" placeholder="在此编辑博客内容" ng-model="blog.content"></textarea>
    </div>
    <div class="blog-box-button">
        <input class="btnblog" type="button" ng-click = "blogPublish()" value="发布博客">
        <input class="btnblog" type="button" ng-click = "blogListReview()" value="查看列表">
    </div>

</div>

server

var http = require('http');
var url = require('url');
var path = require('path');
var static = require('./lib/static-request-handler');
var dynamic = require('./lib/dynamic-request-handler');
var mime =require('./lib/mime-type');
var PORT = 3000;

var server = http.createServer(onRequest);
//服务器监听程序
function onRequest(req, res) {

    var pathname = url.parse(req.url).pathname;

    // 获取后缀名并解析为相应的文件类型
    var suffix = path.extname(pathname);

    // 根据后缀名区分静态资源和动态资源请求
    if (suffix != null && suffix.trim() != "") {
        var contentType = mime.getContentType(suffix);
        static.staticReqHandler(pathname, contentType, res);
    } else {
        dynamic.dynamicReqHandler(pathname, req, res);
    }

}//onRequest

server.listen(PORT);
console.log("Server runing at port: " + PORT + ".");
SuellaSun commented 6 years ago

改进: var fs = require('fs'); var send = require('./send-page'); var path = require('path')

var createFolder = function (filename) { var sep = path.sep var folders = path.dirname(filename).split(sep); var p = ''; while (folders.length) { p += folders.shift() + sep; if (!fs.existsSync(p)) { fs.mkdirSync(p); } } };

function writeData(pathname, req, res) { var postData = '';

req.on('data', function (chunk) {
    postData += chunk;
});

req.on('end', function () {

    insertData(pathname, postData, res)
});

}

function insertData(pathname, postData, res) {

var reslut = { "status": "" };

var username = JSON.parse(postData).username;
// 查看源文件中是否有内容
fs.readFile(pathname, function (err, data) {
    if (err)
        send.send500(res);
    else {
        if (data == "") { // 如果文件为空,则写入格式如下
            postData = '[' + postData + ']';
        }
        else { // 如果格式不为空,则在将待写入的数据加在最后一个元素后面
            var buf = new Buffer(data);
            postData = buf.slice(0, buf.length - 1) + ',' + postData + ']';
        }
        fs.writeFile(pathname, postData, 'utf8', function (err) {
            if (err) {
                console.log('保存失败');
                reslut.status = 403.3;
                isSuccess = false;
            }
            else {
                // 保存完成后的回调函数
                console.log("保存完成");
                reslut.status = 200;
                var filename = path.join(__dirname, '/../public/json/blog-information/'+username + '.json');
                createFolder(filename);
                fs.createWriteStream(filename);

            }
            res.writeHead(200, { 'content-Type': 'text/plain' });
            res.end(JSON.stringify(reslut));
        });
    }
});

}

function insertData1(pathname, postData, res) {

var reslut = { "status": "" };

// 查看源文件中是否有内容
fs.readFile(pathname, function (err, data) {
    if (err)
        send.send500(res);
    else {

        if (data == "") { // 如果文件为空,则写入格式如下

            postData = JSON.parse(postData);
            postData = {
                "id": 1,
                "title": postData.title,
                "content": postData.content,
                "date": postData.date,
                "username": postData.username
            }
            postData = '[' + JSON.stringify(postData) + ']';
        }
        else { // 如果格式不为空,则在将待写入的数据加在最后一个元素后面
            data = JSON.parse(data);
            postData = JSON.parse(postData);
            postData = {
                "id": data.length + 1,
                "title": postData.title,
                "content": postData.content,
                "date": postData.date,
                "username": postData.username
            }
            data = JSON.stringify(data);
            postData = '[' + JSON.stringify(postData) + ',' + data.slice(1, data.length);

        }
        fs.writeFile(pathname, postData, 'utf8', function (err) {
            if (err) {
                console.log('保存失败');
                reslut.status = 403.3;
            }
            else {
                // 保存完成后的回调函数
                console.log("保存完成");
                reslut.status = 200;
            }
            res.writeHead(200, { 'content-Type': 'text/plain' });
            res.end(JSON.stringify(reslut));

        });
    }
});

}

exports.writeData = writeData; exports.insertData = insertData; exports.insertData1 = insertData1;

SuellaSun commented 6 years ago

index.js


var fs = require('fs');
var path = require('path');
var write = require('./write-data');
var send = require('./send-page');
const util = require('./util');

function dynamicReqHandler(pathname, req, res) {
    switch (pathname) {
        case "/":
            pathname = "./public/views/index.html";
            send.sendPage(pathname, 'text/html', res);
            break;
        case "/login":
            login(req, res);
            break;
        case "/signup":
            signup(req, res);
            break;
        case "/uniqueValidate":
            uniqueValidate(req, res);
            break;
        case "/postBlogs":
            postBlog(req, res);
            break;
        case "/getBlogList":
            getList(res);
            break;
        case "/getPersonalhome":
            getPersonalHomePage(req, res);
            break;
        case "/getArticleDetails":
            getArticleDetails(req, res);
            break;

        default:
            send.send500(res);
    }
}

// 用户登录验证
function login(req, res) {
    console.log("Request handler 'login' was called.");

    var postData = '';
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到postData变量中
    req.on('data', function (chunk) {
        postData += chunk;
    });
    // 在end事件触发后然后向客户端返回。
    req.on('end', function () {
        var reslut = { 'status': '' };
        postData = JSON.parse(postData);

        fs.readFile('./public/json/user-infomation.json', function (err, userInfo) {
            if (err)
                send.send500(res);
            else {
                if(userInfo !=""){
                    userInfo = JSON.parse(userInfo);
                    let flag = util.userExists(userInfo, postData);
                    if (flag >= 0) 
                        reslut.status = 200;
                    else 
                        reslut.status = 401.1;
                    res.writeHead(200, { 'content-Type': 'text/plain' });
                    res.end(JSON.stringify(reslut));
                }else{
                    reslut.status = 401.1;
                    res.writeHead(200, { 'content-Type': 'text/plain' });
                    res.end(JSON.stringify(reslut));
                }
            }
        });
    });
}

// 注册
function signup(req, res) {
    console.log("Request handler 'signup' was called.");
    pathname = './public/json/user-infomation.json';
    write.writeData(pathname, req, res);
}

// 验证用户名是否唯一
function uniqueValidate(req, res) {
    console.log("Request handler 'uniqueValidate' was called.");
    var postData = '';
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到postData变量中
    req.on('data', function (chunk) {
        postData += chunk;
    });
    // 在end事件触发后然后向客户端返回。
    req.on('end', function () {

        postData = JSON.parse(postData);// 解析接收的浏览器请求
        console.log(postData);

        // 返回给客户端的状态数据
        var reslut = { 'isUnique': '' };
        fs.readFile('./public/json/user-infomation.json', function (err, userInfo) {
            if (err)
                send.send500(res);
            else {
                if (userInfo != "") {
                    userInfo = JSON.parse(userInfo);
                    var flag = false;
                    for (var i = 0; i < userInfo.length; i++) {
                        if (userInfo[i].username === postData.username) 
                            flag = true;
                    }
                    if (flag) // 存在,不唯一
                        reslut.isUnique = false;
                    else  // 不存在,唯一
                        reslut.isUnique = true;
                    res.writeHead(200, { 'content-Type': 'text/plain' });
                    res.end(JSON.stringify(reslut));
                }
            }
        });
    });
}

// 提交博客数据
function postBlog(req, res) {
    console.log("Request handler 'postBlogs' was called.");
    var postData = '';

    req.on('data', function (chunk) {
        postData += chunk;
    });

    req.on('end', function () {
        postData = JSON.parse(postData);

        fs.readFile('./public/json/user-infomation.json', function (err, userInfo) {
            if (err)
                send.send500(res);
            else {
                let pathname = util.getPath(userInfo, postData.user);
                postData.blog.username = postData.user.username;
                write.insertBlogInfo(pathname, postData.blog, res);
            }
        });
    });

}
// 首页读取JSON数据,显示博客列表(修改,显示所有用户的最新10条)
function getList(res) {
    console.log("Request handler 'getList' was called.");

    dirname = path.join(__dirname, '/../public/json/blog-information/');
    let fileNames = util.findSync(dirname);
    var datas = [];
    for (let i = 0; i < fileNames.length; i++) {
        datas[i] = fs.readFileSync(fileNames[i], 'utf-8');
    }
    var copyDatas = util.getNotNullFile(datas);
    var blogData = "";
    if (copyDatas.length != 0) {
        var blogData = copyDatas[0].slice(0, copyDatas[0].length - 1);
        for (let i = 1; i < copyDatas.length; i++) {
            blogData += ',' + copyDatas[i].slice(1, copyDatas[i].length - 1);
        }
        blogData += ']';

        // 以date降序重新排列blogData
        blogData = JSON.parse(blogData).sort(util.keySort("date"));

        res.writeHead(200, { 'content-Type': 'application/json' });
        res.end(JSON.stringify(blogData));
    }
    else {
        blogData = "[]";

        res.writeHead(200, { 'content-Type': 'application/json' });
        res.end(blogData);
    }
}

// 读取个人主页数据
function getPersonalHomePage(req, res) {
    console.log("Request handler 'getPersonalHomePage' was called.");

    var postData = '';
    req.on('data', function (chunk) {
        postData += chunk;
    });
    // 在end事件触发后然后向客户端返回。
    req.on('end', function () {
        postData = JSON.parse(postData);// 解析接收的浏览器请求

        // 根据用户名区分是哪个用户的主页数据,读取相应文件
        fs.readFile('./public/json/user-infomation.json', function (err, userInfo) {
            if (err)
                send.send500(res);
            else {
                var pathname = util.getPath(userInfo, postData);
                send.sendPage(pathname, "application/json", res);
            }
        });
    });
}

// 获取博客详情
function getArticleDetails(req, res) {
    console.log("Request handler 'getArticleDetails' was called.");

    var postData = '';
    req.on('data', function (chunk) {
        postData += chunk;
    });

    req.on('end', function () {
        postData = JSON.parse(postData);
        let pathname = './public/json/blog-information/' + postData.username + '.json';
        blogData = JSON.parse(fs.readFileSync(pathname, 'utf-8'));

        res.writeHead(200, { 'content-type': "application/json" });
        res.end(JSON.stringify(blogData[blogData.length - postData.id]));
    });
}
exports.dynamicReqHandler = dynamicReqHandler;

util.js

const fs = require('fs');
const path = require('path');

// 获取非空文件列表
function getNotNullFile(arr) {
    var copyArr = [];
    for (let i = 0, j = 0; i < arr.length; i++) {
        if (arr[i] !== "") {
            copyArr[j++] = arr[i];
        }
    }
    return copyArr;
}

// 查看用户是否存在
function userExists(userInfo, postData) {
    let flag = -1;

    for (let i = 0; i < userInfo.length; i++) {
        if (userInfo[i].username === postData.username && userInfo[i].password === postData.password) {
            flag = i;
        }
    }
    return flag;
}

// 获取对应用户的存储路径
function getPath(userInfo, postData) {
    userInfo = JSON.parse(userInfo);

    let index = userExists(userInfo, postData);
    if (index >= 0) {
        pathname = './public/json/blog-information/' + userInfo[index].username + '.json';
    }
    return pathname;
}

// 获取指定目录下的文件
function findSync(startPath) {
    let fileNames = [];
    function finder(path) {
        let files = fs.readdirSync(path);
        files.forEach((val) => {
            let fPath = path + val;
            // 获取文件信息(对象)
            let stats = fs.statSync(fPath);
            if (stats.isDirectory())
                finder(fPath);
            if (stats.isFile())
                fileNames.push(fPath);
        });

    }
    finder(startPath);
    return fileNames;
}

// 新建文件
function createFolder(filename) {
    let sep = path.sep
    let folders = path.dirname(filename).split(sep);
    let p = '';
    while (folders.length) {
        p += folders.shift() + sep;
        if (!fs.existsSync(p)) {
            fs.mkdirSync(p);
        }
    }
};

// 将JSON数组按照某个属性排序
function keySort(property) {
    return function (obj1, obj2) {
        // 降序 return 1,降序 return-1
        return obj2[property] - obj1[property];
    }
}

exports.getNotNullFile = getNotNullFile;
exports.userExists = userExists;
exports.getPath = getPath;
exports.findSync = findSync;
exports.createFolder = createFolder;
exports.keySort = keySort;

write.js

var fs = require('fs');
var send = require('./send-page');
var path = require('path');
const util = require('./util');

function writeData(pathname, req, res,handler) {
    var postData = '';

    req.on('data', function (chunk) {
        postData += chunk;
    });

    req.on('end', function () {
        insertUserInfo(pathname, postData, res);
    });
}

function insertUserInfo(pathname, postData, res) {

    var reslut = { "status": "" };

    var username = JSON.parse(postData).username;

    // 查看源文件中是否有内容
    fs.readFile(pathname, function (err, fileData) {
        if (err)
            send.send500(res);
        else {
            if (fileData == "") { // 如果文件为空,则写入格式如下
                postData = '[' + postData + ']';
            }
            else { // 如果格式不为空,则将待写入的数据加在最后一个元素后面
                postData = fileData.slice(0, fileData.length - 1) + ',' + postData + ']';
            }
            fs.writeFile(pathname, postData, 'utf8', function (err) {
                if (err) {
                    console.log('保存失败');
                    reslut.status = 403.3;
                }
                else {
                    // 保存完成后的回调函数
                    console.log("保存完成");
                    reslut.status = 200;
                    var filename = path.join(__dirname, '/../public/json/blog-information/'+username + '.json');
                    util.createFolder(filename);
                    fs.createWriteStream(filename);

                }
                res.writeHead(200, { 'content-Type': 'text/plain' });
                res.end(JSON.stringify(reslut));
            });
        }
    });
}

function insertBlogInfo(pathname, postData, res) {
    var reslut = { "status": "" };

    // 查看源文件中是否有内容
    fs.readFile(pathname, function (err, fileData) {
        if (err)
            send.send500(res);
        else {

            if (fileData == "") { // 如果文件为空,则写入格式如下
                postData.id = 1;
                postData = '[' + JSON.stringify(postData) + ']';
            }
            else { // 如果格式不为空,则在将待写入的数据加在最后一个元素后面
                postData.id = JSON.parse(fileData).length + 1;
                postData = '[' + JSON.stringify(postData) + ',' + fileData .slice(1, fileData.length);

            }
            fs.writeFile(pathname, postData, 'utf8', function (err) {
                if (err) {
                    console.log('保存失败');
                    reslut.status = 403.3;
                }
                else {
                    // 保存完成后的回调函数
                    console.log("保存完成");
                    reslut.status = 200;
                }
                res.writeHead(200, { 'content-Type': 'text/plain' });
                res.end(JSON.stringify(reslut));

            });
        }
    });
}

exports.writeData = writeData;
exports.insertUserInfo = insertUserInfo;
exports.insertBlogInfo = insertBlogInfo;
SuellaSun commented 6 years ago

MVC(Model-View-Control)的概念以及所解决的问题相信大家都极其熟悉了,而在HTML/CSS/JS开发的页面中,一直存在的痛点在于,那些用JavaScript语言写的一陀一陀的操作DOM(即View)的代码如何去维护。 我们一般会使用jQuery库操作DOM来解决浏览器兼容性的问题,一定程度上也会简少代码量,但数据(即model)与DOM(view)的同步仍然是一个棘手的问题。

  有两种将数据模型与视图绑定的方式: 一种是后端模型,即使用JSP、FTL这类的Java端模板语言,将Java模型与HTML视图绑定,在服务器端渲染成HTML推送至浏览器;还一种是前端模型,即在后端将Java模型(或其他语言开发的模型)序列化成JSON送到浏览器,浏览器端通过“某种”方式,将JSON模型更新到HTML视图(DOM)中形成最终的页面。

  而在浏览器端把JSON更新到DOM中的方式,最原始的方式就是直接写JS操作DOM,包括使用jQuery这样的类库。缺点就是,这样的Web页面中,会被开发出大量的操作DOM的JavaScript代码, 而这样的代码对于后续维护和测试来说都可以说噩梦。于是出现了各种各样的在浏览器端进行数据绑定的模板语言(称为前端模板),比如ArcTemplate、EasyTemplate。忽略掉语法上细节差异, 这些模板语言基本上就是平移后端模板语言如JSP、FreeMarker的语法,在前端HTML中预留一些占位符(俗称挖坑)进行JSON数据的绑定,例如:Arctemplater的原生语法“ <div><%=i%>. <%=list[i].user%></div>”。 当然,这里JSON向DOM同步的过程需要手工执行JS调用,即这是一种非自动的单向的前端数据绑定。这就是第一代前端模板语言。

  接下来,各种JS MVC框架陆续登场。以AngularJS为例:
  首先,它们均使用前端模板(HTML/Template),比如“<div>Hello </div>”;
  其次,提供自动的由JSON模型到DOM视图间的双向数据绑定能力,这样对于页面开发来说,就省去了那个最大的痛点,用JavaScript开发的一陀一陀操作DOM的难以维护的JS代码;
  再次,AngularJS提供了指令(Directive)能力,可以扩展标准HTML属性、扩展HTML Tag标签,例如:“<input type="text" u-validator="maxLength(10)"></input>”这个例子中我们为标准的<input>标签增加了一个前端校验器的属性。

  总结,JS MVC就是在一种在浏览器端使用前端模板(Html/Template)、能自动进行双向数据绑定(Json/DOM)、甚至能够扩展HTML标准属性、Tag标签的一套前端页面开发框架与技术。
SuellaSun commented 6 years ago

Loading加载 当我们在浏览器地址栏中输入一个网址URL,或是点击页面中的一个链接新打开另一个页面,这个时候浏览器就要开始向服务器端发出HTTP请求,加载页面的html内容。 加载是一个持续的过程,现代浏览器并不会等到加载完成再去再后续解析等动作,而是加载一部分解析一部分。如果在解析的过程中,发现了其他的资源,例如:JS脚本文件、CSS文件、图片等其他资源时,会使用数量有限的独立线程去加载对应的资源。 Parse解析 当HTML文档部分或全部下载到浏览器端后,浏览器就要解析文档中的HTML标签,输出一棵与HTML标签对应的DOM对象树。这是一个复杂、反复的过程,详见《How browsers work \ HTML Parser》。 当解析到 Githubissues.

  • Githubissues is a development platform for aggregating issues.