首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >简单html5 5/javascript web数据库应用程序前端

简单html5 5/javascript web数据库应用程序前端
EN

Code Review用户
提问于 2020-04-26 17:38:03
回答 1查看 386关注 0票数 3

这个应用程序是一个非常基本的数据库应用程序的前端。前端假设后端数据库将具有与html表单相同的字段。

我对db2form.js的一些关注是:

  1. javascript中的一些非常具体的html文档引用-例如document.forms.searchform.elements.search.innerText = "Search";
  2. current_contact_idx全局变量似乎不正确。

至于css文件,可能会有很大的改进。

对此申请有任何反馈将是非常欢迎的。

html页面:

代码语言:javascript
复制
  Itel Office
  



  
  
    
      Contacts
      Call Log
    
    
      Contacts

  Enter text below and click Search button to find a contact
  
  ID: 
  


  Name: 
  


Company: 




Email: 



Telephone: 



Mobile: 



alt Telephone: 



Web: 



Address line 1: 



Address line 2: 



Address line 3: 



Address line 4: 



Postcode: 



Category: 



Notes: 





Search

New

Edit
Save
Delete

First
Next
Prior
Last

css文件style.css:

代码语言:javascript
复制
body{
    background-color: #ffff00;
}

nav{
    box-sizing:border-box;
    background-color:#409fff;  /* blue we like */
    display: inline-block;
    width: 20%;
    min-width: 125px;
    margin-right:15px;
    height:100vh;
    overflow: auto;
}

nav a{
    display:block;
    line-height: 45px;
    height:45px;
    color: #FFFFFF;
    text-decoration: none;
    padding-left: 50px;
    margin:10px 0 10px 5px;
}

section{
    display: inline-block;
    width:70%;
    height:100vh;
    overflow: auto;
}

h1{
     color: #409fff;
     padding: 2px;
     margin: 0;
}

form {
    display: grid;
     grid-template-columns: 150px 1fr;
     border: 0;
}

label {
    grid-column: 1 / 2;
    margin: 0;
    padding:0;
     border: 0;
}

input{
    grid-column: 2 / 3;
    margin: 0;
    padding:0;
     border: 0;
     border-radius: 5px;
}

/*input:focus{
     background-color: #fcfab1;
}
*/
textarea{
     border-radius: 5px;
     height: 20px;
}


.buttons{
     display: grid;

     grid-column: 2 / 3;
     grid-gap: 10px;
     grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}

javascript文件db2form.js:

代码语言:javascript
复制
let current_contact_idx = -1;
let records = null;

function search_mode() {
    // now change button to say Search
    document.forms.searchform.elements.search.innerText = "Search";
    document.forms.searchform.elements.new.disabled = false;

    document.forms.searchform.elements.edit.disabled = true;
    document.forms.searchform.elements.save.disabled = true;
    document.forms.searchform.elements.delete.disabled = true;

    document.forms.searchform.elements.first.disabled = true;
    document.forms.searchform.elements.next.disabled = true;
    document.forms.searchform.elements.prior.disabled = true;
    document.forms.searchform.elements.last.disabled = true;
}

function found_mode() {
    // now change button to say Cancel
    document.forms.searchform.elements.search.innerText = "Cancel";
    document.forms.searchform.elements.new.disabled = false;

    document.forms.searchform.elements.edit.disabled = false;
    document.forms.searchform.elements.save.disabled = true;
    document.forms.searchform.elements.delete.disabled = false;

    document.forms.searchform.elements.first.disabled = false;
    document.forms.searchform.elements.next.disabled = false;
    document.forms.searchform.elements.prior.disabled = false;
    document.forms.searchform.elements.last.disabled = false;
}

function new_edit_mode() {
    // now change button to say Cancel
    document.forms.searchform.elements.search.innerText = "Cancel";
    document.forms.searchform.elements.new.disabled = true;

    document.forms.searchform.elements.edit.disabled = true;
    document.forms.searchform.elements.save.disabled = false;
    document.forms.searchform.elements.delete.disabled = true;

    document.forms.searchform.elements.first.disabled = true;
    document.forms.searchform.elements.next.disabled = true;
    document.forms.searchform.elements.prior.disabled = true;
    document.forms.searchform.elements.last.disabled = true;
}

function server_response_callback_search(ajax) {

    let form_elements = document.forms.searchform.elements;

     if(ajax.responseText.length == 0) {
        cancel_step(form_elements);
        document.getElementById('status').innerHTML = "No record found for your search." 
        return;
    }

     console.log("server_response_callback_search response type: " + ajax.getResponseHeader('content-type'));

    records = JSON.parse(ajax.responseText);
    if (records.contacts.length > 0) {
          current_contact_idx = 0;
        populate_field(records.contacts[current_contact_idx]);

        found_mode();
    } else {
        current_contact_idx = -1;  // reset to no record found
          search_mode();  // stay in search mode
     }

    // display message
    if (current_contact_idx == -1) {
        document.getElementById('status').innerHTML = "No record found which matches the criteria";
    } else {
        document.getElementById('status').innerHTML = "Displaying record " + (current_contact_idx + 1).toString() + " of " + records.contacts.length;
    }
}

function server_response_callback_update(ajax, rowid) {

     console.log("server_response_callback_update response type: " + ajax.getResponseHeader('content-type'));
    let form_elements = document.forms.searchform.elements;

    search_mode();

    // empty all input and textarea fields
    for (let element of form_elements) {
        if(element.type != 'hidden') {
            element.value = "";
        }
    }

    document.getElementById('status').innerHTML = ajax.responseText;;
}

function server_response_callback_insert(ajax) {

     console.log("server_response_callback_insert response type: " + ajax.getResponseHeader('content-type'));
    let form_elements = document.forms.searchform.elements;

    search_mode();

    // empty all input and textarea fields
    for (let element of form_elements) {
        if(element.type != 'hidden') {
            element.value = "";
        }
    }

    document.getElementById('status').innerHTML = ajax.responseText;
}


// We need to display what it is that database.exe returns for these cases

function server_response_callback_delete(ajax, rowid) {
     console.log("server_response_callback_delete response type: " + ajax.getResponseHeader('content-type'));
    let form_elements = document.forms.searchform.elements;

    search_mode();

    // empty all input and textarea fields
    for (let element of form_elements) {
        if(element.type != 'hidden') {
            element.value = "";
        }
    }

    document.getElementById('status').innerHTML = ajax.responseText;
}

function populate_field(element) {
    let formelements = document.forms.searchform.elements;

    // formelements is an array
     for (let i = 0; i < formelements.length; i++) {
          if (formelements[i].name in element) {
            formelements[i].value = element[formelements[i].name];
          } else {
                formelements[i].value = "";
          }
     }
     document.getElementById('status').innerHTML = "Displaying record " + (current_contact_idx + 1).toString() + " of " + records.contacts.length;
}

function edit_step() {
     new_edit_mode();
}

function cancel_step(form_elements) {
     search_mode();

    // empty all input and textarea fields
    for (let element of form_elements) {
        if(element.type != 'hidden') {
            element.value = "";
        }
    }
    document.getElementById('status').innerHTML = "";
}

function new_step(form_elements) {
    new_edit_mode();

    // empty all input and textarea fields
    for (let element of form_elements) {
        if(element.type != 'hidden') {
            element.value = "";
        }
    }
    document.getElementById('status').innerHTML = "Enter data for new contact, then click Save button to save to database";
}

function extract_form_values(form_elements) {
    let query = "";
    let first = "yes";
    for (let element of form_elements) {
        if(["text", "textarea", "tel", "email"].includes(element.type)) {
            if(first == "no") {
                query += "&";
            }
            first = "no";
            query += element.name;
            query += "=";
            query += element.value;
        }
    }
    return query;
}

function save_step(form_elements) {
    let request_payload = extract_form_values(form_elements);
    if(request_payload.length == 0) {
        //alert("You need to enter some data to save to database");
        document.getElementById('status').innerHTML = "You need to enter some data to save to database";
        return;
    }

    // we determine whether to UPDATE or INSERT based on presence of rowid.
     // if a rowid assume updating an existing contact, otherwise a new contact
    if (document.forms.searchform.elements.rowid.value == "") {
       // go down INSERT route
        // remove rowid= from payload
          let pos = request_payload.indexOf("rowid=&");
          if (pos != -1) {
            // remove string
                request_payload = request_payload.replace("rowid=&", "");
          }
        request_payload += "&operation=INSERT";
        console.log("sending query to database server: " + request_payload);

        // setup ajax callback to handle response
        ajax_post("/cgi-bin/database.exe", request_payload, server_response_callback_insert);

     } else {
        let rowid = parseInt(document.forms.searchform.elements.rowid.value, 10);

        request_payload += "&operation=UPDATE";
        console.log("sending query to database server: " + request_payload);

        // setup ajax callback to handle response
        ajax_post("/cgi-bin/database.exe", request_payload, server_response_callback_update, rowid);
     }
}

function has_values(form_elements) {

     for (let element of form_elements) {
        if(["text", "textarea", "tel", "email"].includes(element.type) && element.name != "rowid" && element.value != "") {
            return true;
          }
     }
     return false;
}

function insert_step(form_elements) {

     // check user actually entered some data in fields
     if(!has_values(form_elements)) {
        console.log("attempting to insert but no values populated");
          document.getElementById('status').innerHTML = "Enter contact details to add a new contact";
          return;
     }

    let request_payload = extract_form_values(form_elements);
    if(request_payload.length == 0) {
        document.getElementById('status').innerHTML = "You need to enter some update a contact";
        return;
    }

    request_payload += "&operation=INSERT";
    console.log("sending query to database server: " + request_payload);

    // setup ajax callback to handle response
    ajax_post("/cgi-bin/database.exe", request_payload, server_response_callback_insert);
}

function search_step(form_elements) {
    let query = extract_form_values(form_elements);
    query += query.length == 0 ? "operation=SELECT" : "&operation=SELECT";
    console.log("sending query to database server: " + query);

    // setup ajax callback to handle response
    ajax_post("/cgi-bin/database.exe", query, server_response_callback_search);
}

function ajax_post(url, request, callback, arg) {
    // setup ajax callback to handle response
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            callback(this, arg);
        }
    };

    xhttp.open("POST", url, true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send(request);
}

function delete_step(form_elements) {

     if(form_elements.rowid.value == "") {
          const delete_msg = "Form not in correct state to delete a contact";
          document.getElementById('status').innerHTML = delete_msg;
        alert(delete_msg);
          return;
     }

     let rowid = parseInt(form_elements.rowid.value, 10);

     // DELETE FROM table_name WHERE condition;
     let request = `rowid=${rowid}&operation=DELETE`;
    console.log("sending request to database server: " + request);

     let confirmation = confirm("Click Ok if you are absolutely sure you want to delete this contact from the database");
    if (confirmation) {
        // setup ajax callback to handle response
        ajax_post("/cgi-bin/database.exe", request, server_response_callback_delete, rowid);
    }
}

function process(buttontext) {
    console.log(`buttontext=${buttontext}`);

    let form_elements = document.forms.searchform.elements;

     if (buttontext == "New") {
        new_step(form_elements);
    }else if (buttontext == "Edit") {
        edit_step();
    } else if (buttontext == "Save") {
        save_step(form_elements);
    } else if (buttontext == "Search") {
        search_step(form_elements);
    } else if (buttontext == "Cancel") {
        cancel_step(form_elements);
     } else if (buttontext == "Delete") {
          delete_step(form_elements);
     } else if (buttontext == "First") {
          if (records.contacts.length != 0) {
                current_contact_idx = 0;
            populate_field(records.contacts[current_contact_idx]);
          }
     } else if (buttontext == "Next") {
          if (records.contacts.length > (current_contact_idx + 1)) {
                populate_field(records.contacts[++current_contact_idx]);
          } else {
                document.getElementById('status').innerHTML = "You are on the last record";
          }
     } else if (buttontext == "Prior") {
          if (current_contact_idx > 0) {
                populate_field(records.contacts[--current_contact_idx]);
          } else {
                document.getElementById('status').innerHTML = "You are on the first record";
          }
     } else if (buttontext == "Last") {
          if (records.contacts.length != 0) {
                current_contact_idx = records.contacts.length - 1;
            populate_field(records.contacts[current_contact_idx]);
          }
    } else {
        document.getElementById('status').innerHTML = "something has gone wrong - button text incorrectly set";
    }
}

// user can press Enter key to invoke search, Esc key to cancel (go back to ready to search mode)
document.onkeydown = function(evt) {
    evt = evt || window.event;
    var isEscape = false;
     var isEnter = false;
    if ("key" in evt) {
        isEscape = (evt.key === "Escape" || evt.key === "Esc");
        isEnter = (evt.key === "Enter");
    } else {
        isEscape = (evt.keyCode === 27);
        isEnter = (evt.keyCode === 13);
    }
    if (isEscape) {
        // only handle Escape if Cancel button enabled
        if(document.forms.searchform.elements.search.innerText == "Cancel") {
            process("Cancel");
        }
    } else if (isEnter) {
        // only handle Enter if Search button enabled
        if(document.forms.searchform.elements.search.innerText == "Search") {
            process("Search");
        }
    }
};
EN

回答 1

Code Review用户

回答已采纳

发布于 2020-04-27 01:12:12

在Javascript方面:

不要使用内联处理程序,它们有值得使用的太多的问题了。相反,使用Javascript和addEventListener附加侦听器。

由于每次单击包含Search的按钮,您都希望将按钮的文本内容传递给process,因此可以通过检查处理程序中单击按钮的textContent来简洁地完成此操作。

通常最好使用querySelector (它接受简洁、灵活的CSS字符串)来选择元素,而不是通过document.forms

代码语言:javascript
复制
document.querySelector('.buttons').addEventListener('click', ({ target }) => {
  if (!target.matches('button')) return;
  process(target.textContent);
});

使用上述代码将允许您从.buttons > button元素(包括onclick="process(document.forms.searchform.elements.search.innerText)" )中删除所有内联处理程序。

代码语言:javascript
复制
const process = console.log;
document.querySelector('.buttons').addEventListener('click', ({ target }) => {
  if (!target.matches('button')) return;
  process(target.textContent);
});
代码语言:javascript
复制
  Search
  New
  Edit
  Save
  Delete
  First
  Next
  Prior
  Last

最好使用textContent,这是从元素中提取文本的标准方法,而不是innerText,这是Internet中具有相当奇怪的行为的一种特殊属性。innerText几乎从来都不是你想要的。

与其在search_modefound_modenew_edit_mode中一次又一次地选择按钮,不如考虑选择它们一次,然后构造一个按元素类型索引的对象:

代码语言:javascript
复制
const buttons = {};
for (const button of document.querySelectorAll('.buttons > button')) {
  buttons[button.textContent.toLowerCase()] = button;
}

function enableDisableButtons(newVal) {
  for (const button of buttons) {
    button.disabled = newVal;
  }
}
function search_mode() {
  buttons.search.textContent = 'Search';
  enableDisableButtons(true);
  buttons.new.disabled = false;
}

function found_mode() {
  buttons.search.textContent = 'Cancel';
  enableDisableButtons(false);
  buttons.save.disabled = true;
}

function new_edit_mode() {
  buttons.search.textContent = 'Cancel';
  enableDisableButtons(true);
  buttons.save.disabled = false;
}

您还可以保存对status元素的引用,而不是经常重新选择它。

代码语言:javascript
复制
const status = document.querySelector('#status');
// ...
status.innerHTML = "Displaying record " + (current_contact_idx + 1).toString() + " of " + records.contacts.length;

上面的代码还指出了另一个问题--除非您有意插入HTML,否则应该通过分配给textContent而不是innerHTML来设置元素的文本内容。如果代码不可信,使用innerHTML可能会导致任意代码的执行,此外,它比textContent慢,而且对脚本阅读器来说更令人困惑。所以,对于上面的内容,你应该选择

代码语言:javascript
复制
status.textContent = "Displaying record " + (current_contact_idx + 1).toString() + " of " + records.contacts.length;

在您的process函数中,而不是对参数进行大量的if/else检查,您可以考虑使用按钮文本索引对象,当需要处理该按钮时,它的值就是您想要运行的函数。在处理程序中,只需查找对象上的函数并运行它:

代码语言:javascript
复制
const actionsByButtonText = {
  New: new_step,
  Edit: edit_step,
  Save: save_step,
  // ...
};
function process(buttontext) {
  console.log(`buttontext=${buttontext}`);
  const fn = actionsByButtonText[buttontext];
  if (fn) fn();
  else status.textContent = "something has gone wrong - button text incorrectly set";
}

(不需要将form_elements传递给这些函数--它们可以迭代上面的buttons对象,这作为一个参数没有多大意义,因为它永远不会改变)

在声明变量时,默认情况下您使用的是let。对总用const最好--除非您必须重新分配,否则不要使用let,并且永远不要使用var (就像在您的ajax_post中)。使用const向脚本的后续读者(包括您)指出,变量名称永远不会重新分配,这比允许使用let重新分配要少一些认知开销。

在Javascript中,变量几乎总是使用camelCase命名的,如果您想要遵循它,您可能需要考虑它。

这个脚本有点长--最初是371行。一旦您有了一个具有超过3-4个函数的脚本,我会强烈考虑使用模块来组织它。拥有单独的模块,每个模块都有自己的功能,比拥有一个大文件更易于维护。模块也很有用,因为它们之间的依赖是显式的,而不是所有的东西都是全局的,并且有可能引用其他所有的东西--当代码不是微不足道的时候,这可能会使事情变得有点混乱。看看像webpack这样的东西。

您还应该考虑在HTML中使用适当的缩进,这样可以使结构更加可读性。这个例子:

代码语言:javascript
复制
    Contacts

Enter text below and click Search button to find a contact

ID: 
很可能是

  Contacts
  Enter text below and click Search button to find a contact
  
    ID: 
    
    ...还有其他的改进也可以做,但这应该是一个良好的开端。
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/241259

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档