zoukankan      html  css  js  c++  java
  • 01: 实现注册登录功能

    目录:抽屉项目之js最佳实践

    01: 实现注册登录功能

    02: 实现发布帖子功能

    03: 将帖子展示到页面、点赞

    04: 层级评论

    目录:

    1.1 显示、隐藏 "登录/注册" 菜单     返回顶部

      1、此部分实现下面三个功能

          功能1:未登录时在右上角显示 “登录/注册” 菜单

          功能2:成功登录后隐藏 “登录/注册” 菜单,显示登录用户信息

          功能3:js设置初始化函数:鼠标滑过显示注销功能,检查用户已登录直接显示登录信息,而不是"登录/注册"菜单

                      

      2、相关code

    <body>
        <div class="header">
            <div class="w">
                <div class="login_or_register fr">
                    <a href="javascript:void(0);" onclick="show_login_reg_frm()">登录 / 注册</a>
                </div>
                <div class="user_info fr">
                    <span id="display_name"  {% if is_login %}is_login{% endif %}>{{ user.display_name }}</span>
                    <div class="user_menu hide">
                        <a>设置</a>
                        <a onclick="logout()">退出</a>
                    </div>
                </div>
            </div>
        </div>
    </body>
    index.html html页面
    <body>
        <script>
            /* 初始化函数 */
            $(function () {
                /* 处理是否登录 */
                if($("#display_name")[0].hasAttribute("is_login")){
                    // 已经登录
                    $(".login_or_register").addClass("hide");
                    $(".user_info").removeClass("hide");
                }else {
                    // 未登录
                    $(".login_or_register").removeClass("hide");
                    $(".user_info").addClass("hide");
                }
    
                /* 用户菜单是否显示: 鼠标划过就会触发.hover绑定的函数 */
                $("div.user_info").hover(function () {
                    show_user_menu(true);
                },function () {
                    show_user_menu(false);
                });
            });
        </script>
    </body>
    index.html js初始化函数
    /* 显示登录、注册页面 */
    function show_login_reg_frm() {
        $("div.login_reg_frm").removeClass("hide");
        $("div.shelter").removeClass("hide");
    }
    
    /* 注销 */
    function logout() {
        $.get({
            url: "/app01/logout/",
            dataType: "json",
            success:function (response) {
                if(response.status=='ok'){
                    window.location.href="/app01/";
                }
            }
        })
    }
    
    /* 用户下拉菜单显示开关 */
    function show_user_menu(flag) {
        if(flag){
            $("div.user_menu").removeClass("hide");
        }else{
            $("div.user_menu").addClass("hide");
        }
    }
    base.js
    # 注销
    def logout(request):
        request.session['is_login'] = False
        request.session['current_user'] = {}
        return HttpResponse(json.dumps({'status': 'ok'}))
    views.py

    1.2 注册功能     返回顶部

       1、此部分实现以下四个功能

        功能1:提交用户注册信息

        功能2:检查用户名和邮箱是否已注册

        功能3:检查两次密码是否一致

        功能4:创建验证码图片标签

             

      2、功能1提交用户信息

    <body>
        <div class="shelter hide">
            <div class="login_reg_frm hide">
                <div class="close_login_reg_frm" onclick="close_login_reg_frm()">×</div>
                <div class="reg_frm fl">
                    <h1>注册</h1>
                    <form method="post" id="register_frm">
                        <table>
                            <tr>
                                <th>用户名</th>
                                <td><input type="text" id="login_name" name="login_name" onblur="check_exist(this)"></td>
                                <td class="tips"></td>
                            </tr>
                            <tr>
                                <th>邮箱</th>
                                <td><input type="email" id="email" name="email" onblur="check_exist(this)"></td>
                                <td class="tips"></td>
                            </tr>
                            <tr>
                                <th>密码</th>
                                <td><input id="password" type="password" name="password" autocomplete="off" minlength="3"></td>
                                <td class="tips"></td>
                            </tr>
                            <tr>
                                <th>确认密码</th>
                                <td><input id="password2" type="password" name="password2" autocomplete="off" minlength="3" onblur="confirm_password()"></td>
                                <td class="tips"></td>
                            </tr>
                            <tr>
                                <th>验证码</th>
                                <td>
                                    <input type="text" id="verify_code" name="verify_code" class="verify_code" maxlength="4" onclick="create_verify_code_img()">
                                </td>
                                <td class="tips"></td>
                            </tr>
                        </table>
                        <div style="position: relative;">
                            <a href="javascript:void(0);" onclick="register(this)">注册</a>
                            <div class="reg_shelter hide"></div>
                        </div>
    
                        <br>
                        <div class="register_result"></div>
                    </form>
                </div>
            </div>
        </div>
    </body>
    index.html html注册界面
    /* 提交用户注册信息 */
    function register(ele) {
        // 数据检查
        var check_pass = true;
        var check_list = {
            'login_name': '用户名',
            'email': '邮箱',
            'password': '密码',
            'password2': '确认密码',
            'verify_code': '验证码'
        };
        for(var key in check_list){
            var val = $.trim($('.reg_frm #' + key).val());
            if(val.length==0){
                // 如果要检查的input值为空,提醒用户
                check_pass = false;
                $(".reg_frm #" + key).parent().parent().find('td:last-child').text("不能为空");
            }
        }
        if(!check_pass){
            return false;
        }
    
        // 通过检查后
        var login_name = $.trim($('.reg_frm #login_name').val());
        var email = $.trim($('.reg_frm #email').val());
        var password = $.trim($('.reg_frm #password').val());
        var password2 = $.trim($('.reg_frm #password2').val());
        var verify_code = $.trim($('.reg_frm #verify_code').val());
    
        // 提交前,先将按钮置为不可点击
        $("div.reg_shelter").removeClass("hide");
        var data = $('#register_frm').serialize();
        console.log(data);
        $.post({
            url: "/app01/register/",
            data: data,
            dataType: "json",
            success: function (response) {
                console.log(response);
                if(response.hasOwnProperty("status")){
                    if(response.status=='ok'){
                        //console.log("注册成功");
                        $("div.register_result").text("注册成功");
                        setTimeout(function () {
                            $("div.login_reg_frm").addClass("hide");
                            $("div.shelter").addClass("hide");
                        }, 2000);
                    }else{
                        $("div.reg_shelter").addClass("hide");
                        $("div.register_result").text(response.msg);
                    }
                }else{
                    var ul = document.createElement('ul');
                    for(var key in response){
                        var li = document.createElement('li');
                        li.innerText = response[key][0].message;
                        ul.appendChild(li);
                    }
                    $("div.register_result").html(ul.outerHTML);
                    $("div.reg_shelter").addClass("hide");
                }
            },
            error: function (xhr) {
                $("div.reg_shelter").addClass("hide");
            }
        });
        reload_verify_code();   // 无论结果如何,都刷新验证码
    }
    base.js
    # 用户注册
    def register(request):
        # 注册的URL
        if request.method == 'POST':
            reg_frm = RegisterFrm(data=request.POST)
            if reg_frm.is_valid():
                cd = reg_frm.cleaned_data
                # 验证码比对
                vcode_from_client = cd.get("verify_code", "")
                vcode_in_session = request.session.get("verify_code")
                if vcode_from_client and vcode_in_session and vcode_from_client.upper() == vcode_in_session.upper():
                    # 验证码比对通过
                    new_user = reg_frm.save(commit=False)
                    password2 = cd.get("password2")
                    m = hashlib.md5()
                    m.update(password2.encode())
                    new_user.password = m.hexdigest()
                    new_user.display_name = cd.get("login_name")
                    new_user.email = cd.get("email")
                    # new_user.last_login = datetime.datetime.now()
                    new_user.last_login = timezone.now()
                    new_user.last_ip = request.META.get("REMOTE_ADDR")
                    new_user.save()
                    # request.POST['verify_code'] = ""
                    return HttpResponse(json.dumps({'status': 'ok'}))
                return HttpResponse(json.dumps({'status': 'fail', 'msg': '验证码不正确'}))
            else:
                return HttpResponse(reg_frm.errors.as_json())
    views.py

      3、功能2检查用户名和邮箱是否已注册

    <tr>
        <th>用户名</th>
        <td><input type="text" id="login_name" name="login_name" onblur="check_exist(this)"></td>
        <td class="tips"></td>
    </tr>
    <tr>
        <th>邮箱</th>
        <td><input type="email" id="email" name="email" onblur="check_exist(this)"></td>
        <td class="tips"></td>
    </tr>
    index.html 绑定事件
    /* 检查用户名和邮箱是否已注册 */
    function check_exist(ele) {
        var t = ele.getAttribute("name");
        var v = ele.value;
        v = $.trim(v);
        if(v.length>0){
            $.post({
                url: "/app01/check_exist/",
                data: {"check_type": t, "check_value": v},
                dataType: "json",
                success: function (response) {
                    var check_result = "";
                    if(response.status=='ok'){
                        // 没有重复
                        check_result = "√";
                    }else{
                        check_result = "已存在";
                        ele.setAttribute("duplicate", "duplicate");
                    }
                    $(ele).parent().parent().find('td:last-child').text(check_result);
                }
            });
        }
    }
    base.js
    # 用户注册时,检查提交的数据是否占用
    def check_exist(request):
        # 检查是否已存在相同的值
        if request.method == 'POST':
            check_type = request.POST.get("check_type")
            value = request.POST.get("check_value")
            parameter = {check_type: value}
            count = User.objects.filter(**parameter).count()
            if count > 0:
                return HttpResponse(json.dumps({'status': 'fail', 'msg': 'exist'}))
            else:
                return HttpResponse(json.dumps({'status': 'ok'}))
    views.py

      4、功能3检查两次密码是否一致

    <tr>
        <th>密码</th>
        <td><input id="password" type="password" name="password" autocomplete="off" minlength="3"></td>
        <td class="tips"></td>
    </tr>
    <tr>
        <th>确认密码</th>
        <td><input id="password2" type="password" name="password2" autocomplete="off" minlength="3" onblur="confirm_password()"></td>
        <td class="tips"></td>
    </tr>
    index.html 绑定事件
    /* 检查两次密码是否一致 */
    function confirm_password() {
        if($('.reg_frm #password').val()!=$('#password2').val()){
            $('.reg_frm #password2').parent().parent().find('td:last-child').text("两次密码不一致");
        }else{
            $('.reg_frm #password').parent().parent().find('td:last-child').text("√");
            $('.reg_frm #password2').parent().parent().find('td:last-child').text("√");
        }
    }
    base.js

      5、功能4创建验证码图片标签 

    <tr>
        <th>验证码</th>
        <td>
            <input type="text" id="verify_code" name="verify_code" class="verify_code" maxlength="4" onclick="create_verify_code_img()">
        </td>
        <td class="tips"></td>
    </tr>
    index.html 绑定事件
    /* 创建验证码图片标签 */
    function create_verify_code_img() {
        // 创建验证码图片标签,插入到验证码输入框后面
        if(!document.getElementById('verify_code_img')){
            var img = document.createElement('img');
            img.id = 'verify_code_img';
            img.src = '/app01/verify_code/';
            img.className = 'verify_code';
            img.onclick = reload_verify_code;
            $("input.verify_code").after(img);
        }
    }
    
    /* 刷新验证码函数 */
    function reload_verify_code() {
        var img = $('img.verify_code')[0];
        img.src += '?';
    }
    base.js
    def verify_code(request):
        """生成验证码图片"""
        from backend import check_code as CheckCode  # 该check_code是老师的验证码插件
        from io import BytesIO  # BytesIO是内存Stream,用于存取二进制数据,可当文件handler用
        codeImg, strs = CheckCode.create_validate_code()
        request.session['verify_code'] = strs
        stream = BytesIO()
        codeImg.save(stream, 'png')
        return HttpResponse(stream.getvalue(), r'image/png')
    views.py
    import random
    from PIL import Image, ImageDraw, ImageFont, ImageFilter
    
    _letter_cases = "abcdefghjkmnpqrstuvwxy"  # 小写字母,去除可能干扰的i,l,o,z
    _upper_cases = _letter_cases.upper()  # 大写字母
    _numbers = ''.join(map(str, range(3, 10)))  # 数字
    init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
    
    def create_validate_code(size=(120, 30),
                             chars=init_chars,
                             img_type="GIF",
                             mode="RGB",
                             bg_color=(255, 255, 255),
                             fg_color=(0, 0, 255),
                             font_size=18,
                             font_type="Monaco.ttf",
                             length=4,
                             draw_lines=True,
                             n_line=(1, 2),
                             draw_points=True,
                             point_chance = 2):
        '''
        @todo: 生成验证码图片
        @param size: 图片的大小,格式(宽,高),默认为(120, 30)
        @param chars: 允许的字符集合,格式字符串
        @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
        @param mode: 图片模式,默认为RGB
        @param bg_color: 背景颜色,默认为白色
        @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
        @param font_size: 验证码字体大小
        @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
        @param length: 验证码字符个数
        @param draw_lines: 是否划干扰线
        @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
        @param draw_points: 是否画干扰点
        @param point_chance: 干扰点出现的概率,大小范围[0, 100]
        @return: [0]: PIL Image实例
        @return: [1]: 验证码图片中的字符串
        '''
    
        width, height = size # 宽, 高
        img = Image.new(mode, size, bg_color) # 创建图形
        draw = ImageDraw.Draw(img) # 创建画笔
    
        def get_chars():
            '''生成给定长度的字符串,返回列表格式'''
            return random.sample(chars, length)
    
        def create_lines():
            '''绘制干扰线'''
            line_num = random.randint(*n_line) # 干扰线条数
    
            for i in range(line_num):
                # 起始点
                begin = (random.randint(0, size[0]), random.randint(0, size[1]))
                #结束点
                end = (random.randint(0, size[0]), random.randint(0, size[1]))
                draw.line([begin, end], fill=(0, 0, 0))
    
        def create_points():
            '''绘制干扰点'''
            chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]
    
            for w in range(width):
                for h in range(height):
                    tmp = random.randint(0, 100)
                    if tmp > 100 - chance:
                        draw.point((w, h), fill=(0, 0, 0))
    
        def create_strs():
            '''绘制验证码字符'''
            c_chars = get_chars()
            strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开
    
            font = ImageFont.truetype(font_type, font_size)
            font_width, font_height = font.getsize(strs)
    
            draw.text(((width - font_width) / 3, (height - font_height) / 3),
                        strs, font=font, fill=fg_color)
    
            return ''.join(c_chars)
    
        if draw_lines:
            create_lines()
        if draw_points:
            create_points()
        strs = create_strs()
    
        # 图形扭曲参数
        params = [1 - float(random.randint(1, 2)) / 100,
                  0,
                  0,
                  0,
                  1 - float(random.randint(1, 10)) / 100,
                  float(random.randint(1, 2)) / 500,
                  0.001,
                  float(random.randint(1, 2)) / 500
                  ]
        img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
    
        img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)
    
        return img, strs
    /backend/check_code.py

    1.3 登录功能     返回顶部

        1、此部分实现以下四个功能

        功能1:提交用户登录信息

        功能2:对用户提交信息验证

      2、相关code

    <body>
        <div class="shelter hide">
            <div class="login_reg_frm hide">
                <div class="close_login_reg_frm" onclick="close_login_reg_frm()">×</div>
                <div class="login_frm fl">
                    <h1>登录</h1>
                    <table>
                        <tr>
                            <th>用户名</th><td><input type="text" name="login_name" class="login_name"></td>
                        </tr>
                        <tr>
                            <th>密码</th><td><input type="password" name="password" class="password"></td>
                        </tr>
                    </table>
                    <a href="javascript:void(0);" onclick="login(this)">登录</a>
                    <div class="login_result"></div>
                </div>
            </div>
        </div>
    </body>
    index.html html登录界面
    /* 登录 */
    function login() {
        var login_name = $(".login_frm input.login_name").val();
        var password = $(".login_frm input.password").val();
        $.post({
            url: '/app01/login/',
            data: {'login_name': login_name, 'password': password},
            dataType: "json",
            success: function (response) {
                if(response.status=='ok'){
                    // 登录成功,读取用户昵称和头像
                    $("div.login_result").text("登录成功");
                    var display_name = response.display_name;
                    var head_pic = response.head_pic;
                    $("span#display_name").text(display_name);
                    $("img.head_pic").attr("src", head_pic);
                    $("div.login_reg_frm").addClass("hide");
                    $("div.shelter").addClass("hide");
                    $(".user_info #display_name").attr("is_login", "");
                    $(".user_info").removeClass("hide");
                    $(".login_or_register").addClass("hide");
                    get_online_users();
                }else{
                    $("div.login_result").text(response.error);
                }
            },
            error: function (xhr) {
    
            }
        });
    }
    
    /* 检查是否登录 */
    function is_login() {
        return document.getElementById('display_name').hasAttribute('is_login');
    }
    
    /* 隐藏登录框 */
    function close_login_reg_frm() {
        $("div.login_reg_frm").addClass("hide");
        $("div.shelter").addClass("hide");
    }
    base.js
    # 登陆
    def login(request):
        # 登录视图,检查用户名 + 密码md5 ,不通过返回fail+验证失败
        # 检查enable,不通过返回fail + 用户已停用
        # 全部通过则返回ok+用户昵称+用户头像
        if request.method == 'POST':
            ret = {'status': '',
                   'error': '',
                   'display_name': '',
                   'head_pic': ''}
            login_name = request.POST.get("login_name")
            password = request.POST.get("password")
            if login_name and password:
                # 将密码转md5
                m = hashlib.md5()
                m.update(password.encode())
                password_md5 = m.hexdigest()
    
                # 获取用户对象
                user = User.objects.filter(login_name=login_name, password=password_md5).first()
                if user:
                    # 检查是否无效
                    if user.enable:
                        # 有效
                        # 将用户信息登记到session中
                        request.session['is_login'] = True
                        request.session['current_user'] = {
                            'id': user.id,
                            'login_name': user.login_name,
                            'display_name': user.display_name,
                        }
    
                        # 返回验证通过信息+用户昵称+头像url到客户端
                        ret['status'] = 'ok'
                        ret['display_name'] = user.display_name
                        ret['head_pic'] = settings.STATIC_URL + r'img/head/' + (user.head_pic or 'mxcp_320x320.jpg')
                    else:
                        ret['status'] = 'fail'
                        ret['error'] = '该用户已停用'
                else:
                    ret['status'] = 'fail'
                    ret['error'] = '用户名或密码不正确'
            else:
                ret['status'] = 'fail'
                ret['error'] = '用户名或者密码不能为空'
            return HttpResponse(json.dumps(ret))
    views.py

    1.4 获取当前用户数量     返回顶部

        <script>
            /* 初始化函数 */
            $(function () {
                /* 显示在线用户 */
                get_online_users();
                setInterval(get_online_users, 10000);
            });
        </script>
    初始化函数中使用定时器实时跟新在线用户数量
    /* 获取在线用户 */
    function get_online_users() {
        if(is_login()){
            var online_users_container = $("div.online_users_container");
            // 清理工作
            online_users_container.children().remove();
            online_users_container.text("");
        
            // 获取在线用户
            $.get({
                url:"/app01/get_online_users/",
                dataType:"json",
                success:function (response) {
                    if(response.status=='ok'){
                        console.log(response);
                        var users = response.data;
                        online_users_container.text("在线用户列表:");
                        for(var key in users){
                            var user_a = document.createElement('a');
                            user_a.innerText=users[key]['display_name'];
                            user_a.setAttribute("user_id", users[key]['id']);
                            user_a.href = "javascript:void(0);";
                            online_users_container.append(user_a);
                        }
                    }
                }
            });
        
        }
    }
    get_online_users(js) 获取在线用户数量
    def get_online_users(request):
        current_user = request.session.get("current_user")
        current_user_id = current_user.get("id")
        current_time = timezone.now()
        td = datetime.timedelta(**settings.LOGIN_PARAMETERS['ONLINE_INTERVAL'])
        users = User.objects.exclude(id=current_user_id, ).filter(is_login=True,
                                                                  last_login__gte=(
                                                                      current_time + td)
                                                                  ).values("id", "head_pic", "display_name",)
        users_list = list(users)
        return HttpResponse(json.dumps({
            'status': 'ok',
            'data': users_list
        }))
    views.py 从数据库中统计在线用户数量

    附加:js代码(四个大功能点)

    // 第一部分:实现登录注册功能
    /* ajax检查数据是否已被注册使用 */
    function check_exist(ele) {
        var t = ele.getAttribute("name");
        var v = ele.value;
        v = $.trim(v);
        if(v.length>0){
            $.post({
                url: "/app01/check_exist/",
                data: {"check_type": t, "check_value": v},
                dataType: "json",
                success: function (response) {
                    // console.log(response);
                    var check_result = "";
                    if(response.status=='ok'){
                        // 没有重复
                        check_result = "√";
                    }else{
                        check_result = "已存在";
                        ele.setAttribute("duplicate", "duplicate");
                    }
                    $(ele).parent().parent().find('td:last-child').text(check_result);
                }
            });
        }
    }
    
    function register(ele) {
        // 数据检查
        var check_pass = true;
        var check_list = {
            'login_name': '用户名',
            'email': '邮箱',
            'password': '密码',
            'password2': '确认密码',
            'verify_code': '验证码'
        };
        for(var key in check_list){
            var val = $.trim($('.reg_frm #' + key).val());
            if(val.length==0){
                // 如果要检查的input值为空,提醒用户
                check_pass = false;
                $(".reg_frm #" + key).parent().parent().find('td:last-child').text("不能为空");
            }
        }
        if(!check_pass){
            return false;
        }
    
        // 通过检查后
        var login_name = $.trim($('.reg_frm #login_name').val());
        var email = $.trim($('.reg_frm #email').val());
        var password = $.trim($('.reg_frm #password').val());
        var password2 = $.trim($('.reg_frm #password2').val());
        var verify_code = $.trim($('.reg_frm #verify_code').val());
    
        // 提交前,先将按钮置为不可点击
        $("div.reg_shelter").removeClass("hide");
        var data = $('#register_frm').serialize();
        console.log(data);
        $.post({
            url: "/app01/register/",
            data: data,
            dataType: "json",
            success: function (response) {
                console.log(response);
                if(response.hasOwnProperty("status")){
                    if(response.status=='ok'){
                        //console.log("注册成功");
                        $("div.register_result").text("注册成功");
                        setTimeout(function () {
                            $("div.login_reg_frm").addClass("hide");
                            $("div.shelter").addClass("hide");
                        }, 2000);
                    }else{
                        $("div.reg_shelter").addClass("hide");
                        $("div.register_result").text(response.msg);
                    }
                }else{
                    var ul = document.createElement('ul');
                    for(var key in response){
                        var li = document.createElement('li');
                        li.innerText = response[key][0].message;
                        ul.appendChild(li);
                    }
                    $("div.register_result").html(ul.outerHTML);
                    $("div.reg_shelter").addClass("hide");
                }
            },
            error: function (xhr) {
                $("div.reg_shelter").addClass("hide");
            }
        });
        reload_verify_code();   // 无论结果如何,都刷新验证码
    }
    
    /* 检查两次密码是否一致 */
    function confirm_password() {
        if($('.reg_frm #password').val()!=$('#password2').val()){
            $('.reg_frm #password2').parent().parent().find('td:last-child').text("两次密码不一致");
        }else{
            $('.reg_frm #password').parent().parent().find('td:last-child').text("√");
            $('.reg_frm #password2').parent().parent().find('td:last-child').text("√");
        }
    }
    
    /* 创建验证码图片标签 */
    function create_verify_code_img() {
        // 创建验证码图片标签,插入到验证码输入框后面
        if(!document.getElementById('verify_code_img')){
            var img = document.createElement('img');
            img.id = 'verify_code_img';
            img.src = '/app01/verify_code/';
            img.className = 'verify_code';
            img.onclick = reload_verify_code;
            $("input.verify_code").after(img);
        }
    }
    
    /* 刷新验证码函数 */
    function reload_verify_code() {
        var img = $('img.verify_code')[0];
        img.src += '?';
    }
    
    /* 显示登录、注册页面 */
    function show_login_reg_frm() {
        $("div.login_reg_frm").removeClass("hide");
        $("div.shelter").removeClass("hide");
    }
    
    /* 用户下拉菜单显示开关 */
    function show_user_menu(flag) {
        if(flag){
            $("div.user_menu").removeClass("hide");
        }else{
            $("div.user_menu").addClass("hide");
        }
    }
    
    /* 登录 */
    function login() {
        var login_name = $(".login_frm input.login_name").val();
        var password = $(".login_frm input.password").val();
        $.post({
            url: '/app01/login/',
            data: {'login_name': login_name, 'password': password},
            dataType: "json",
            success: function (response) {
                if(response.status=='ok'){
                    // 登录成功,读取用户昵称和头像
                    $("div.login_result").text("登录成功");
                    var display_name = response.display_name;
                    var head_pic = response.head_pic;
                    $("span#display_name").text(display_name);
                    $("img.head_pic").attr("src", head_pic);
                    $("div.login_reg_frm").addClass("hide");
                    $("div.shelter").addClass("hide");
                    $(".user_info #display_name").attr("is_login", "");
                    $(".user_info").removeClass("hide");
                    $(".login_or_register").addClass("hide");
                    get_online_users();
                }else{
                    $("div.login_result").text(response.error);
                }
            },
            error: function (xhr) {
    
            }
        });
    }
    
    /* 注销 */
    function logout() {
        $.get({
            url: "/app01/logout/",
            dataType: "json",
            success:function (response) {
                if(response.status=='ok'){
                    window.location.href="/app01/";
                }
            }
        })
    }
    
    /* 检查是否登录 */
    function is_login() {
        return document.getElementById('display_name').hasAttribute('is_login');
    }
    
    /* 隐藏登录框 */
    function close_login_reg_frm() {
        $("div.login_reg_frm").addClass("hide");
        $("div.shelter").addClass("hide");
    }
    part1: 实现登录注册功能
    // 第二部分:实现发布帖子功能
    /* 展示发布框 */
    function show_publish_frm(flag) {
        if(!is_login()){
            show_login_reg_frm();
            return false;
        }
        if(flag){
            $("div.shelter").removeClass("hide");
            $("div.publish_frm").removeClass("hide");
        }else{
            $("div.shelter").addClass("hide");
            $("div.publish_frm").addClass("hide");
        }
    }
    
    function clear_publish_form() {
                $("textarea.publish_text").val("");
                $(".publish_frm a.current").removeClass("current");
                $("#fo")[0].reset();
                $("div.uploaded_preview").children().remove();
            }
    
    function publish() {
        var data = {};
        data['pub_text'] = $.trim($("textarea.publish_text").val());
        // 检查文本内容是否为空
        if(data['pub_text'].length==0){
            alert("文字内容不能为空。");
            return false;
        }
    
        // 检查是否有选择类别
        data['catalog'] = $("div.publish_catalog a.current").attr("cid");
        if(!data['catalog']){
            alert("请选择一个分类");
            return false;
        }
    
        // 获取图片
        var img = $("div.uploaded_preview img")[0];
        if(img){
            data['img_link'] = $(img).attr("src");
        }
    
        $.post({
            url:"/app01/publish/",
            data: data,
            dataType: "json",
            success: function (response) {
                if(response.status=='ok'){
                    alert("发布成功!");
                    clear_publish_form();
                    show_publish_frm(false);
                    $("div.shelter").addClass("hide");
                }
            },
            error: function (xhr) {
    
            }
        });
    }
    
    function upload_img() {
        document.getElementById('if').onload=callback;
        document.getElementById('fo').submit();
    }
    
    /* 上传完毕后的回调函数 */
    function callback() {
        var t = $("#if").contents().find('body').text();
        var result = JSON.parse(t);
        console.log(result);
        if(result.status=='ok'){
            var a = document.createElement('a');
            a.href = result.link;
            a.target = '_blank';
            var img = document.createElement('img');
            img.src = result.link;
            a.appendChild(img);
            $("div.uploaded_preview").html(a.outerHTML);
        }
    }
    
    function get_online_users() {
            if(is_login()){
                var online_users_container = $("div.online_users_container");
                // 清理工作
                online_users_container.children().remove();
                online_users_container.text("");
    
                // 获取在线用户
                $.get({
                    url:"/app01/get_online_users/",
                    dataType:"json",
                    success:function (response) {
                        if(response.status=='ok'){
                            console.log(response);
                            var users = response.data;
                            online_users_container.text("在线用户列表:");
                            for(var key in users){
                                var user_a = document.createElement('a');
                                user_a.innerText=users[key]['display_name'];
                                user_a.setAttribute("user_id", users[key]['id']);
                                user_a.href = "javascript:void(0);";
                                online_users_container.append(user_a);
                            }
                        }
                    }
                });
    
            }
        }
    prt2: 实现发布帖子功能
    // 第三部分:将帖子展示到页面,点赞
    function create_post_list(posts, cls) {
        if(posts.length>0){
            var big_div = document.createElement('div');
            big_div.className = cls;
            for(var i=0;i<posts.length;i++){
                var post_div = document.createElement('div'); // 包裹着整个帖子的div
                post_div.className="post_container clearfix";
                post_div.setAttribute("post_id", posts[i].id);
                var left_div = document.createElement('div');
                left_div.className="left_container fl";
                var right_div = document.createElement('div');
                right_div.className="right_container fl";
                var content_div = document.createElement('div');
                content_div.className="post_content";
                var bar_div = document.createElement('div');
                bar_div.className="post_bar";
                var comment_div = document.createElement('div');
                comment_div.className="comment_container hide";
    
                content_div.innerText = posts[i].content;
                var like = posts[i].like?"已赞":"赞";
                var like_a = document.createElement('a');
                var comment_a = document.createElement('a');
                var displayname_span = document.createElement("span");
                var create_i = document.createElement('i');
                like_a.href = comment_a.href = "javascript:void(0);";
                like_a.className="like_btn";
                like_a.setAttribute("onclick", "like(this," + posts[i].id + ")");
                like_a.setAttribute("like_count", posts[i].like_count);
                like_a.innerText = like+ '(' + posts[i].like_count + ')';
                comment_a.className="show_comments_btn";
                comment_a.setAttribute("onclick", "show_comments(this,"+ posts[i].id +")");
                comment_a.innerText = '评('+posts[i].comment_count+')';
                displayname_span.innerText = posts[i].user__display_name;
                create_i.innerText='在 '+posts[i].create_on+' 发布';
                bar_div.appendChild(like_a);
                bar_div.appendChild(comment_a);
                bar_div.appendChild(displayname_span);
                bar_div.appendChild(create_i);
    
                // comment_div.innerText = "这里是评论";
                var comment_text_container = document.createElement('div');
                var comment_content_container = document.createElement('div');
                comment_text_container.className="comment_text_container";
                comment_content_container.className="comment_content_container";
                comment_div.appendChild(comment_text_container);
                comment_div.appendChild(comment_content_container);
    
    
                left_div.appendChild(content_div);
                left_div.appendChild(bar_div);
    
                if(posts[i].hasOwnProperty("img_link")){
                    var img = document.createElement('img');
                    img.src = posts[i].img_link;
                    right_div.appendChild(img);
                }
    
                var row_container = document.createElement('div');
                row_container.className="row_container clearfix";
                row_container.appendChild(left_div);
                row_container.appendChild(right_div);
    
                post_div.appendChild(row_container);
                post_div.appendChild(comment_div);
    
                big_div.appendChild(post_div);
            }
            $("div.post_list").append(big_div);
        }
    }
    
    function view_posts(ele, catalog, page) {
        $(ele).siblings('a').removeClass("current");
        $(ele).addClass("current");
        $("div.paginator").children().remove();
        $.get({
            url:"/app01/posts/",
            data:{"catalog":catalog, "page":page},
            dataType:"json",
            success:function (response) {
                if(response.status=='ok'){
                    // 服务器返回数据
                    // console.log(response);
                    var posts = response['data']['posts'];
                    var current_page = response['data']['current_page'];
                    var page_count = response['data']['page_count'];
    
                    if(posts.length>0){
                        // 有帖子数据
                        // 区分置顶和普通帖子
                        var top_post_list = [];
                        var normal_post_list = [];
                        for(var key in posts){
                            var post = posts[key];
                            if(post.top){
                                // 帖子有置顶属性
                                if(post.catalog_id==response['data']['current_catalog']){
                                    // 帖子是当前类别
                                    post.content = '【置顶】'+ post.content;
                                    top_post_list.push(post);
                                }else{
                                    // 推入非置顶帖子
                                    normal_post_list.push(post);
                                }
                            }else{
                                // 非置顶帖子
                                normal_post_list.push(post);
                            }
                        }
    
                        // 分好之后交给对应的函数处理
                        $("div.post_list").html("");
                        create_post_list(top_post_list,"top_posts");
                        create_post_list(normal_post_list,"normal_posts");
                        create_paginator(page_count, current_page);
                    }else {
                        // 没有帖子
                        $("div.post_list").text("还没有帖子喲,要不你发一个:)");
                    }
                }
            }
        });
    }
    
    /* 分页 */
    function create_paginator(total, current) {
        if(total>0){
            var paginator_container = $("div.paginator");
            paginator_container.children().remove();
            for(var i=1;i<=total;i++){
                var a = document.createElement('a');
                a.innerText=i;
                if(i==current) a.className="current";
                a.href="javascript:void(0);";
                var cid = $("div.nav a.current").attr("cid");
                a.setAttribute("onclick", "view_posts(this,"+cid+","+i+")");
                paginator_container.append(a);
            }
        }
    }
    part3: 将帖子展示到页面,点赞
    // 第四部分:创建和提交、层级评论
    /* 点赞 */
    function like(ele, post_id) {
        if(!is_login()){
            show_login_reg_frm();
            return false;
        }
        $.get({
            url:"/app01/like_post/",
            data:{'post':post_id},
            dataType:"json",
            success: function (response) {
                console.log(response);
                if(response.status="ok"){
                    var like_count = parseInt($(ele).attr("like_count"));
                    if(response.msg=='liked'){
                        // 已赞
                        alert("已赞");
                        like_count++;
                        $(ele).text("已赞("+like_count+")");
                    }else if(response.msg=='unliked'){
                        // 已取消赞
                        alert("已取消赞");
                        like_count--;
                        $(ele).text("赞("+like_count+")");
                    }
                    $(ele).attr("like_count", like_count);
                }
            }
        });
    }
    
    /* 获取指定帖子的评论 */
    function get_comments(post_id) {
        var comments;
        $.get({
            url:"/app01/get_comments/",
            data:{"post": post_id},
            dataType: "json",
            async: false,
            success:function (response) {
                if(response.status=='ok'){
                    comments = response['data'];
                }
            }
        });
        return comments;
    }
    
    /* 展示该帖子的所有评论 */
    function show_comments(ele, post_id) {
        // 先隐藏所有帖子的评论div,然后展示用户点击的帖子的评论div
        $("div.comment_container").addClass("hide");
        var current_comment_container = $(ele).parent().parent().parent().siblings(".comment_container").removeClass("hide");
    
        // 插入一个textarea
        var comment_text_container = current_comment_container.children(".comment_text_container");
        //console.log(comment_text_container);
        comment_text_container.children().remove();
        var comment_text = document.createElement('textarea');
        comment_text.className = "comment_text";
        comment_text_container.append(comment_text);
    
        var send_btn = document.createElement('a');
        send_btn.className="send_btn";
        send_btn.innerText = "发送";
        send_btn.href = "javascript:void(0)";
        send_btn.setAttribute("onclick", "post_comment(this,"+post_id+")");
        comment_text_container.append(send_btn);
    
        // 获取这个帖子的所有评论
        var posts = get_comments(post_id);
        var comment_content_container = current_comment_container.find(".comment_content_container")[0];
        build_comment_tree(posts,comment_content_container);
    }
    
    /* 创建评论的HTML */
    function build_comment_tree(posts, comment_content_container) {
        if(posts.length>0){
            // 先进行清理工作
    
            $(comment_content_container).text("").children().remove();
    
            // 添加一个根ul
            var root_ul = document.createElement('ul');
            comment_content_container.appendChild(root_ul);
    
            // 循环每个帖子
            for(var key in posts){
                // 生成一个li节点,带comment_id,该li中也带一个ul用于存放子评论
                var li = document.createElement('li');
                li.setAttribute("comment_id", posts[key]['id']);
                li.setAttribute("display_name", posts[key]['user__display_name']);
                li.setAttribute("user_id", posts[key]['user_id']);
    
                // li的内容
                var comment_content_div = document.createElement('div'); // 评论的具体内容
                comment_content_div.className="comment_content_div";
                comment_content_div.setAttribute("onmouseover","show_reply_btn(this,true)");
                comment_content_div.setAttribute("onmouseout","show_reply_btn(this,false)");
                var display_name = posts[key]['user__display_name']==$("div.user_info #display_name").text() ? "我" : posts[key]['user__display_name'];
                comment_content_div.innerText = display_name +
                    ": " +
                    posts[key]['content']+
                    "  "+
                    posts[key]['create_on'];
    
                var comment_bar = document.createElement('div');    // 针对该评论的工具栏
                var reply_a = document.createElement('a');
                reply_a.className="reply_btn hide";
                reply_a.innerText = "回复";
                reply_a.href = "javascript:void(0);";
                reply_a.setAttribute("onclick", "reply("+posts[key]['id']+",this)");
                //comment_bar.appendChild(reply_a);
                comment_content_div.innerHTML += reply_a.outerHTML;
    
                var comment_row = document.createElement('div');    // 一条评论的div,包括了以上两个div
                comment_row.className="comment_row";
                comment_row.appendChild(comment_content_div);
                comment_row.appendChild(comment_bar);
    
                li.appendChild(comment_row);    // 将整条评论+工具添加到li中
    
                // 用于存放子评论的ul,下方可以没有任何子评论
                var sub_ul = document.createElement('ul');
                li.appendChild(sub_ul);
    
                if(posts[key]['reply_to']){
                    // 评论有reply_to
                    $(comment_content_container).find("li[comment_id="+posts[key]['reply_to']+"]").children("ul").append(li);
                }else {
                    // 评论没有reply_to,将li加到根部的ul
                    root_ul.appendChild(li);
                }
            }
    
        }else{
            $(comment_content_container).text("暂时还没有评论");
        }
    }
    
    /**/
    function show_reply_btn(ele,show) {
        show?$(ele).find(".reply_btn:first").removeClass("hide"):$(ele).find(".reply_btn:first").addClass("hide")
    }
    
    /* 提交评论的内容 */
    function post_comment(ele, post_id) {
        var comment_obj = {};
        comment_obj['post']=post_id;
        var ta = $(ele).siblings('textarea');
        comment_obj['comment_text'] = $.trim(ta.val());
        if(comment_obj['comment_text'].length==0){
            alert("请输入评论内容再提交");
            return false;
        }
        var reply_to = $(ele).siblings('textarea').attr("reply_to");
        if(reply_to){
            comment_obj['reply_to'] = reply_to
        }
    
        // ajax上传评论
        $.post({
            url:"/app01/post_comment/",
            data:comment_obj,
            dataType:"json",
            success:function (response) {
                if(response.status=='ok'){
                    // 评论成功
                    alert("评论成功");
                    var show_comments_btn = $(ele).parent().parent().parent().find('.show_comments_btn')[0];
                    show_comments(show_comments_btn, post_id)
                }
            }
        });
    }
    
    //点击某个评论的回复按钮后,修改textarea的comment_id属性并让其得到焦点
    function reply(comment_id, ele) {
        if(!is_login()){
            show_login_reg_frm();
            return false;
        }
        var reply_to_user = $(ele).parent().parent().parent().attr("display_name");
        $("textarea.comment_text").val("").attr("reply_to",comment_id).attr("placeholder","回复 "+reply_to_user).focus();
    }
    part4: 创建和提交、层级评论
  • 相关阅读:
    java基本数据类型及运算的注意事项
    B-Tree 和 B+Tree 结构及应用,InnoDB 引擎, MyISAM 引擎
    软件工程与软件开发模型、软件开发方法
    2020年3月份Unity3D游戏源码合集-免费下载
    独立游戏开发必备!8个效果不错的Unity3D 免费模型资源包
    2019年4月份整理的Unity3D 20个实用插件-免费下载
    2019年4月份整理的Unity3D游戏完整源码
    2019年3月整理的2D美术资源合集
    画面效果都不错!20个精品Unity3D着色器插件
    Unity3D中UnityPlayerActivity与UnityPlayerNativeActivity有什么区别
  • 原文地址:https://www.cnblogs.com/xiaonq/p/8213735.html
Copyright © 2011-2022 走看看