日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

大事件后台管理系统开发实战(下)

發布時間:2024/9/27 windows 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大事件后台管理系统开发实战(下) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 續前篇:大事件后臺管理系統開發實戰(中)
  • 1. 文章類別
    • 1.1 點擊編輯按鈕展示修改文章分類的彈出層
    • 1.2 為修改文章分類的彈出層填充表單數據
    • 1.3 更新文章分類的數據
    • 1.4 刪除文章分類
  • 2. 文章列表
    • 2.1 創建文章列表頁面
    • 2.2 定義查詢參數對象q
    • 2.3 請求文章列表數據并使用模板引擎渲染列表結構
    • 2.3.1 定義獲取文章列表數據
    • 2.4 定義美化時間格式的過濾器
    • 2.5 繪制篩選區域的UI結構
    • 2.6 發起請求獲取并渲染文章分類的下拉選擇框
    • 2.7 實現篩選的功能
  • 3. 分頁
    • 3.1 定義渲染分頁的 renderPage 方法
    • 3.2 調用 laypage.render 方法渲染分頁的基本結構
    • 3.3 在jump回調函數中通過obj.curr獲取到最新的頁碼值
    • 3.4 解決 jump 回調函數發生死循環的問題
    • 3.5 自定義分頁的功能項
    • 3.6 實現切換每頁展示多少條數據的功能
  • 4. 刪除文章
    • 4.1 實現刪除文章的功能
    • 4.2 解決刪除文章時的小 Bug
  • 5. 發布文章
    • 5.1 創建文章發布頁面的基本結構
    • 5.2 新建基本的表單結構
    • 5.3 渲染文章類別對應的下拉選擇框結構
    • 5.4 渲染富文本編輯器
    • 5.5 渲染封面裁剪區域
    • 5.6 渲染提交按鈕區域
    • 5.7 點擊選擇封面按鈕打開文件選擇框
    • 5.8 將選擇的圖片設置到裁剪區域中
    • 小結 - 渲染封面裁剪區域
    • 5.9 分析發布文章的實現步驟
    • 5.10 基于Form表單快速創建FormData對象
    • 5.11 將裁剪后的封面追加到FormData對象中
    • 5.12 發起Ajax請求實現發布文章的功能
  • 6. 編輯文章
    • 6.1 創建文章編輯頁面基本結構
    • 6.2 給編輯按鈕添加點擊事件
    • 6.3 新建基本的表單結構
    • 6.4 文章類別對應的下拉選擇框結構
    • 6.5 渲染富文本編輯器
    • 6.6 封面裁剪區域結構
    • 6.7 提交按鈕區域
    • 6.8 通過 URLSearchParams 對象,獲取 URL 傳遞的參數
    • 6.9 發起請求獲取文章詳情
    • 6.10 選擇文章封面
    • 6.11 監聽文件(文章封面圖片)選擇框的 change 事件
    • 6.12 設置文章的發布狀態
    • 6.13 發布文章
    • 6.14 完整html結構
    • 6.15 完整css 樣式代碼
    • 6.16 編輯功能完整 JS 代碼
  • 7. 將開發完成的項目代碼推送到GitHub


續前篇:大事件后臺管理系統開發實戰(中)

1. 文章類別

1.1 點擊編輯按鈕展示修改文章分類的彈出層

  • 為編輯按鈕添加 btn-edit 類名如下:

    <button type="button" class="layui-btn layui-btn-xs btn-edit" data-id="{{$value.Id}}">編輯</button>
  • 定義 修改分類 的彈出層:

    <script type="text/html" id="dialog-edit"><form class="layui-form" id="form-edit" lay-filter="form-edit"><!-- 隱藏域,保存 Id 的值 --><input type="hidden" name="Id"><div class="layui-form-item"><label class="layui-form-label">分類名稱</label><div class="layui-input-block"><input type="text" name="name" required lay-verify="required" placeholder="請輸入分類名稱" autocomplete="off" class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">分類別名</label><div class="layui-input-block"><input type="text" name="alias" required lay-verify="required" placeholder="請輸入分類別名" autocomplete="off" class="layui-input"></div></div><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="formDemo">確認修改</button></div></div></form> </script>
  • 快速為一個表單填充數據:先為form表單添加 lay-filter 屬性,再調用form方法(前提是要先導入form:var form=layui.form)。同時,為表單創建一個隱藏域(input)用于保存id值
    3. 通過 代理 的形式,為 btn-edit 按鈕綁定點擊事件:

    var indexEdit = null$('tbody').on('click', '.btn-edit', function() {// 彈出一個修改文章分類信息的層indexEdit = layer.open({type: 1,area: ['500px', '250px'],title: '修改文章分類',content: $('#dialog-edit').html()})})

    1.2 為修改文章分類的彈出層填充表單數據

  • 為編輯按鈕綁定 data-id 自定義屬性:

    <button type="button" class="layui-btn layui-btn-xs btn-edit" data-id="{{$value.Id}}">編輯</button>
  • 在展示彈出層之后,根據 id 的值發起請求獲取文章分類的數據,并填充到表單中:

    var id = $(this).attr('data-id') // 發起請求獲取對應分類的數據 $.ajax({method: 'GET',url: '/my/article/cates/' + id,success: function(res) {form.val('form-edit', res.data)} })
  • 1.3 更新文章分類的數據

  • 通過代理的形式,為修改分類的表單綁定 submit 事件:

    $('body').on('submit', '#form-edit', function(e) {e.preventDefault()$.ajax({method: 'POST',url: '/my/article/updatecate',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('更新分類數據失敗!')}layer.msg('更新分類數據成功!')layer.close(indexEdit)initArtCateList()}}) })
  • 1.4 刪除文章分類

  • 為刪除按鈕綁定 btn-delete 類名,并添加 data-id 自定義屬性:

    <button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.Id}}">刪除</button>
  • 通過代理的形式,為刪除按鈕綁定點擊事件:

    $('tbody').on('click', '.btn-delete', function() {var id = $(this).attr('data-id') // 獲取 id 的值// 提示用戶是否要刪除layer.confirm('確認刪除?', { icon: 3, title: '提示' }, function(index) {$.ajax({method: 'GET',url: '/my/article/deletecate/' + id,success: function(res) {if (res.status !== 0) {return layer.msg('刪除分類失敗!')}layer.msg('刪除分類成功!')layer.close(index)initArtCateList()}})}) })
  • 2. 文章列表

    共分為3個區域,依卡片面板上的布局設計,從上到下依次是:

    • 篩選區域;
    • 列表區域;
    • 分頁區域。

    2.1 創建文章列表頁面

    首先,繪制卡片區域,打開layui官網,復制卡片面板的HTML結構代碼

  • 新建 /article/art_list.html 頁面結構如下:

    <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/article/art_list.css" /></head><body><!-- 卡片區域 --><div class="layui-card"><div class="layui-card-header">文章列表</div><div class="layui-card-body"></div></div><!-- 導入第三方的 JS 插件 --><script src="/assets/lib/layui/layui.all.js"></script><script src="/assets/lib/jquery.js"></script><script src="/assets/js/baseAPI.js"></script><!-- 導入自己的 JS 腳本 --><script src="/assets/js/article/art_list.js"></script></body> </html>
  • 新建 /assets/css/article/art_list.css 樣式表如下:

    html, body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }
  • 新建 /assets/js/article/art_list.js 腳本文件。

  • 2.2 定義查詢參數對象q

  • 定義一個查詢的參數對象如下:

    // 定義一個查詢的參數對象,將來請求數據的時候,// 需要將請求參數對象提交到服務器var q = {pagenum: 1, // 頁碼值,默認請求第一頁的數據pagesize: 2, // 每頁顯示幾條數據,默認每頁顯示2條cate_id: '', // 文章分類的 Idstate: '' // 文章的發布狀態}
  • 2.3 請求文章列表數據并使用模板引擎渲染列表結構

    API 接口如圖(注意,請求時需攜帶 4 個 參數):




    2.3.1 定義獲取文章列表數據

    1)定義查詢的參數對象q, 將來請求數據時,需要將請求參數對象提交到服務器。

    var q = {pagenum: 1, // 默認值,默認請求第一頁的數據 pagesize: 2, // 每頁顯示幾條數據cate_id: '', // 文章分類的id,默認為空state: '' // 文章的發布狀態}

    2)定義一個獲取文章列表數據的方法(自定義函數)
    注: 要先導入模板引擎

    initTable() // 獲取文章列表數據的方法 function initTable() {$.ajax({method: 'GET',url: '/my/article/list',data: q,success: function(res) {if (res.status !== 0) {return layer.msg('獲取文章列表失敗!')}// 使用模板引擎渲染頁面的數據var htmlStr = template('tpl-table', res)$('tbody').html(htmlStr)}}) }
  • 在頁面中添加表格結構如下:
    在layui官網找到 【頁面元素】?\Rightarrow?【表格】?\Rightarrow?【常規用法】,復制html結構到代碼編輯器中。

  • 修改后的表格結構如下:

    <!-- 列表區域 --> <table class="layui-table"><colgroup><col /><col width="150" /><col width="180" /><col width="150" /><col width="150" /></colgroup><thead><tr><th>文章標題</th><th>分類</th><th>發表時間</th><th>狀態</th><th>操作</th></tr></thead><tbody></tbody> </table>
  • 定義列表數據的模板結構:

    <script type="text/html" id="tpl-table">{{each data}}<tr><td>{{$value.title}}</td><td>{{$value.cate_name}}</td><td>{{$value.pub_date|dataFormat}}</td><td>{{$value.state}}</td><td><button type="button" class="layui-btn layui-btn-xs">編輯</button><button type="button" class="layui-btn layui-btn-danger layui-btn-xs">刪除</button></td></tr>{{/each}} </script>
  • 2.4 定義美化時間格式的過濾器

  • 通過 template.defaults.imports 定義過濾器(此屬性模板引擎獨有,需先導入模板引擎):

    // 定義美化時間的過濾器template.defaults.imports.dataFormat = function(date) {const dt = new Date(date)var y = dt.getFullYear()var m = padZero(dt.getMonth() + 1)var d = padZero(dt.getDate())var hh = padZero(dt.getHours())var mm = padZero(dt.getMinutes())var ss = padZero(dt.getSeconds())return y + '-' + m + '-' + d + ' ' + hh + ':' + mm + ':' + ss}// 定義補零的函數function padZero(n) {return n > 9 ? n : '0' + n}
  • 在模板引擎中使用過濾器:

    <td>{{$value.pub_date|dataFormat}}</td>
  • 2.5 繪制篩選區域的UI結構

  • 繪制 UI 結構:

    <!-- 篩選區域 --> <form class="layui-form" id="form-search"><div class="layui-form-item layui-inline"><select name="cate_id"></select></div><div class="layui-form-item layui-inline"><select name="state"><option value="">所有狀態</option><option value="已發布">已發布</option><option value="草稿">草稿</option></select></div><div class="layui-form-item layui-inline"><button class="layui-btn" lay-submit lay-filter="formDemo">篩選</button></div> </form>
  • 2.6 發起請求獲取并渲染文章分類的下拉選擇框

  • 定義 initCate 函數請求文章分類的列表數據:

    initCate()// 初始化文章分類的方法function initCate() {$.ajax({method: 'GET',url: '/my/article/cates',success: function(res) {if (res.status !== 0) {return layer.msg('獲取分類數據失敗!')}// 調用模板引擎渲染分類的可選項var htmlStr = template('tpl-cate', res)$('[name=cate_id]').html(htmlStr)// 通過 layui 重新渲染表單區域的UI結構form.render()}})}
  • 定義分類可選項的模板結構:

    <script type="text/html" id="tpl-cate"><option value="">所有分類</option>{{each data}}<option value="{{$value.Id}}">{{$value.name}}</option>{{/each}} </script>
  • 2.7 實現篩選的功能

  • 為篩選表單綁定 submit 事件:

    $('#form-search').on('submit', function(e) {e.preventDefault()// 獲取表單中選中項的值var cate_id = $('[name=cate_id]').val()var state = $('[name=state]').val()// 為查詢參數對象 q 中對應的屬性賦值q.cate_id = cate_idq.state = state// 根據最新的篩選條件,重新渲染表格的數據initTable() })
  • 3. 分頁

    在 layui 官方文檔中找到 【內置模塊?\Rightarrow?分頁】,



    1)在自己 vs code 中 art_list.html 分頁區域的位置 ,添加一個 id 名為 pageBox 的 div 容器,用于存放分頁組件

    2)初始化分頁區:從 layui 中導入 laypage 對象,即復制上圖上的代碼 var laypage=layui.laypage,并在 art_list.js 頭部導入此句代碼。

    3)js 中調用 laypage.render 方法渲染分頁的結構。注意要傳入 4 個參數

    參數選項說明類型默認值
    elem指向存放分頁的容器,值可以是容器ID、DOM對象。如:
    1. elem: ‘id’ 注意:這里不能加 # 號
    2. elem: document.getElementById(‘id’)
    String/Object-
    count數據總數。一般通過服務端得到Number-
    limit每頁顯示的條數。laypage將會借助 count 和 limit 計算出分頁數。Number10
    curr起始頁。一般用于刷新類型的跳頁以及HASH跳頁。Number1
    // 導入 laypage 對象 var laypage = layui.laypage; // 渲染底部分分頁區域的方法function renderPage(total) {laypage.render({elem: 'pageBox', //分頁容器 Idcount: total, // 分頁條數limit: q.pagesize, // 每頁顯示幾條數據curr: q.pagenum // 指定默認選中哪一頁})}

    保存并刷新網頁后,效果如下:



    3.1 定義渲染分頁的 renderPage 方法

  • 定義渲染分頁的方法:

    function renderPage(total) {console.log(total) }
  • 在 initTable 中調用 renderPage 方法:

    function initTable() {$.ajax({method: 'GET',url: '/my/article/list',data: q,success: function(res) {if (res.status !== 0) {return layer.msg('獲取文章列表失敗!')}// 使用模板引擎渲染頁面的數據var htmlStr = template('tpl-table', res)$('tbody').html(htmlStr)// 調用渲染分頁的方法renderPage(res.total)}}) }
  • 3.2 調用 laypage.render 方法渲染分頁的基本結構

  • 在頁面中定義分頁的區域:

    <!-- 分頁區域 --> <div id="pageBox"></div>
  • 調用 laypage.render() 方法來渲染分頁的結構:

    // 定義渲染分頁的方法 function renderPage(total) {// 調用 laypage.render() 方法來渲染分頁的結構laypage.render({elem: 'pageBox', // 分頁容器的 Idcount: total, // 總數據條數limit: q.pagesize, // 每頁顯示幾條數據curr: q.pagenum // 設置默認被選中的分頁}) }
  • 3.3 在jump回調函數中通過obj.curr獲取到最新的頁碼值

    // 定義渲染分頁的方法 function renderPage(total) {// 調用 laypage.render() 方法來渲染分頁的結構laypage.render({elem: 'pageBox', // 分頁容器的 Idcount: total, // 總數據條數limit: q.pagesize, // 每頁顯示幾條數據curr: q.pagenum, // 設置默認被選中的分頁// 分頁發生切換的時候,觸發 jump 回調jump: function(obj) {console.log(obj.curr)// 把最新的頁碼值,賦值到 q 這個查詢參數對象中q.pagenum = obj.curr}}) }

    3.4 解決 jump 回調函數發生死循環的問題

    分頁里面有個 jump 回調函數(包括兩個參數,obj和first),通過這個回調就可以拿到當前的頁碼值。只要點擊頁碼或者調用了 laypage.render() 方法,就會觸發 jump 回調。

    jump 中,能監聽到分頁切換事件

    // 定義渲染分頁的方法function renderPage(total) {// 調用 laypage.render() 方法來渲染分頁的結構laypage.render({elem: 'pageBox', // 分頁容器的 Idcount: total, // 總數據條數limit: q.pagesize, // 每頁顯示幾條數據curr: q.pagenum, // 設置默認被選中的分頁// 分頁發生切換的時候,觸發 jump 回調// 觸發 jump 回調的方式有兩種:// 1. 點擊頁碼的時候,會觸發 jump 回調// 2. 只要調用了 laypage.render() 方法,就會觸發 jump 回調jump: function(obj, first) {// 可以通過 first 的值,來判斷是通過哪種方式,觸發的 jump 回調// 如果 first 的值為 true,證明是方式2觸發的// 否則就是方式1觸發的console.log(first)console.log(obj.curr)// 把最新的頁碼值,賦值到 q 這個查詢參數對象中q.pagenum = obj.curr// 根據最新的 q 獲取對應的數據列表,并渲染表格// initTable() // 不能直接在這里調用,會形成死循環。if (!first) {initTable()}}})}

    3.5 自定義分頁的功能項

    // 定義渲染分頁的方法 function renderPage(total) {// 調用 laypage.render() 方法來渲染分頁的結構laypage.render({elem: 'pageBox', // 分頁容器的 Idcount: total, // 總數據條數limit: q.pagesize, // 每頁顯示幾條數據curr: q.pagenum, // 設置默認被選中的分頁layout: ['count', 'limit', 'prev', 'page', 'next', 'skip'],limits: [2, 3, 5, 10],// 分頁發生切換的時候,觸發 jump 回調// 觸發 jump 回調的方式有兩種:// 1. 點擊頁碼的時候,會觸發 jump 回調// 2. 只要調用了 laypage.render() 方法,就會觸發 jump 回調jump: function(obj, first) {// 可以通過 first 的值,來判斷是通過哪種方式,觸發的 jump 回調// 如果 first 的值為 true,證明是方式2觸發的// 否則就是方式1觸發的console.log(first)console.log(obj.curr)// 把最新的頁碼值,賦值到 q 這個查詢參數對象中q.pagenum = obj.curr// 根據最新的 q 獲取對應的數據列表,并渲染表格// initTable()if (!first) {initTable()}}}) }

    3.6 實現切換每頁展示多少條數據的功能

    // 定義渲染分頁的方法 function renderPage(total) {// 調用 laypage.render() 方法來渲染分頁的結構laypage.render({elem: 'pageBox', // 分頁容器的 Idcount: total, // 總數據條數limit: q.pagesize, // 每頁顯示幾條數據curr: q.pagenum, // 設置默認被選中的分頁layout: ['count', 'limit', 'prev', 'page', 'next', 'skip'],limits: [2, 3, 5, 10],// 分頁發生切換的時候,觸發 jump 回調// 觸發 jump 回調的方式有兩種:// 1. 點擊頁碼的時候,會觸發 jump 回調// 2. 只要調用了 laypage.render() 方法,就會觸發 jump 回調jump: function(obj, first) {// 可以通過 first 的值,來判斷是通過哪種方式,觸發的 jump 回調// 如果 first 的值為 true,證明是方式2觸發的// 否則就是方式1觸發的console.log(first)console.log(obj.curr)// 把最新的頁碼值,賦值到 q 這個查詢參數對象中q.pagenum = obj.curr// 把最新的條目數,賦值到 q 這個查詢參數對象的 pagesize 屬性中q.pagesize = obj.limit// 根據最新的 q 獲取對應的數據列表,并渲染表格// initTable()if (!first) {initTable()}}}) }

    4. 刪除文章

    4.1 實現刪除文章的功能

  • 為刪除按鈕綁定 btn-delete 類名和 添加data-id 自定義屬性:

    <button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.Id}}">刪除</button>
  • 通過代理的形式,為刪除按鈕綁定點擊事件處理函數:

    $('tbody').on('click', '.btn-delete', function() {// 獲取到文章的 idvar id = $(this).attr('data-id') // 這句一定要放在詢問提示框之前,否則會刪除失敗!// 詢問用戶是否要刪除數據layer.confirm('確認刪除?', { icon: 3, title: '提示' }, function(index) {$.ajax({method: 'GET',url: '/my/article/delete/' + id,success: function(res) {if (res.status !== 0) {return layer.msg('刪除文章失敗!')}layer.msg('刪除文章成功!')initTable()}})layer.close(index)}) })
  • 4.2 解決刪除文章時的小 Bug

    $('tbody').on('click', '.btn-delete', function() {// 獲取刪除按鈕的個數var len = $('.btn-delete').length// 獲取到文章的 idvar id = $(this).attr('data-id')// 詢問用戶是否要刪除數據layer.confirm('確認刪除?', { icon: 3, title: '提示' }, function(index) {$.ajax({method: 'GET',url: '/my/article/delete/' + id,success: function(res) {if (res.status !== 0) {return layer.msg('刪除文章失敗!')}layer.msg('刪除文章成功!')// 當數據刪除完成后,需要判斷當前這一頁中,是否還有剩余的數據// 如果沒有剩余的數據了,則讓頁碼值 -1 之后,// 再重新調用 initTable 方法// 4if (len === 1) {// 如果 len 的值等于1,證明刪除完畢之后,頁面上就沒有任何數據了// 頁碼值最小必須是 1q.pagenum = q.pagenum === 1 ? 1 : q.pagenum - 1}initTable()}})layer.close(index)}) })

    5. 發布文章

    5.1 創建文章發布頁面的基本結構

  • 新建 /article/art_pub.html 頁面結構如下:

    <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/article/art_pub.css" /></head><body><!-- 卡片區域 --><div class="layui-card"><div class="layui-card-header">寫文章</div><div class="layui-card-body">卡片式面板面板通常用于非白色背景色的主體內<br />從而映襯出邊框投影</div></div><!-- 導入第三方的 JS 插件 --><script src="/assets/lib/layui/layui.all.js"></script><script src="/assets/lib/jquery.js"></script><script src="/assets/js/baseAPI.js"></script><!-- 導入自己的 JS --><script src="/assets/js/article/art_pub.js"></script></body> </html>
  • 新建 /assets/css/article/art_pub.css 樣式文件如下:

    html, body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }
  • 新建 /assets/js/article/art_pub.js 腳本文件如下:

    $(function() { })
  • 5.2 新建基本的表單結構

    <!-- 發布文章的表單 --> <form class="layui-form"><div class="layui-form-item"><label class="layui-form-label">文章標題</label><div class="layui-input-block"><input type="text" name="title" required lay-verify="required" placeholder="請輸入標題" autocomplete="off" class="layui-input" /></div></div> </form>

    5.3 渲染文章類別對應的下拉選擇框結構

  • 定義 UI 結構:

    <!-- 第二行 --><div class="layui-form-item"><label class="layui-form-label">文章類別</label><div class="layui-input-block"><select name="cate_id" lay-verify="required"></select></div></div>
  • 導入 art-template:

    <script src="/assets/lib/template-web.js"></script>
  • 定義模板結構:

    <script type="text/html" id="tpl-cate"><option value="">請選擇文章類別</option>{{each data}}<option value="{{$value.Id}}">{{$value.name}}</option>{{/each}} </script>
  • 定義 initCate 方法:

    $(function() {var layer = layui.layervar form = layui.forminitCate()// 定義加載文章分類的方法function initCate() {$.ajax({method: 'GET',url: '/my/article/cates',success: function(res) {if (res.status !== 0) {return layer.msg('初始化文章分類失敗!')}// 調用模板引擎,渲染分類的下拉菜單var htmlStr = template('tpl-cate', res)$('[name=cate_id]').html(htmlStr)// 一定要記得調用 form.render() 方法 // 由于layui不知道動態生成了分類form.render()}})} })

  • 5.4 渲染富文本編輯器

    參考我的另一篇文章: 基于 Layui 的富文本編輯器和封面圖片剪裁的實現方案

    與編輯器 & 圖片裁剪實現方案相關的素材文件:
    網盤下載鏈接:https://pan.baidu.com/s/1k9IBXKKQfD7pf9a6NNyQkQ

    提取碼:qw6o

    5.5 渲染封面裁剪區域

    參考 基于 Layui 的富文本編輯器和封面圖片剪裁的實現方案


    5.6 渲染提交按鈕區域

    <!-- 第五行 --><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit>發布</button><button class="layui-btn layui-btn-primary" lay-submit>存為草稿</button></div></div>

    5.7 點擊選擇封面按鈕打開文件選擇框

  • 修改 UI 結構,為 選擇封面 按鈕添加 id,并且在按鈕后面添加 文件選擇框:

    <!-- 選擇封面按鈕 --> <button type="button" class="layui-btn layui-btn-danger" id="btnChooseImage">選擇封面</button> <!-- 隱藏的文件選擇框 --> <input type="file" id="coverFile" style="display: none;" accept="image/png,image/jpeg,image/gif" />
  • 為選擇封面的按鈕,綁定點擊事件處理函數:

    $('#btnChooseImage').on('click', function() {$('#coverFile').click() })

  • 5.8 將選擇的圖片設置到裁剪區域中

  • 監聽 coverFile 的 change 事件,獲取用戶選擇的文件列表:

    // 監聽 coverFile 的 change 事件,獲取用戶選擇的文件列表$('#coverFile').on('change', function(e) {// 獲取到文件的列表數組var files = e.target.files// 判斷用戶是否選擇了文件if (files.length === 0) {return}// 根據文件,創建對應的 URL 地址var newImgURL = URL.createObjectURL(files[0])// 為裁剪區域重新設置圖片$image.cropper('destroy') // 銷毀舊的裁剪區域.attr('src', newImgURL) // 重新設置圖片路徑.cropper(options) // 重新初始化裁剪區域})

  • 小結 - 渲染封面裁剪區域

    第一步:為文件選擇框綁定 change 事件;

    第二步:在事件對象 e 中,獲取到用戶選擇的文件列表files;

    第三步:判斷用戶是否選擇了文件,如果沒有選擇文件,就直接return出去,不再執行后面代碼;

    第四步:用戶選擇了文件,我們需要將文件創建為對應的新的url地址;

    第五步:重新為裁剪區域設置圖片。

    5.9 分析發布文章的實現步驟

    API 接口如圖所示:



  • 為 存為草稿 按鈕添加 id 屬性:

    <button class="layui-btn layui-btn-primary" lay-submit id="btnSave2">存為草稿</button>
  • 定義文章的發布狀態:

    var art_state = '已發布'
  • 為存為草稿按鈕,綁定點擊事件處理函數:

    $('#btnSave2').on('click', function() {art_state = '草稿' })

  • 5.10 基于Form表單快速創建FormData對象

  • 為發布文章的 Form 表單添加 id 屬性:

    <form class="layui-form" id="form-pub"></form>
  • 為表單綁定 submit 提交事件:

    $('#form-pub').on('submit', function(e) {// 1. 阻止表單的默認提交行為e.preventDefault()// 2. 基于 form 表單,快速創建一個 FormData 對象var fd = new FormData($(this)[0])// 3. 將文章的發布狀態,追加到 fd 中fd.append('state', art_state)})
  • 快速創建 FormData 對象:new FormData($(this)[0])

    代碼注釋:
    在 new FormData 期間,通過把 jQuery 對象 $(this)以[0]的形式轉換為一個原生的 DOM 對象,然后把這個 DOM 對象傳遞給new FormData(),就能夠創建出一個 FormData 對象。

    為了證實這個fd 對象中確實存了一些數據,我們可以用forEach將 FormData 中存儲的每一個鍵循環打印到控制臺查看,方法如下:

    // 測試創建 FormData 是否成功 fd.forEach(function(v, k) { // 用v 接收FormData中存的值,k 接收鍵console.log(k, v); })

    提交事件觸發后,控制臺打印如下:




    5.11 將裁剪后的封面追加到FormData對象中

    這里仍然參照文章 基于 Layui 的富文本編輯器和封面圖片剪裁的實現方案 一文中 “4. 將裁剪后的圖片,輸出為文件” 的代碼。

    代碼如圖:




    // 為表單綁定 submit 提交事件$('#form-pub').on('submit', function(e) {// 1. 阻止表單的默認提交行為e.preventDefault()// 2. 基于 form 表單,快速創建一個 FormData 對象var fd = new FormData($(this)[0])// 3. 將文章的發布狀態,存到 fd 中fd.append('state', art_state)// 4. 將封面裁剪過后的圖片,輸出為一個文件對象$image.cropper('getCroppedCanvas', {// 創建一個 Canvas 畫布width: 400,height: 280}).toBlob(function(blob) {// 將 Canvas 畫布上的內容,轉化為文件對象// 得到文件對象后,進行后續的操作// 5. 將文件對象,存儲到 fd 中fd.append('cover_img', blob)// 6. 發起 ajax 數據請求})})

    只要調用了toBlob,就能將裁剪之后的圖片輸出為文件了,.toBlob(function(blob)中的blob就是圖片文件。再將 blob存到 FormData(也就是fd) 里。

    5.12 發起Ajax請求實現發布文章的功能

  • 定義一個發布文章的方法:

    function publishArticle(fd) {$.ajax({method: 'POST',url: '/my/article/add',data: fd,// 注意:如果向服務器提交的是 FormData 格式的數據,// 必須添加以下兩個配置項contentType: false,processData: false,success: function(res) {if (res.status !== 0) {return layer.msg('發布文章失敗!')}layer.msg('發布文章成功!')// 發布文章成功后,跳轉到文章列表頁面location.href = '/article/art_list.html'}}) }
  • 注意:
    如果向服務器提交的是 FormData 格式的數據,必須添加以下兩個配置項
    contentType: false,
    processData: false,
    否則,請求就會失敗。

  • 把裁剪的圖片追加到 FormData 對象中之后,調用 publishArticle 方法:

    // 為表單綁定 submit 提交事件 $('#form-pub').on('submit', function(e) {// 1. 阻止表單的默認提交行為e.preventDefault()// 2. 基于 form 表單,快速創建一個 FormData 對象var fd = new FormData($(this)[0])// 3. 將文章的發布狀態,存到 fd 中fd.append('state', art_state)// 4. 將封面裁剪過后的圖片,輸出為一個文件對象$image.cropper('getCroppedCanvas', {// 創建一個 Canvas 畫布width: 400,height: 280}).toBlob(function(blob) {// 將 Canvas 畫布上的內容,轉化為文件對象// 得到文件對象后,進行后續的操作// 5. 將文件對象,存儲到 fd 中fd.append('cover_img', blob)// 6. 發起 ajax 數據請求publishArticle(fd)}) })

  • 6. 編輯文章

    6.1 創建文章編輯頁面基本結構

  • 新建 /article/art_edit.html 頁面結構如下:
  • <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/article/art_pub.css" /></head><body><!-- 卡片區域 --><div class="layui-card"><div class="layui-card-header">寫文章</div><div class="layui-card-body">卡片式面板面板通常用于非白色背景色的主體內<br />從而映襯出邊框投影</div></div><!-- 導入第三方的 JS 插件 --><script src="/assets/lib/layui/layui.all.js"></script><script src="/assets/lib/jquery.js"></script><script src="/assets/js/baseAPI.js"></script><!-- 導入自己的 JS --><script src="/assets/js/article/art_edit.js"></script></body></html>
  • 新建 /assets/css/article/art_edit.css 樣式文件(初始化頁面)如下:
  • html, body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }
  • 新建 /assets/js/article/art_edit.js 腳本文件如下:
  • $(function() { })

    6.2 給編輯按鈕添加點擊事件

  • 修改文章列表的模板引擎
    將/article/art.list.html文件打開,給模板引擎中的“編輯”按鈕添加類名btn_edit、自定義屬性data-index和data-id
  • <button type="button" data-index='{{$value.Id}}' class="layui-btn layui-btn-xs btn-edit" data-id="{{$value.Id}}">編輯</button>
  • 給【編輯】按鈕綁定點擊事件
  • // 給文章編輯按鈕綁定 click 單擊事件$('body').on('click', '.btn-edit', function() {location.href = '/article/art_edit.html?id=' + $(this).attr('data-id')})

    6.3 新建基本的表單結構

    在上一步創建的html結構的卡片區域中,將類名為 layui-card-body 的 div 盒子內的文字替換為如下表單(在Layui官方文檔中復制輸入框html結構),并為form表單添加id="formAddArticle"

    <!-- 修改文章的表單 --> <form class="layui-form" lay-filter="addArticle" id="formAddArticle" enctype="multipart/form-data"><!-- 文章標題 --><div class="layui-form-item"><label class="layui-form-label">文章標題</label><div class="layui-input-block"><input type="text" name="title" required lay-verify="required" placeholder="請輸入標題" autocomplete="off" class="layui-input" /></div></div> </form>

    6.4 文章類別對應的下拉選擇框結構

  • 定義 UI 結構:

    <!-- 文章類別 --><div class="layui-form-item"><label class="layui-form-label">文章類別</label><div class="layui-input-block" id="art_cate"></div></div>
  • 導入 art-template:
    在html文件底部,在導入的 layui.js 后面導入template 模板引擎腳本文件。

    <script src="/assets/lib/template-web.js"></script>
  • 定義文章分類列表模板結構:
    給模板結構添加 id屬性:id="selectArtCates",方便后續渲染。

    <!-- 文章分類列表的模板 --><script type="text/html" id="selectArtCates"><select name="cate_id" lay-verify="required"><option value="">請選擇文章類別</option>{{each data}}<option value="{{$value.Id}}">{{$value.name}}</option>{{/each}}</select></script>
  • 定義 renderArticleCates 方法,渲染文章分類列表:

    $(function() {// 獲取需要的 layui 對象var form = layui.form// 1. 渲染文章分類列表renderArticleCates()function renderArticleCates() {$.get('/my/article/cates', function(res) {if (res.status !== 0) {return layer.msg('獲取文章分類列表失敗!')}var htmlStr = template('selectArtCates', res)$('#art_cate').html(htmlStr)// 一定要記得調用 form.render() 方法 // 由于layui不知道動態生成了分類form.render()getArticleById()})}

  • 6.5 渲染富文本編輯器

    參考 基于 Layui 的富文本編輯器和封面圖片剪裁的實現方案 完成。


    6.6 封面裁剪區域結構

  • 剪裁區域html
  • <!-- 文章封面 --> <div class="layui-form-item"><label class="layui-form-label">文章封面</label><div class="layui-input-block cropper-container"><!-- 文件選擇框 --><input type="file" id="fileCover" accept="image/jpeg,image/png,image/gif,image/bmp" style="display: none;" /><div class="cropper-box"><img id="image" src=""></div><div class="right-box"><div class="img-preview"></div><button class="layui-btn layui-btn-danger" id="btnChooseCoverImage">選擇封面</button></div></div> </div>
  • art_edit.css 文件中添加剪裁區域 css 樣式
  • .cropper-box {width: 400px;height: 280px; }#image {max-width: 400px;/* 這個設置很重要 */max-height: 280px; }.img-preview {width: 200px;height: 140px;overflow: hidden;margin-bottom: 20px; }.cropper-container {display: flex; }

    6.7 提交按鈕區域

    <!-- 按鈕區域 --> <div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit id="btnPublish">發布</button><button class="layui-btn layui-btn-primary" lay-submit id="btnSave">存為草稿</button></div> </div>

    給表單添加隱藏域,用于獲取用戶選擇的文章的Id。

    <input type="hidden" name="Id" />

    6.8 通過 URLSearchParams 對象,獲取 URL 傳遞的參數

    // 通過 URLSearchParams 對象,獲取 URL 傳遞過來的參數var params = new URLSearchParams(location.search)var artId = params.get('id')// 文章的發布狀態var pubState = ''

    解釋
    首先聲明變量params,并通過URLSearchParams對象賦值,再通過params.get()的方式輸入鍵、拿到值(這里賦值給artId),就很簡單地 拿到了前一個頁面(文章列表頁點擊“編輯”時)傳過來的文章id值。

    Location對象提供以下屬性。

    屬性說明
    Location.href整個 URL
    Location.protocol當前 URL 的協議,包括冒號(:)
    Location.host主機,包括冒號(:)和端口(默認的80端口和443端口會省略)。
    Location.hostname主機名,不包括端口。
    Location.port端口號。
    Location.pathnameURL 的路徑部分,從根路徑/開始。
    Location.search查詢字符串部分,從問號?開始。
    Location.hash片段字符串部分,從#開始。
    Location.username域名前面的用戶名。
    Location.password域名前面的密碼。
    Location.originURL 的協議、主機名和端口。

    更多關于URLSearchParams(location.search),可參考MDN文檔 和后面這篇簡書文章 《JS Location對象,URL對象,URLSearchParams對象》

    6.9 發起請求獲取文章詳情

    根據文章的 Id,獲取文章的詳情,并初始化表單的數據內容:

    function getArticleById() {// 發起請求,獲取文章詳情$.get('/my/article/' + artId, function(res) {// 獲取數據失敗if (res.status !== 0) {return layer.msg('獲取文章失敗!')}// 獲取數據成功var art = res.data// 為 form 表單賦初始值form.val('addArticle', {Id: art.Id,title: art.title,cate_id: art.cate_id,content: art.content})// 手動初始化富文本編輯器initEditor() // cropper插件自帶方法,導入插件即可使用// 初始化圖片裁剪器var $image = $('#image')// 設置圖片路徑$image.attr('src', 'http://ajax.frontend.itheima.net' + art.cover_img)// 裁剪選項var cropperOption = {aspectRatio: 400 / 280,preview: '.img-preview',// 初始化圖片裁剪框的大小autoCropArea: 1}// 初始化裁剪區域$image.cropper(cropperOption)})}

    form.val:攜帶有值就給表單賦值,未攜帶值則獲取表單中的值。

    語法:form.val('filter', object);
    用于給指定表單集合的元素賦值和取值。如果 object 參數存在,則為賦值;如果 object 參數不存在,則為取值。其中「取值」功能為 layui 2.2.5 開始新增

    attr() 方法:設置被選元素(這里是image標簽)的屬性和值。詳情參閱 W3School文檔。

    裁剪選項 var cropperOption={},參見 基于Layui 的富文本編輯器與封面的實現方案


    6.10 選擇文章封面

    // 選擇封面$('#btnChooseCoverImage').on('click', function(e) e.preventDefault() // 阻止默認提交行為$('#fileCover').click()})

    6.11 監聽文件(文章封面圖片)選擇框的 change 事件

    $('#fileCover').on('change', function(e) {var files = e.target.files// 沒有選擇文件if (files.length === 0) {return}// 重新為裁剪區域設置圖片$('#image').cropper('destroy').attr('src', URL.createObjectURL(files[0])).cropper({aspectRatio: 400 / 280,preview: '.img-preview'}) })

    6.12 設置文章的發布狀態

    $('#btnPublish').on('click', function() {pubState = '已發布' }) $('#btnSave').on('click', function() {pubState = '草稿' })

    6.13 發布文章

    綁定【發布】按鈕的submit提交事件,同樣的需參照 基于Layui 的富文本編輯器與封面的實現方案,完成后的代碼如下:

    $('#formAddArticle').on('submit', function(e) {e.preventDefault() // 阻止默認提交事件// 創建一個 Canvas 畫布$('#image').cropper('getCroppedCanvas', {width: 400,height: 280})// 將 Canvas 畫布上的內容,轉化為文件對象.toBlob(function(blob) { // 5.1 組織參數對象 FormDatavar fd = new FormData($('#formAddArticle')[0])// 5.2 添加封面fd.append('cover_img', blob)// 5.3 添加文章的發表狀態fd.append('state', pubState)// 5.4 發起請求$.ajax({method: 'POST',url: '/my/article/edit',data: fd,contentType: false,processData: false,success: function(res) {if (res.status !== 0) {return layer.msg('編輯文章失敗!')}location.href = '/article/art_list.html'}})}) })

    toBlob()方法的語法:canvas.toBlob(callback, type, encoderOptions);
    用以展示canvas上的圖片;這個圖片文件可以被緩存或保存到本地,由用戶代理端自行決定。如不特別指明,圖片的類型默認為 image/png,分辨率為 96dpi。
    第三個參數用于針對image/jpeg格式的圖片進行輸出圖片的質量設置(值在0與1之間)。
    更多詳情請參閱 MDN文檔

    附< 文件在線轉 Base64 地址>: https://www.css-js.com/tools/base64.html

    至此,文章編輯功能的開發已算完成。

    6.14 完整html結構

    <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css"><!-- 富文本樣式 --><link rel="stylesheet" href="/assets/lib/cropper/cropper.css" /><link rel="stylesheet" href="/assets/css/article/art_edit.css"> </head><body><div class="layui-card"><div class="layui-card-header">修改文章</div><div class="layui-card-body"><!-- 修改文章的表單 --><form class="layui-form" lay-filter="addArticle" id="formAddArticle" enctype="multipart/form-data"><!-- 文章標題 --><div class="layui-form-item"><label class="layui-form-label">文章標題</label><div class="layui-input-block"><input type="text" name="title" required lay-verify="required" placeholder="請輸入標題" autocomplete="off" class="layui-input" /></div></div><!-- 文章類別 --><div class="layui-form-item"><label class="layui-form-label">文章類別</label><div class="layui-input-block" id="art_cate"></div></div><!-- 文章內容 --><div class="layui-form-item"><label class="layui-form-label">文章內容</label><div class="layui-input-block" style="height: 400px;"><textarea name="content" id="content"></textarea></div></div><!-- 文章封面 --><div class="layui-form-item"><label class="layui-form-label">文章封面</label><div class="layui-input-block cropper-container"><!-- 文件選擇框 --><input type="file" id="fileCover" accept="image/jpeg,image/png,image/gif,image/bmp" style="display: none;" /><div class="cropper-box"><img id="image" src=""></div><div class="right-box"><div class="img-preview"></div><button class="layui-btn layui-btn-danger" id="btnChooseCoverImage">選擇封面</button></div></div></div><!-- 按鈕區域 --><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit id="btnPublish">發布</button><button class="layui-btn layui-btn-primary" lay-submit id="btnSave">存為草稿</button></div></div><input type="hidden" name="Id" /></form></div></div><!-- 文章分類列表的模板 --><script type="text/html" id="selectArtCates"><select name="cate_id" lay-verify="required"><option value="">請選擇文章類別</option>{{each data}}<option value="{{$value.Id}}">{{$value.name}}</option>{{/each}}</select></script><script src="/assets/lib/layui/layui.all.js"></script><script src="/assets/lib/template-web.js"></script><script src="/assets/lib/jquery.js"></script><script src="/assets/js/baseAPI.js"></script><!-- 富文本編輯器 --><script src="../../assets/lib/tinymce/tinymce.min.js"></script><script src="../../assets/lib/tinymce/tinymce_setup.js"></script><!-- 圖片裁剪 --><script src="../../assets/lib/cropper/Cropper.js"></script><script src="../../assets/lib/cropper/jquery-cropper.js"></script><script src="/assets/js/article/art_edit.js"></script> </body></html>

    6.15 完整css 樣式代碼

    html,body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }.cropper-box {width: 400px;height: 280px; }#image {max-width: 400px;/* 這個設置很重要! */max-height: 280px; }.img-preview {width: 200px;height: 140px;overflow: hidden;margin-bottom: 20px; }.cropper-container {display: flex; }.cropper-box {margin-right: 15px; }.right-box {text-align: center; }

    6.16 編輯功能完整 JS 代碼

    $(function() {// 通過 URLSearchParams 對象,獲取 前一個頁面URL 傳遞過來的參數var params = new URLSearchParams(location.search)var artId = params.get('id')// 文章的發布狀態var pubState = ''// 獲取需要的 layui 對象var form = layui.form// 1. 渲染文章分類列表renderArticleCates()function renderArticleCates() {$.get('/my/article/cates', function(res) {if (res.status !== 0) {return layer.msg('獲取文章分類列表失敗!')}var htmlStr = template('selectArtCates', res)$('#art_cate').html(htmlStr)form.render()getArticleById()})}// 2. 根據文章的 Id,獲取文章的詳情,并初始化表單的數據內容function getArticleById() {// 發起請求,獲取文章詳情$.get('/my/article/' + artId, function(res) {// 獲取數據失敗if (res.status !== 0) {return layer.msg('獲取文章失敗!')}// 獲取數據成功var art = res.data// 為 form 表單賦初始值form.val('addArticle', {Id: art.Id,title: art.title,cate_id: art.cate_id,content: art.content})// 手動初始化富文本編輯器initEditor()// 初始化圖片裁剪器var $image = $('#image')$image.attr('src', 'http://ajax.frontend.itheima.net' + art.cover_img)// $image.attr('src', 'http://www.liulongbin.top:3007' + art.cover_img)// 裁剪選項var cropperOption = {aspectRatio: 400 / 280,preview: '.img-preview',// 初始化圖片裁剪框的大小autoCropArea: 1}// 初始化裁剪區域$image.cropper(cropperOption)})}// 3. 選擇封面$('#btnChooseCoverImage').on('click', function(e) {e.preventDefault()$('#fileCover').click()})// 4. 監聽文件選擇框的 change 事件$('#fileCover').on('change', function(e) {var files = e.target.files// 沒有選擇文件if (files.length === 0) {return}// 重新為裁剪區域設置圖片$('#image').cropper('destroy').attr('src', URL.createObjectURL(files[0])).cropper({aspectRatio: 400 / 280,preview: '.img-preview'})})// 設置文章的發布狀態$('#btnPublish').on('click', function() {pubState = '已發布'})$('#btnSave').on('click', function() {pubState = '草稿'})// 5. 發布文章$('#formAddArticle').on('submit', function(e) {e.preventDefault()$('#image').cropper('getCroppedCanvas', {width: 400,height: 280}).toBlob(function(blob) {// 5.1 組織參數對象var fd = new FormData($('#formAddArticle')[0])// 5.2 添加封面fd.append('cover_img', blob)// 5.3 添加文章的發表狀態fd.append('state', pubState)// 5.4 發起請求$.ajax({method: 'POST',url: '/my/article/edit',data: fd,contentType: false,processData: false,success: function(res) {if (res.status !== 0) {return layer.msg('編輯文章失敗!')}location.href = '/article/art_list.html'}})})}) })

    7. 將開發完成的項目代碼推送到GitHub

    1、檢查當前所在分支:

    git branch

    2、本地提交

    git add .

    3、檢查所有文件狀態

    git status

    4、運行 git commit -m

    git commit -m "完成文章管理相關功能的開發"

    5、將本地article分支提交到 Github 存儲

    git push -u origin article

    6、將本地article分支里最新的代碼合并到master主分支
    1) 切換到 master 主分支

    git checkout master

    2)合并article里最新的代碼

    git merge article

    7、將本地 master最新代碼推送到Github中

    git push 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的大事件后台管理系统开发实战(下)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。