JavaScript >> Javascript 文檔 >  >> Tags >> CSS

帶有 PHP、MySQL 和 jQuery 的 AJAX 待辦事項列表

在本教程中,我們將使用 PHP、MySQL 和 jQuery 製作一個簡單的 AJAX-ed Todo List App。在此過程中,我們將演示 PHP 的 OOP 功能,使用 jQuery UI 並實現一些不錯的 AJAX 功能。

為了更好地理解本教程的步驟,您可以繼續下載演示存檔 可從上方的按鈕獲得。

第 1 步 - PHP

由於這更像是一個面向開發人員的教程,我們將從 PHP 部分開始。與之前的教程不同,這次我們利用的是 PHP 5 的 OOP 特性。

最終用戶可用的所有功能 - 創建、編輯、刪除和重新排序待辦事項 - 都是作為類的不同方法實現的,下面將詳細解釋。

todo.class.php - 第 1 部分

/* Defining the ToDo class */

class ToDo{

    /* An array that stores the todo item data: */

    private $data;

    /* The constructor */
    public function __construct($par){
        if(is_array($par))
            $this->data = $par;
    }

    /*
        This is an in-build "magic" method that is automatically called
        by PHP when we output the ToDo objects with echo.
    */

    public function __toString(){

        // The string we return is outputted by the echo statement

        return '
            <li id="todo-'.$this->data['id'].'" class="todo">

                <div class="text">'.$this->data['text'].'</div>

                <div class="actions">
                    <a href="" class="edit">Edit</a>
                    <a href="" class="delete">Delete</a>
                </div>

            </li>';
    }

構造函數將數組作為參數傳遞並存儲在 $data 類的屬性。該數組是使用 mysql_fetch_assoc() 從數據庫中獲取的一行 並包含待辦事項的id和文本。

在這之後是神奇的 __toString() 方法,當我們嘗試回顯該類的對象時在內部調用該方法。它返回的字符串包含每個待辦事項使用的標記 -

  • 具有唯一 id 和類名“todo”的元素,其中我們有 todo 的文本和兩個動作超鏈接。

    todo.class.php - 第 2 部分

     /*
            The edit method takes the ToDo item id and the new text
            of the ToDo. Updates the database.
        */
    
        public static function edit($id, $text){
    
            $text = self::esc($text);
            if(!$text) throw new Exception("Wrong update text!");
    
            mysql_query("   UPDATE tz_todo
                            SET text='".$text."'
                            WHERE id=".$id
                        );
    
            if(mysql_affected_rows($GLOBALS['link'])!=1)
                throw new Exception("Couldn't update item!");
        }
    
        /*
            The delete method. Takes the id of the ToDo item
            and deletes it from the database.
        */
    
        public static function delete($id){
    
            mysql_query("DELETE FROM tz_todo WHERE id=".$id);
    
            if(mysql_affected_rows($GLOBALS['link'])!=1)
                throw new Exception("Couldn't delete item!");
        }
    
        /*
            The rearrange method is called when the ordering of
            the todos is changed. Takes an array parameter, which
            contains the ids of the todos in the new order.
        */
    
        public static function rearrange($key_value){
    
            $updateVals = array();
            foreach($key_value as $k=>$v)
            {
                $strVals[] = 'WHEN '.(int)$v.' THEN '.((int)$k+1).PHP_EOL;
            }
    
            if(!$strVals) throw new Exception("No data!");
    
            // We are using the CASE SQL operator to update the ToDo positions en masse:
    
            mysql_query("   UPDATE tz_todo SET position = CASE id
                            ".join($strVals)."
                            ELSE position
                            END");
    
            if(mysql_error($GLOBALS['link']))
                throw new Exception("Error updating positions!");
        }

    類的定義繼續使用一些靜態方法。這些是特殊方法,無需創建類的對象即可訪問。例如,您可以通過編寫來調用編輯方法:ToDo::edit($par1,$par2) .

    注意我們如何使用異常來處理錯誤。當發生異常時,腳本執行會停止,由腳本的其餘部分來捕獲它並輸出適當的狀態。

    此外,您可能會發現我們使用待辦事項的新位置更新數據庫的方式很有趣。我們正在使用 CASE 運算符,在 MySQL 中可用。這樣,無論數據庫中有多少個待辦事項,我們只執行一個查詢。

    todo.class.php - 第 3 部分

     /*
            The createNew method takes only the text of the todo as a parameter,
            writes to the database and outputs the new todo back to
            the AJAX front-end.
        */
    
        public static function createNew($text){
    
            $text = self::esc($text);
            if(!$text) throw new Exception("Wrong input data!");
    
            $posResult = mysql_query("SELECT MAX(position)+1 FROM tz_todo");
    
            if(mysql_num_rows($posResult))
                list($position) = mysql_fetch_array($posResult);
    
            if(!$position) $position = 1;
    
            mysql_query("INSERT INTO tz_todo SET text='".$text."', position = ".$position);
    
            if(mysql_affected_rows($GLOBALS['link'])!=1)
                throw new Exception("Error inserting TODO!");
    
            // Creating a new ToDo and outputting it directly:
    
            echo (new ToDo(array(
                'id'    => mysql_insert_id($GLOBALS['link']),
                'text'  => $text
            )));
    
            exit;
        }
    
        /*
            A helper method to sanitize a string:
        */
    
        public static function esc($str){
    
            if(ini_get('magic_quotes_gpc'))
                $str = stripslashes($str);
    
            return mysql_real_escape_string(strip_tags($str));
        }
    
    } // closing the class definition
    

    使用 self:: 可以輕鬆訪問同一類的靜態方法 關鍵詞。這樣我們使用 esc() 清理傳入用戶數據的方法。

    還要注意 createNew() 方法。在其中,在數據庫上運行 INSERT 查詢後,我們使用返回的自動分配的唯一 id 和 mysql_insert_id() 並創建一個新的 todo 對象,然後將其回顯到前端。

    現在讓我們看看這個類是如何使用的。

    demo.php - 第 1 部分

    // Select all the todos, ordered by position:
    $query = mysql_query("SELECT * FROM `tz_todo` ORDER BY `position` ASC");
    
    $todos = array();
    
    // Filling the $todos array with new ToDo objects:
    
    while($row = mysql_fetch_assoc($query)){
        $todos[] = new ToDo($row);
    }

    包含 todo.class.php 之後 在 demo.php 中 ,我們選擇待辦事項並循環遍歷MySQL結果集,填寫$todos 包含對象的數組。

    demo.php - 第 2 部分

    // Looping and outputting the $todos array. The __toString() method
    // is used internally to convert the objects to strings:
    
    foreach($todos as $item){
        echo $item;
    }

    在頁面的後面,這些對像被回顯出來。感謝 __toString() 上面討論的方法,所有的標記都是自動生成的,所以我們不必處理任何這些。

    前端發出許多不同的 AJAX 調用。製作一個單獨的文件來處理它們中的每一個有點過分,所以最好的解決方案是將它們分組到一個 AJAX 處理文件中。這是在 ajax.php 中完成的 ,您可以在下面看到。

    ajax.php

    $id = (int)$_GET['id'];
    
    try{
    
        switch($_GET['action'])
        {
            case 'delete':
                ToDo::delete($id);
                break;
    
            case 'rearrange':
                ToDo::rearrange($_GET['positions']);
                break;
    
            case 'edit':
                ToDo::edit($id,$_GET['text']);
                break;
    
            case 'new':
                ToDo::createNew($_GET['text']);
                break;
        }
    
    }
    catch(Exception $e){
    //  echo $e->getMessage();
        die("0");
    }
    
    echo "1";

    在 switch 語句的幫助下,我們決定執行 ToDo 類的哪些靜態方法。如果這些方法之一發生錯誤,則會調度異常。因為整個 switch 都包含在 try 語句中 ,腳本的執行停止,控制權傳遞給 catch 語句,該語句輸出零並退出腳本。

    通過取消註釋第 26 行,您可能會回顯(或寫入日誌)究竟發生了什麼樣的錯誤。

    第 2 步 - MySQL

    tz_todo 表保存並分配待辦事項的唯一 ID(通過字段的 auto_increment 設置)、位置、文本和 dt_added 時間戳。

    您可以在 table.sql 中找到將重新創建表的 SQL 在下載存檔中。另外,如果您打算在自己的服務器上運行演示,請不要忘記在 connect.php 中填寫您的登錄詳細信息 .

    第 3 步 - XHTML

    由於大部分標記是由 PHP 生成的,因此我們需要處理頁面的其餘部分 XHTML。首先我們需要包含 jQuery , jQuery UI ,以及文檔中的樣式表。將樣式表包含在 head 部分和 JavaScript 文件就在結束 之前被認為是一種很好的做法 標記。

    <link rel="stylesheet" href="jquery-ui.css" type="text/css" />
    <link rel="stylesheet" type="text/css" href="styles.css" />
    
    <script type="text/javascript" src="jquery.min.js"></script>
    <script type="text/javascript" src="jquery-ui.min.js"></script>
    <script type="text/javascript" src="script.js"></script>

    在此之後,我們可以繼續對頁​​面的其餘部分進行編碼。

    demo.php

    <div id="main">
    
        <ul class="todoList">
    
        <?php
    
            // Looping and outputting the $todos array. The __toString() method
            // is used internally to convert the objects to strings:
    
            foreach($todos as $item){
                echo $item;
            }
    
            ?>
    
        </ul>
    
        <a id="addButton" class="green-button" href="">Add a ToDo</a>
    
    </div>
    
    <!-- This div is used as the base for the confirmation jQuery UI dialog box. Hidden by CSS. -->
    <div id="dialog-confirm" title="Delete TODO Item?">Are you sure you want to delete this TODO item?</div>

    每個待辦事項都是一個li todoList 中的項目 無序列表。這樣,我們以後可以使用 jQuery UI 的 sortable 方法 輕鬆將其轉換為交互式可排序元素。同時,在這個過程中,我們增強了代碼的語義價值。

    第 4 步 - CSS

    現在讓我們繼續討論 todos 的樣式。為了更好的可讀性,這裡只給出了原始樣式表的一部分。您可以在 styles.css 中找到其餘部分 在下載存檔中。

    styles.css - 第 1 部分

    /* The todo items are grouped into an UL unordered list */
    
    ul.todoList{
        margin:0 auto;
        width:500px;
        position:relative;
    }
    
    ul.todoList li{
        background-color:#F9F9F9;
        border:1px solid #EEEEEE;
        list-style:none;
        margin:6px;
        padding:6px 9px;
        position:relative;
        cursor:n-resize;
    
        /* CSS3 text shadow and rounded corners: */
    
        text-shadow:1px 1px 0 white;
    
        -moz-border-radius:6px;
        -webkit-border-radius:6px;
        border-radius:6px;
    }
    
    ul.todoList li:hover{
        border-color:#9be0f9;
    
        /* CSS3 glow effect: */
        -moz-box-shadow:0 0 5px #A6E5FD;
        -webkit-box-shadow:0 0 5px #A6E5FD;
        box-shadow:0 0 5px #A6E5FD;
    }
    

    待辦事項列表 ul 在頁面上水平居中並分配相對位置。 其中的元素(待辦事項)共享許多 CSS3 規則。不幸的是,這些在舊版瀏覽器中不起作用,但由於它們僅用於演示目的,即使像 IE6 一樣舊的瀏覽器也可以享受完整的腳本,儘管不如預期的那麼漂亮。

    styles.css - 第 2 部分

    /* The edit textbox */
    
    .todo input{
        border:1px solid #CCCCCC;
        color:#666666;
        font-family:Arial,Helvetica,sans-serif;
        font-size:0.725em;
        padding:3px 4px;
        width:300px;
    }
    
    /* The Save and Cancel edit links: */
    
    .editTodo{
        display:inline;
        font-size:0.6em;
        padding-left:9px;
    }
    
    .editTodo a{
        font-weight:bold;
    }
    
    a.discardChanges{
        color:#C00 !important;
    }
    
    a.saveChanges{
        color:#4DB209 !important;
    }

    在代碼的第二部分,我們設置了輸入文本框的樣式,在待辦事項被編輯時顯示,以及保存和取消鏈接。

    第 5 步 - jQuery

    轉到 JavaScript 代碼。這裡我們使用了兩個 jQuery UI 的用戶界面組件 - sortable , 和 對話框 .僅這些就為我們節省了至少幾個小時的開發時間,這是使用像 jQuery 這樣經過深思熟慮的庫的好處之一。

    script.js - 第 1 部分

    $(document).ready(function(){
        /* The following code is executed once the DOM is loaded */
    
        $(".todoList").sortable({
            axis        : 'y',              // Only vertical movements allowed
            containment : 'window',         // Constrained by the window
            update      : function(){       // The function is called after the todos are rearranged
    
                // The toArray method returns an array with the ids of the todos
                var arr = $(".todoList").sortable('toArray');
    
                // Striping the todo- prefix of the ids:
    
                arr = $.map(arr,function(val,key){
                    return val.replace('todo-','');
                });
    
                // Saving with AJAX
                $.get('ajax.php',{action:'rearrange',positions:arr});
            }
        });
    
        // A global variable, holding a jQuery object
        // containing the current todo item:
    
        var currentTODO;
    
        // Configuring the delete confirmation dialog
        $("#dialog-confirm").dialog({
            resizable: false,
            height:130,
            modal: true,
            autoOpen:false,
            buttons: {
                'Delete item': function() {
    
                    $.get("ajax.php",{"action":"delete","id":currentTODO.data('id')},function(msg){
                        currentTODO.fadeOut('fast');
                    })
    
                    $(this).dialog('close');
                },
                Cancel: function() {
                    $(this).dialog('close');
                }
            }
        });

    要顯示對話框,我們需要有一個基本 div,它將被轉換為對話框。 div 的內容將作為對話框的文本顯示,而 div 的 title 屬性的內容將成為對話框窗口的標題。你可以找到這個 div (id=dialog-confirm ) 在 demo.php 中 .

    script.js - 第 2 部分

      // When a double click occurs, just simulate a click on the edit button:
        $('.todo').live('dblclick',function(){
            $(this).find('a.edit').click();
        });
    
        // If any link in the todo is clicked, assign
        // the todo item to the currentTODO variable for later use.
    
        $('.todo a').live('click',function(e){
    
            currentTODO = $(this).closest('.todo');
            currentTODO.data('id',currentTODO.attr('id').replace('todo-',''));
    
            e.preventDefault();
        });
    
        // Listening for a click on a delete button:
    
        $('.todo a.delete').live('click',function(){
            $("#dialog-confirm").dialog('open');
        });
    
        // Listening for a click on a edit button
    
        $('.todo a.edit').live('click',function(){
    
            var container = currentTODO.find('.text');
    
            if(!currentTODO.data('origText'))
            {
                // Saving the current value of the ToDo so we can
                // restore it later if the user discards the changes:
    
                currentTODO.data('origText',container.text());
            }
            else
            {
                // This will block the edit button if the edit box is already open:
                return false;
            }
    
            $('<input type="text">').val(container.text()).appendTo(container.empty());
    
            // Appending the save and cancel links:
            container.append(
                '<div class="editTodo">'+
                    '<a class="saveChanges" href="">Save</a> or <a class="discardChanges" href="">Cancel</a>'+
                '</div>'
            );
    
        });

    注意 jQuery live() 的使用 綁定事件的方法。我們正在使用 live() , 而不是 bind() ,因為 live() 可以監聽任何元素上的事件,甚至是那些還不存在的元素。這樣我們就可以確保用戶將來添加到頁面的所有待辦事項,也將觸發與當前存在的事件處理程序相同的事件處理程序。

    script.js - 第 3 部分

      // The cancel edit link:
    
        $('.todo a.discardChanges').live('click',function(){
            currentTODO.find('.text')
                        .text(currentTODO.data('origText'))
                        .end()
                        .removeData('origText');
        });
    
        // The save changes link:
    
        $('.todo a.saveChanges').live('click',function(){
            var text = currentTODO.find("input[type=text]").val();
    
            $.get("ajax.php",{'action':'edit','id':currentTODO.data('id'),'text':text});
    
            currentTODO.removeData('origText')
                        .find(".text")
                        .text(text);
        });
    
        // The Add New ToDo button:
    
        var timestamp;
        $('#addButton').click(function(e){
    
            // Only one todo per 5 seconds is allowed:
            if(Date.now() - timestamp<5000) return false;
    
            $.get("ajax.php",{'action':'new','text':'New Todo Item. Doubleclick to Edit.'},function(msg){
    
                // Appending the new todo and fading it into view:
                $(msg).hide().appendTo('.todoList').fadeIn();
            });
    
            // Updating the timestamp:
            timestamp = Date.now();
    
            e.preventDefault();
        });
    
    }); // Closing $(document).ready()

    在代碼的最後一部分,我們將事件綁定到 Save取消 鏈接,在編輯時添加到待辦事項中。我們還為 "Add" 設置了一個事件監聽器 按鈕。請注意我們如何通過將新待辦事項的提交率限制為每 5 秒一個來防止氾濫。

    有了這個,我們的 AJAX 待辦事項列表就完成了!

    結論

    今天,我們使用 PHP、MySQL 和 jQuery 創建了一個簡單的啟用 AJAX 的 ToDo Web 腳本。您可以使用它來創建自己的任務管理應用程序或將其變成一個成熟的網絡應用程序。

    你怎麼看?您將如何修改此代碼?


  • Tutorial JavaScript 教程
    1. 異步 JavaScript - 我如何理解它。

    2. 反應 VS Vue.js

    3. JSByte:如何在 JavaScript 中檢查 null 或 undefined 的虛假值

    4. 使用 DHTML 文章創建彈出式註釋

    5. 以編程方式使用 NPM

    6. 網上商店考試項目

    7. 理解 ECMAScript 規範,第 3 部分

    1. 使用 HTML5 Async 和 Defer 加載非阻塞 JavaScript

    2. JavaScript 中的換行符

    3. 向我解釋 Angular

    4. 會話和 Cookie 以及(本地)存儲,哦,天哪!

    5. 如何僅使用 javascript 將 blob url 轉換為字節數組

    6. 將 SASS 添加到 create-react-app

    7. 如何使用 JavaScript 檢測我的瀏覽器版本和操作系統?

    1. 了解 useEffect、useRef 和自定義 Hooks

    2. 使用 javascript、html、css 的井字遊戲

    3. 使用 react 創建一個類似 freecodecamp 的網站

    4. 在 arcgis js api 4.x 中通過當前點坐標、角度和距離獲取新的點坐標