目錄:抽屜項目之js最佳實踐
目錄:
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>

<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>

/* 顯示登錄、注冊頁面 */ 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"); } }

# 注銷 def logout(request): request.session['is_login'] = False request.session['current_user'] = {} return HttpResponse(json.dumps({'status': 'ok'}))
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>

/* 提交用戶注冊信息 */ 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(); // 無論結果如何,都刷新驗證碼 }

# 用戶注冊 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())
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>

/* 檢查用戶名和郵箱是否已注冊 */ 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); } }); } }

# 用戶注冊時,檢查提交的數據是否占用 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'}))
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>

/* 檢查兩次密碼是否一致 */ 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("√"); } }
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>

/* 創建驗證碼圖片標簽 */ 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 += '?'; }

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')

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
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>

/* 登錄 */ 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"); }

# 登陸 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))
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); } } } }); } }

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 }))
附加: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"); }

// 第二部分:實現發布帖子功能 /* 展示發布框 */ 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); } } } }); } }

// 第三部分:將帖子展示到頁面,點贊 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); } } }

// 第四部分:創建和提交、層級評論 /* 點贊 */ 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(); }