1. 程式人生 > 實用技巧 >大事件專案分享---實現後臺操作互動---後臺頁面資料的增刪改查

大事件專案分享---實現後臺操作互動---後臺頁面資料的增刪改查

專案介紹:

實現的頁面效果:

後臺管理頁面:

以上的靜態頁面,通過 HTML結構 和 CSS樣式 實現 而頁面的互動由 JS 來實現

練習專案的目標:

1.瞭解真實專案開發的架構設計

  • (1)前端三層分離的程式設計思想

  • (2)網路請求層單獨處理的程式設計思想

2.培養大家的專案思維能力

  • (1)獨立小功能需求分析->頁面需求分析->整個專案需求分析

  • (2)熟練運用ajax+模板引擎實現頁面業務邏輯功能

3.提升大家的專案經驗

  • (1)專案技術難點的分析與解決方案

  • (2)各種第三方外掛使用

回顧ajax發起請求和接收響應

回顧模板引擎實現資料的動態渲染

掌握token實現狀態保持的前臺頁面實現過程

進一步的掌握和體會前臺頁面的互動,理解前臺頁面互動的處理流程

進一步的掌握ajax的其它使用方式

搭建後臺環境:

專案之前需要使用資料視覺化軟體 naVicat 和 mysql資料庫 將以儲存的資料匯入和伺服器的開啟

開啟大事件專案資料夾 >> 找到大事件介面資料夾 >> 找到BigEventServers資料夾 >> 找到config 下的檔案 index.js 開啟 根據檔案內容

根據以上內容,在Navicat 中新建一個名字叫 'bignews' 的資料庫 >> 然後在BigEventServers資料夾中找到 reset 檔案開啟 >> 在開啟的該目錄下開啟小黑窗 >> 輸入命令node index.js 出現'搞定'兩個字即資料匯入成功.

開啟伺服器: 在BigEventServers資料夾目錄下 開啟小黑窗 輸入命令 app.js 執行 出現: 開啟成功: http://localhost:8080 即伺服器開啟成功.

模態框的新增

原因::相當於彈出層,可以用於取代alert進行使用者提示

 1 <!-- 模態框做為body的直接子元素 -->
 2 <div class="modal fade" id="myModal" tabindex="-1" role="dialog">
 3     <div class="modal-dialog" role="document">
 4         <div class="modal-content">
 5
<div class="modal-header"> 6 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span 7 aria-hidden="true">&times;</span></button> 8 <h4 class="modal-title">友情提示</h4> 9 </div> 10 <div class="modal-body"> 11 <p class="logininfo">One fine body&hellip;</p> 12 </div> 13 <div class="modal-footer"> 14 <button type="button" class="btn btn-primary btnconfirm">確定</button> 15 </div> 16 </div> 17 </div> 18 </div>

注意點: 模態框的整體結構要直接做 body 的子元素, 如果巢狀在其他HTML結構中會出現模態框無法點選使用

http模組的封裝

作用: 使頁面的程式碼更簡潔, 便於管理, 不易出錯. 頁面請求的 url 只需要引入該檔案(http.js) 再呼叫方法即可

 1 (function (w) {
 2   var baseURL = 'http://127.0.0.1:8080/api/v1'
 3   w.itcast = {
 4     // 定義基準路徑,所謂基準路徑就是資源url前面那一坨
 5     baseURL: baseURL,//基地址
 6     user_login: baseURL + '/admin/user/login',//使用者登入
 7     user_info: baseURL + '/admin/user/info',//使用者資訊
 8     user_detail: baseURL + '/admin/user/detail',//使用者詳情
 9     user_edit: baseURL + '/admin/user/edit',//使用者編輯
10     category_list: baseURL + '/admin/category/list',//文章類別查詢
11     category_add: baseURL + '/admin/category/add',//文章類別新增
12     category_search: baseURL + '/admin/category/search',//文章類別搜尋
13     category_edit: baseURL + '/admin/category/edit',//文章類別編輯
14     category_delete: baseURL + '/admin/category/delete',//文章類別刪除
15     article_query: baseURL + '/admin/article/query',//文章搜尋
16     article_publish: baseURL + '/admin/article/publish',//文章釋出
17     article_search: baseURL + '/admin/article/search',//文章資訊查詢
18     article_edit: baseURL + '/admin/article/edit',//文章編輯
19     article_delete: baseURL + '/admin/article/delete',//文章刪除
20     comment_search: baseURL + '/admin/comment/search',//文章評論列表
21     comment_pass: baseURL + '/admin/comment/pass',//文章評論通過
22     comment_reject: baseURL + '/admin/comment/reject',//文章評論不通過
23     comment_delete: baseURL + '/admin/comment/delete',//文章評論刪除
24   }
25 })(window)

後臺登入頁面

實現點選登入按鈕, 登入到後臺首頁頁面

 1 // 實現登陸
 2 // 1、使用者登入
 3 // 請求地址:/admin/user/login
 4 // 請求方式:post
 5 $('.input_sub').on('click', function () {
 6     // serialize:獲取獲取指定表單中擁有name屬性的表單元素的value值
 7     console.log($('.login_form').serialize())
 8     $.ajax({
 9         type: 'post',
10         url: itcast.user_login,
11         data: $('.login_form').serialize(),
12         dataType: 'json',
13         success: function (res) {
14             console.log(res)
15             $('.logininfo').text(res.msg)
16             if (res.code == 200) {
17                 // 將後臺返回的token資料儲存到本地
18                   localStorage.setItem('bignews_token_58', res.token)
19                 $('#myModal').modal('show')
20                 // hidden.bs.modal:在當前模態框被隱藏之後觸發
21                 $('#myModal').on('hidden.bs.modal', function (e) {
22                     location.href = './index.html'
23                 })
24             } else {
25                 // alert(res.msg)
26                 $('#myModal').modal('show')
27             }
28         }
29     })
30 })
31 
32 // 單擊模態框中的確定,隱藏模態框
33 $('.btnconfirm').on('click', function () {
34     $('#myModal').modal('hide')
35 })

因為後續的頁面的操作都需要許可權操作 , 即如果使用者登入成功了才可以在後續的頁面中使用增刪改查的許可權 , 那就需要給頁面傳一個tokan令牌,證明使用者已經登入過了,即可繼續操作頁面,

因為後續的頁面有很多請求, 如果一個個去加既麻煩還冗餘, 這時候就需要一個全域性函式來解決這種

該函式可以寫在頁面引入的 jQuery檔案 的 最後 不要加在中間或其他地方,容易更改了原始碼的結構

 1 // 這裡新增ajax的全域性函式的配置
 2 $.ajaxSetup({
 3     // 每個請求傳送之前都會經過beforeSend,可以在這個回撥進行請求頭的統一設定
 4     beforeSend: function (xhr) {
 5         let token = localStorage.getItem('bignews_token_58')
 6         if (token) {
 7             xhr.setRequestHeader('Authorization', token)
 8         }
 9     },
10     // 新增統一的錯誤處理
11     error: function (xhr, status, error) {
12         console.log(xhr, status, error)
13         if (error == 'Forbidden') {//使用者未登入
14             alert('請先登入!')
15             window.location.href = './login.html';//跳轉登陸頁面
16         };
17     }
18 })

注意事項:

在前端頁面結構中如果按鈕的型別為: 'submit' 會有一個預設行為,會影響到後面的操作, 所以將登陸按鈕的type屬性從submit修改為button

引數獲取不到,我們需要人為設定表單元素的name, 因為serialize() 的方法會獲取到表單域中帶有name屬性的元素的表單值 name值一定要參照後臺介面

token的本地儲存和傳遞

在登陸成功之後將token儲存到本地

後續請求傳遞token

為了簡化操作,使用$.ajaxSetup進行統一的處理

在登陸成功之後將token儲存到本地

// 將後臺返回的token資料儲存到本地
localStorage.setItem('bignews_token_58', res.token)

首頁

使用者資訊的動態渲染

首頁主體內容頁面的展示

左側選單的功能處理

頂部欄的個人中心和退出

使用者資訊的動態渲染

// 動態渲染使用者資訊
// 2、獲取使用者資訊
// 請求地址:/admin/user/info
// 請求方式:get
$.ajax({
        url: allSite.user_info,
        dataType: 'json',
        // beforeSend: function (xhr) {
        //     xhr.setRequestHeader('Authorization', localStorage.getItem('token_58'))
        // },
        success: function (res) {
            console.log(res);
            if (res.code == 200) {
                $('.user_info>img').attr('src', res.data.userPic)
                $('.user_info>span').html(`歡迎&nbsp;&nbsp;${res.data.nickname}`)
                $('.user_center_link>img').attr('src', res.data.userPic)
            }
        }
    })

首頁主體內容頁面的展示

使用iframe浮動框架,也稱為頁中頁

使用方式

1.新增浮動框架,為浮動框架設定name屬性

2.設定超連結的target屬性的值為iframe的name屬性的 值

<!-- 右側主體內容 -->
<div class="main" id="main_body">
    <!-- 新增一個浮動框架 -->
    <iframe class="myframe" src="./main_count.html" frameborder="0" name='main_frame'></iframe>
</div>

左側選單的功能

 1 //主頁左側導航欄功能實現
 2     $('.level01').on('click', function () {
 3         $(this).addClass('active').siblings().removeClass('active')
 4 
 5         if ($(this).next().hasClass('level02')) {
 6             $(this).next().slideToggle()
 7             $(this).find('b').toggleClass('rotate0')
 8         } else {
 9             $('.level02').slideUp()
10             $('.level02>li').removeClass('active')
11         }
12     })
13 
14     $('.level02>li').on('click', function () {
15         $(this).addClass('active').siblings().removeClass('active')
16     })

後臺首頁頂部的個人中心功能:

效果: 實現點選個人中心跳轉到個人中心頁面,並給左側的導航欄的個人中心導航選項新增樣式

<a href="./user.html" target="main_frame" onclick='$("#user").click()'>個人中心</a>

後臺首頁頂部的退出功能:

效果: 點選退出 實現刪除之前儲存的token 並且跳轉到登入頁面

//點選退出按鈕實現刪除token令牌,跳轉到登入頁面
    $('.logout').on('click', function () {
        localStorage.removeItem('token_58')
        window.location.href = './login.html'
    })

文章列表頁

主要實現功能:

  • 頁面資料的渲染,讓後臺文章資料動態渲染到頁面中
  • 資料篩選功能, 選擇文章型別和狀態,點選篩選, 使頁面資料根據選項動態渲染
  • 分頁外掛, 在列表頁下方生成一個分頁結構,使使用者點選對應鍵,跳轉到對應的頁面
  • 實現發表文章 和 編輯文章 的頁面跳轉

頁面資料的渲染

使用模板引擎動態渲染頁面會更簡便

 1 <!-- 頁面需要先引入模板引擎js檔案 -->
 2     <script src="./libs/template-web.js"></script>
 3 -----------------------------------------------------
 4 
 5 <!-- 模板結構 -->
 6 <script type="text/template" id="articleListTemp">
 7         {{each data}}
 8             <tr>
 9                 <td>{{$value.title}}</td>
10                 <td>{{$value.author}}</td>
11                 <td>{{$value.category}}</td>
12                 <td class="text-center">{{$value.date}}</td>
13                 <td class="text-center">{{$value.state}}</td>
14                 <td class="text-center">
15                     <a href="article_edit.html" class="btn btn-default btn-xs">編輯</a>
16                     <a href="javascript:void(0);" class="btn btn-danger btn-xs delete">刪除</a>
17                 </td>
18             </tr>
19         {{/each}}
20     </script>

實現動態渲染:

注意點: 在這裡發起請求時 對應的傳參需要根據伺服器介面文件 所需的引數來傳遞

文件所示所有的值可以為空, 則有預設值

// 獲取所有文章資料,實現文章資料的列表渲染
  // 10、文章搜尋
  // 請求地址:/admin/article/query
  // 請求方式:get
$.ajax({
    url: itcast.article_query,
    data: {
        page: 1, // 當前頁碼
        perpage: 10 // 每頁展示的數量
    },
    dataType: 'json',
    success: function (res) {
        console.log(res)
        if (res.code == 200) {
            $('tbody').html(template('articleListTemp', res.data))
        }
    }
})

資料篩選功能

難點: 下拉列表的使用

下拉列表的基本特性

  • 如果沒有設定value屬性,那麼後期獲取到的select下拉列表的value屬性值為option標籤之間的值

  • 如果設定了value屬性,那麼後期獲取到的就是value屬性所繫結的值

下拉列表的使用場景

  • 展示固定選項 -- 根據後臺需求和展示需要固定寫死

  • 渲染動態選項 -- 實現下拉列表的動態渲染,同時要根據資料業務的處理需求設定value屬性

下拉列表的動態渲// 分類資料的動態渲染

// 5、所有文章類別
// 請求地址:/admin/category/list
// 請求方式:get
  //設定全域性變數分頁外掛結構也會用到 letpage=1,perpage=10   $.ajax({
    url: itcast.category_list,
    dataType: 'json',
    success: function (res) {
        console.log(res)
        if (res.code == 200) {
            let str = `<option value="">所有分類</option>`
            for (let i = 0; i < res.data.length; i++) {
                str += `<option value='${res.data[i].id}'>${res.data[i].name}</option>`
            }
            $('#selCategory').html(str)
        }
    }
})

這時候會返回的資料

資料的篩選

  • 對於所有狀態,文章只有兩種狀態:草稿|已釋出,意味著我們可以固定寫死

  • 對於文章分類,它的資料是來自於後臺資料庫,所以需要動態渲染

  • 對於後臺的處理是:如果傳入的分類或狀態引數,就會拼接條件,否則不拼接條件,而查詢所有資料

函式的封裝

因為每次篩選都會重新渲染文章列表頁,所以將上面的頁面渲染程式碼進行函式封裝,這樣能夠使程式碼複用,更加簡潔

function init () {
    $.ajax({
        url: itcast.article_query,
        data: {
            page: 1, // 當前頁碼
            perpage: 10, // 每頁展示的數量
            type: $('#selCategory').val(), // 文章的分類,如果為''則查詢所有分類的文章資料
            state: $('#selStatus').val() // 文章的狀態,如果為''則查詢所有狀態的文章資料
        },
        dataType: 'json',
        success: function (res) {
            console.log(res)
            if (res.code == 200) {
                $('tbody').html(template('articleListTemp', res.data))
            }
        }
    })
}

實現資料的篩選

// 實現資料篩選
$('#btnSearch').on('click', function (e) {
    e.preventDefault()
    page = 1
    init()
})

分頁外掛 實現分頁結構

當資料量比較大的時候,不適合在一頁展示完所有資料的時候,就應該進行分頁

需要用到分頁外掛 在Bootstrap官網中就提供了這種分頁外掛

bootstrap-paginator是一款基於bootstrap的jQuery分頁外掛

注意點: 根據下載的檔案版本 在傳引數時需要注意 引數:bootstrapMajorVersion 需要根據版本傳入對應的值

引數: 紅色字型為必須引數

頁面需要引入的檔案:

<link rel="stylesheet" href="./lib/bootstrap.css">
<!--使用bootstrap外掛必須使用引入jquery,因為bootstrap是基於jquery開發的-->
<script src="./lib/jquery-2.1.1.min.js"></script>
<!--bootstrap外掛-->
<script src="./lib/bootstrap.js"></script>
<!--分頁外掛-->
<script src="./lib/bootstrap-paginator.js"></script>

實現分頁結構

 //實現分頁結構的顯示
    /**
     *
     * @param pageCurrent 當前所在頁  因為有全域性變數定義則不用傳遞
     * @param pageSum 總頁數
     * @param callback 呼叫ajax   不需要觸發
     */
    function setPage(pageSum) {
        $(".pagination").bootstrapPaginator({
            //設定版本號
            bootstrapMajorVersion: 3,
            // 顯示第幾頁
            currentPage: page,
            // 總頁數
            totalPages: pageSum,
            //當單擊操作按鈕的時候, 執行該函式, 呼叫ajax渲染頁面
            onPageClicked: function (event, originalEvent, type, getpage) {
                // getpage 為第四個引數,獲取使用者點選的頁碼數
                console.log(getpage);
                //獲取的頁碼賦值給全域性變數
                page = getpage;
                // 再重新渲染頁面,跳轉到對應頁數
                init()
            }
        })
    }

呼叫分頁函式實現分頁功能

在上面的程式碼進行修改

functioninit(){ $.ajax({ //10、文章搜尋 //請求地址:/admin/article/query //請求方式:get
url:allSite.article_query, data:{ type:$('#selCategory').val(),//文章的分類,如果為''則查詢所有分類的文章資料 state:$('#selStatus').val(),//文章的狀態,如果為''則查詢所有狀態的文章資料 page:page, perpage:perpage }, dataType:'json', success:function(res){ console.log(res);       -------------------------------下面是實現的程式碼--------------------------- if(res.code==200){ //將模板新增到對應位置渲染出來 $('tbody').html(template('articleListTemp',res.data)) //分頁結構的渲染 if(res.data.data.length==0){ //當篩選文章資料時,資料為零時,分頁外掛會預設顯示5頁分頁,不符合實際的需求,所以當資料為零時分頁結構顯示一頁 setPage(1) }else{ //其他情況即為有資料則正常渲染 setPage(res.data.totalPage) } } } }) } init()

文章釋出

收集後臺介面需要的資料

注意是使用 formdata 方式提交資料, 圖片也是已資料傳遞 , 而不是簡單的傳遞字串

打開發布文章頁面就開始渲染分類資料

這裡要注意: 在頁面檔案中要傳入封裝好的 http.js 檔案 即 url 對應的地址

 1 //打開發布文章,渲染頁面的文章類別
 2     $.ajax({
 3         // 所有文章類別
 4         // 請求地址:/ admin / category / list
 5         // 請求方式:get
 6         url: allSite.category_list,
 7         dataType: 'json',
 8         success: function (res) {
 9             // console.log(res);
10             let str = ''
11             for (let index = 0; index < res.data.length; index++) {
12                 str += `<option value="${res.data[index].id}">${res.data[index].name}</option>`
13             }
14             $('.category').html(str)
15         }
16     })

實現釋出文章頁面的檔案預覽

注意事項,因為使用的是formdata 方式上傳 即使用者選擇好圖片時就實現預覽但不上傳檔案, 這時候就需要本地預覽

URL.creatObjectUrl:它可以將指定的資源託管到內建臨時伺服器

 1   /*2.檔案預覽 */
 2     //1.給file表單元素註冊onchange事件
 3     $('#inputCover').change(function () {
 4         //1.2 獲取使用者選擇的圖片 通過URL的createObjectUrl獲取託管在伺服器端的資源路徑
 5         var file = $('#inputCover')[0].files[0];
 6         //1.3 將檔案轉為src路徑
 7         var url = window.URL.createObjectURL(file);
 8         //1.4 將url路徑賦值給img標籤的src
 9         $('.article_cover').attr('src', url);
10     });

實現釋出文章頁面的時間功能

需要一個日期外掛 在頁面檔案中需要引入css 和 js 在頁面結構中還需要一個載體 建議使用文字框

引入檔案

<link rel="stylesheet" href="./libs/jedate/css/jedate.css">
<script src="./libs/jedate/js/jedate.js"></script>

新增載體

<div class="form-group">
     <label class="col-sm-2 control-label">釋出時間:</label>
     <div class="col-sm-4">
      --------新增一個文字框載體---------------   <input type="text" class="jeinput" id="testico" placeholder="YYYY-MM-DD" name='date'> </div> </div>

在頁面的js檔案中 進行日期外掛的初始化

jeDate 中有兩個引數, 第一個引數傳入載體, 第二引數傳的是一個物件,用於定製日期外掛的功能樣式, 可以不傳 則有預設值,但樣式會很醜.

外掛獲取日期值 用value方式就可以獲取

  //加入日期外掛
    $(function () {
jeDate("#testico", { trigger: "click", format: "YYYY-MM-DD", theme: { bgcolor: "#D91600", pnColor: "#FF6653" }, isinitVal: true }) });

實現釋出文章頁面新增富文字框外掛

引入資源

<script src="./libs/tinymce/tinymce.min.js"></script>

新增載體

         <div class="form-group">
                    <label for="inputEmail3" class="col-sm-2 control-label">文章內容:</label>
                    <div class="col-sm-10">
            ------------------新增載體------------
            <textarea id="mytextarea"></textarea> </div> </div>

在頁面的js檔案中 進行外掛的初始化

注意事項:

  • 富文字框外掛會在載體上方新增一個新的結構,使用者的資料是輸入在這個新結構中,意味著我們無法從文字框載體中獲取資料
  • 富文字框的內容是網頁結構,因為它要記錄使用者輸入內容的格式,而html可以描述這種結構
//加入富文字框外掛
    tinymce.init({
        selector: '#mytextarea',
        height: '350px',
        language: 'zh_CN',
        directionality: 'ltl',
        browser_spellcheck: true,
        contextmenu: false,
        plugins: [
            "advlist autolink lists link image charmap print preview anchor",
            "searchreplace visualblocks code fullscreen",
            "insertdatetime media table contextmenu paste imagetools wordcount",
            "code"
        ],
        toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | code",
    });

獲取外掛的內容的方法:tinymce.activeEditor.getContent()

再將資料新增到 formdata 中

  let formdata = new FormData($('#form')[0])
    // console.log(tinymce.activeEditor.getContent())
    // 將富文字框的內容新增到formdata
    formdata.append('content', tinymce.activeEditor.getContent())

實現文章的新增

下面是完整的實現程式碼 其中沒有 分類的動態渲染和外掛的使用 的程式碼 是因為後期還需要複用到 所以封裝到一個js檔案中去引入使用 則在頁面HTML檔案中引入即可,下方有詳細程式碼

注意事項:

  • 使用formdata方式獲取資料時 會少了 富文字框的資料 和 文章狀態的資料 就需要主動新增進去
  • 釋出文章的圖片一定要上傳, 因為後臺介面是固定需要不可以為空 ,不傳遞會報400的錯誤 即引數不正確
  • 圖片的格式支援jpg,png,gif,副檔名要求小寫
 1 $(function () {
 2     /*2.檔案預覽 */
 3     //1.給file表單元素註冊onchange事件
 4     $('#inputCover').change(function () {
 5         //1.2 獲取使用者選擇的圖片
 6         var file = $('#inputCover')[0].files[0];
 7         //1.3 將檔案轉為src路徑  通過URL的createObjectUrl獲取託管在伺服器端的資源路徑
 8         var url = window.URL.createObjectURL(file);
 9         //1.4 將url路徑賦值給img標籤的src
10         $('.article_cover').attr('src', url);
11     });
12     //點擊發布按鈕,獲取使用者資料
13     // 11、釋出文章
14     // 請求地址:/admin/article / publish
15     // 請求方式:post
16     // 請求引數:通過formData提交
17     // 由於釋出按鈕和草稿按鈕業務邏輯相同,
18     // 只是state引數不同,可以封裝一個函式,將state作為引數傳遞
19     $('.btn-release').on('click', function (e) {
20         //阻止預設行為
21         e.preventDefault()
22         uploadingData('已釋出')
23     })
24     $('.btn-draft').on('click', function (e) {
25         //阻止預設行為
26         e.preventDefault()
27         uploadingData('草稿')
28     })
29     
30     function uploadingData(state) {
31         //建立FormData
32         let formdata = new FormData($('#form')[0])
33         //tinymce.activeEditor.getContent()獲取富文字框的文字內容  獲取的資料是以 HTML格式顯示 ,後期渲染時需要使用html方法
34         formdata.append('content', tinymce.activeEditor.getContent())
35         //追加文章狀態
36         formdata.append('state', state)
37         console.log(...formdata);
38         //實現文章釋出
39         $.ajax({
40             type: 'post',
41             url: allSite.article_publish,
42             data: formdata,
43             dataType: 'json',
44             contentType: false,
45             processData: false,
46             success: function (res) {
47                 console.log(res);
48                 if (res.code == 200) {
49                     alert(res.msg)
50                     //返回文章列表頁 ,給左側列表頁導航欄項新增樣式
51                     $('.level02>li:eq(0)', window.parent.document).addClass('active').siblings().removeClass('active');
52                     window.location.href = './article_list.html'
53                 }
54             }
55         })
56     }
57 
58 })

公共程式碼 comment.js

 1 $(function () {
 2     //打開發布文章,渲染頁面的文章類別
 3     $.ajax({
 4         // 所有文章類別
 5         // 請求地址:/ admin / category / list
 6         // 請求方式:get
 7         url: allSite.category_list,
 8         dataType: 'json',
 9         success: function (res) {
10             // console.log(res);
11             let str = ''
12             for (let index = 0; index < res.data.length; index++) {
13                 str += `<option value="${res.data[index].id}">${res.data[index].name}</option>`
14             }
15             $('.category').html(str)
16         }
17     })
18 
19     //加入日期外掛
20     $(function () {
21         //或者為這樣的
22         jeDate("#testico", {
23             trigger: "click",
24             format: "YYYY-MM-DD",
25             theme: { bgcolor: "#D91600", pnColor: "#FF6653" },
26             isinitVal: true
27         })
28     });
29 
30     //加入富文字框外掛
31     tinymce.init({
32         selector: '#mytextarea',
33         height: '350px',
34         language: 'zh_CN',
35         directionality: 'ltl',
36         browser_spellcheck: true,
37         contextmenu: false,
38         plugins: [
39             "advlist autolink lists link image charmap print preview anchor",
40             "searchreplace visualblocks code fullscreen",
41             "insertdatetime media table contextmenu paste imagetools wordcount",
42             "code"
43         ],
44         toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | code",
45     });
46 })

文章刪除功能

注意事項:

  • 在文章列表頁面中 文章的資料時使用模板引擎動態渲染的 所有在繫結事件時 不可以直接繫結在元素上, 要通過結構中存在的父元素來繫結--事件委託的方式
  • 刪除事件需要根據id來進行刪除 而結構中又沒有id引數傳遞 這時候就需要自己新增 自定義屬性 data 來儲存id 再去獲取id

在模板結構的刪除結構 新增自定義屬性

 1 <script type="text/template" id="articleListTemp">
 2         {{each data}}
 3             <tr>
 4                 <td>{{$value.title}}</td>
 5                 <td>{{$value.author}}</td>
 6                 <td>{{$value.category}}</td>
 7                 <td class="text-center">{{$value.date}}</td>
 8                 <td class="text-center">{{$value.state}}</td>
 9                 <td class="text-center">
10                     <a href="article_edit.html?id={{$value.id}}" class="btn btn-default btn-xs" id="compile_btn">編輯</a>
               --------------新增自定義屬性--------------------------- 11 <a href="javascript:void(0);" class="btn btn-danger btn-xs delete_btn" data-id='{{$value.id}}'>刪除</a> 12 </td> 13 </tr> 14 {{/each}}

實現刪除效果

注意獲取頁面傳遞的id

 1 //實現刪除文章功能
 2     // 14、刪除文章
 3     // 請求地址:/admin/article / delete
 4     // 請求方式:post
 5     $('table>tbody').on('click', '.delete_btn', function () {
 6         $.ajax({
 7             type: 'post',
 8             url: allSite.article_delete,
 9             dataType: 'json',
10             data: {
            --------------獲取頁面傳遞的id-------------
11 id: $(this).attr('data-id') 12 }, 13 success: function (res) { 14 console.log(res); 15 if (res.code == 204) { 16 alert(res.msg) 17 location.reload(); 18 } else { 19 alert(res.msg) 20 } 21 } 22 }) 23 })

文章編輯功能

使用者點選編輯, 跳轉到編輯頁面 根據後臺資料渲染 編輯文章頁面

渲染頁面注意事項:

  • 在編輯跳轉時要傳遞id
  • 在編輯頁接收引數id
  • 根據id查詢文章詳情資料
  • dom賦值

實現資料的預設展示

傳遞id

<script type="text/template" id="articleListTemp">
        {{each data}}
            <tr>
                <td>{{$value.title}}</td>
                <td>{{$value.author}}</td>
                <td>{{$value.category}}</td>
                <td class="text-center">{{$value.date}}</td>
                <td class="text-center">{{$value.state}}</td>
                <td class="text-center">
             -------------新增?id={{$value.id}} 用於傳遞id-----------------------
            <a href="article_edit.html?id={{$value.id}}" class="btn btn-default btn-xs" id="compile_btn">編輯</a> <a href="javascript:void(0);" class="btn btn-danger btn-xs delete_btn" data-id='{{$value.id}}'>刪除</a> </td> </tr> {{/each}}

在編輯頁面獲取id

使用itcast.getParameter 需要在頁面檔案中引入一個js檔案 用於把傳遞的引數結構為 key=value&key=value&key=value.... 轉換為物件

//1.獲取artile_list頁面傳遞過來的文章id
    let id = itcast.getParameter(location.search).id
    // console.log(id);

引入的檔案結構 可以建立檔案再複製貼上程式碼使用

 1 var itcast = {
 2     getParameter: function (str) { // ?id=7&name=jack
 3         // 刪除?
 4         str = str.replace('?', '')  // id=7&name=jack
 5         // 分割字串
 6         var arr = str.split('&')  // ["id=7","name=jack"]
 7         // 迴圈遍歷再次分割
 8         var obj = {}
 9         for (var i = 0; i < arr.length; i++) { // 1.id=7
10             var temp = arr[i].split('=') // ["id",7]
11             // 將資料新增到物件
12             obj[temp[0]] = temp[1] // {id:7}
13         }
14         return obj
15     }
16 }

根據id查詢文章詳情資料

注意事項:

  • 獲取id 需要定義全域性變數 後面也會使用到
  • 使用者不傳入圖片時,後臺就預設不修改
  • 在給時間外掛複製需要注意 因為 時間外掛封裝的js檔案 和 頁面的js檔案是分開的, 卻都是非同步操作,所以有可能會造成文章詳情資料已經成功的獲取了,而分類下拉列表還沒有渲染完畢,所以造成選項不能切換.
    這時候需要定時器延遲載入// settimeout中的程式碼,會在其它所有程式碼執行完畢之後再執行
  • 富文字框的賦值 外掛預設會將文字域的內容同步到富文字框外掛,當外掛載入完畢之後同步
 1 //根據id獲取文章資訊
 2     // 12、根據id獲取文章資訊
 3     // 請求地址:/admin/article / search
 4     // 請求方式:get
 5 
 6     //1.獲取artile_list頁面傳遞過來的文章id
 7     let id = itcast.getParameter(location.search).id
 8     // console.log(id);
 9     $.ajax({
10         url: allSite.article_search,
11         data: { id },
12         dataType: 'json',
13         success: function (res) {
14             // console.log(res);
15             if (res.code == 200) {
16                 $('#inputTitle').val(res.data.title)
17                 $('.article_cover').attr('src', res.data.cover)
            // settimeout中的程式碼,會在其它所有程式碼執行完畢之後再執行
18 setTimeout(function () { 19 $('select.category').val(res.data.categoryId) 20 }, 0) 21 $('#testico').val(res.data.date)
            //
富文字框的賦值 外掛預設會將文字域的內容同步到富文字框外掛,當外掛載入完畢之後同步
22                 $('#mytextarea').val(res.data.content)
23             }
24         }
25     })

實現編輯功能

下面是完整程式碼

 1 $(function () {
 2     //根據id獲取文章資訊
 3     // 12、根據id獲取文章資訊
 4     // 請求地址:/admin/article / search
 5     // 請求方式:get
 6     //1.獲取artile_list頁面傳遞過來的文章id
 7     let id = itcast.getParameter(location.search).id
 8     // console.log(id);
 9     $.ajax({
10         url: allSite.article_search,
11         data: { id },
12         dataType: 'json',
13         success: function (res) {
14             // console.log(res);
15             if (res.code == 200) {
16                 $('#inputTitle').val(res.data.title)
17                 $('.article_cover').attr('src', res.data.cover)
18                 setTimeout(function () {
19                     $('select.category').val(res.data.categoryId)
20                 }, 0)
21                 $('#testico').val(res.data.date)
22                 $('#mytextarea').val(res.data.content)
23             }
24         }
25     })
26     // 13、文章編輯
27     // 請求地址:/admin/article / edit
28     // 請求方式:post
29     $('.btn-edit').on('click', function (e) {
30         //阻止預設行為
31         e.preventDefault()
32         uploadingData('已釋出')
33     })
34     $('.btn-draft').on('click', function (e) {
35         //阻止預設行為
36         e.preventDefault()
37         uploadingData('草稿')
38     })
39 
40     function uploadingData(state) {
41         //建立FormData
42         let formdata = new FormData($('#form')[0])
43         //tinymce.activeEditor.getContent()獲取富文字框的文字內容  獲取的資料是以 HTML格式顯示 
44         formdata.append('content', tinymce.activeEditor.getContent())
45         //追加文章狀態
46         formdata.append('state', state)
47         //追加id
48         formdata.append('id', id)
49         // console.log(...formdata);
50         //實現文章釋出
51         $.ajax({
52             type: 'post',
53             url: allSite.article_edit,
54             data: formdata,
55             dataType: 'json',
56             contentType: false,
57             processData: false,
58             success: function (res) {
59                 console.log(res);
60                 if (res.code == 200) {
61                     alert('修改成功')
62                     //返回文章列表頁 ,給左側列表頁導航欄項新增樣式
63                     $('.level02>li:eq(0)', window.parent.document).addClass('active').siblings().removeClass('active');
64                     window.location.href = './article_list.html'
65                 }
66             }
67         })
68     }
69     /*2.檔案預覽 */
70     //1.給file表單元素註冊onchange事件
71     $('#inputCover').change(function () {
72         //1.2 獲取使用者選擇的圖片
73         var file = $('#inputCover')[0].files[0];
74         //1.3 將檔案轉為src路徑
75         var url = window.URL.createObjectURL(file);
76         //1.4 將url路徑賦值給img標籤的src
77         $('.article_cover').attr('src', url);
78     });
79 })
//實現刪除文章功能 //14、刪除文章 //請求地址:/admin/article/delete //請求方式:post $('table>tbody').on('click','.delete_btn',function(){ $.ajax({ type:'post', url:allSite.article_delete, dataType:'json', data:{ id:$(this).attr('data-id') }, success:function(res){ console.log(res); if(res.code==204){ alert(res.msg) location.reload(); }else{ alert(res.msg) } } }) })