form 元素及表单能做的那些事

2021/01/09 HTML 共 4624 字,约 14 分钟

背景

一个项目上线前期张老师排除打包问题的时候恰巧看到了我的代码。代码功能实现没有任何问题,但是一点都不优雅,还存在潜在的问题,张老师悉心指导,手把手教我编程。结果是代码结构变了,代码逻辑减少了一般,且特别优雅,我震惊了,入职三个月左右,get 到了特别特别多的东西,真的特别特别感谢张老师的指导,自己的基础明显的感觉到了提升。这就是我学习 form 表单契机。选择比努力,特别是遇到一个好的领导的时候

form 的热身活动

最近在学习lulu ui的源码,lulu ui 的理念就是用美化原生的标签属性,所有的操作都属于原生操作,这个就对基础有要求了。恰巧我在源码里面看到了一个

<form id="form">
// 这里很多内容
</form>


// 下面这一段不再form表单里面。在页面任何位置
<button form="form" type="submit">提交</button>
<button form="form" type="reset">重置</button>

当时我有点懵逼,button 都隔了那么远,还能控制form的提交,而且上面有一个我没用过的 form=”form” ,只要type=”submit”,就会自动提交,如果type=”reset”,点击按钮自动清空表单数据,不需要任何js控制

表单原生 html5 新特性: 就是表单元素上面加一个form 属性,值是指定form表单的id,他们之间就能够关联起来。效果和写在form表单里面一样的

在线demo体验

看到这个form属性,我算是长见识了,原生标签真强大,后来我还知道了更多的

优化用户体验,再一次接触了

优化用户体验的时候我再一次接触到了表单元素,张老师看我代码的时候问我,那段代码干啥的,我说:”用户按回车键帮用户做提交事件“,我写了不少键盘判断事件和逻辑处理呢。在团队的氛围和感染下我也越来越重视用户体验了。我以为这回张老师要夸我了,谁知道他和我,这个代码删了吧,有的是原生标签帮你做这个事。

我懵了,因为我不知道,我知道可有可无的代码删了,多一行代码就可能多一个bug。在张老师的指导下,我改了。

就上面的那个在线demo,实现了tab键聚焦和return提交表单,去试试呗。就是当你操作了表单,并且表单有值,按回车键会自动提交表单。这个用户体验很nice,但是如果你用的不是表单的话,这就需要你自己做很多的js处理了。还有就是按tab键的时候表单元素会自动聚焦,若是鼠标或者触控板不好使的时候这个就特别管用的,正巧国家在推行无障碍访问,这就是了。如果不是表单元素需要你自己设置tabindex了,自己设置多此一举,浪费代码

label 和 input 组合也可以做很多事

有时候一些简单的操作并不需要用到form,用表单相关元素就可以解决了

比如:点击按钮修改某一行的数据

借用 label 修改数据

简简单单的几行css 就可以搞定很多事,我长知识了。这些是我以前没有接触过的,再张老师看我的代码的时候指出的问题

说起这个又有一个小故事:

<input is="ui-range" type="range">
<input type="range">

我想获取到第一个标签元素修改他的样式,我直接给她定义了一个class,同事见了我代码说直接属性选择器获取呀,我有点懵逼,我不会呀。我拉着同事和我说怎么写=> [is="ui-range"]{} 就可以了呀。居然可以这样,我问我同事是不是只要是元素上面自定义的属性都可以这样使用。他说是的,这时候张老师瞅过来说我一定是没有好好看他的书,这些他的书里都写到了。然后我就明白了这个东西,张老师还说,css属性是从右往左,input[type="range"] 这里的input是多余的,因为 [type="range"] 就是input元素,再在前面写,多余了,浪费代码。我懂了,背css面试的时候背的可溜了,自己写的时候就忘记了

form 表单提交指定格式数据

当我用form表单提交数据的时候,如果是get请求,所有的参数都会放在url的请求,显然有时候这个是不安全的,我们希望get请求,但是参数要放在请求头里面,那么如何处理呢?

逛公司乐享的时候,刚好看到了一篇文章,写的很不错,里面也讲了get请求如何实现参数的不同发送的方法

  1. 首先要阻止默认的请求方法
form.addEventListener("submit", (ev) => {
    ev.preventDefault();
    // 自己发请求
})
  1. 表单提交的数据类型

根据数据类型来划分,通常使用的表单提交数据格式大概有以下几种

formdata格式,=> 需要通过 FormData 创建

json格式,形如{ a:1,b:2,c=3 } => 在 new FormData 创建的基础之上

url字符串拼接,形如 a=1&b=2&c=3 => 这种不需要我们处理

formdata 格式

new FormData

var formData = new FormData(form); // form为表单对象
Object.defineProperty(HTMLFormElement.prototype, 'formdata', {
    get() {
        return new FormData(this);
    }
})

formdata 格式: 利用的是new FormData,获取表单上面的name属性

jsondata 格式

Object.defineProperty(HTMLFormElement.prototype, 'jsondata', {
    get() {
        const jsondata = {}
        const formdata = new FormData(this);
        formdata.forEach((value, key) => {
            if (!jsondata[key]) {
                jsondata[key] = formdata.getAll(key).length > 1 ? formdata.getAll(key) : formdata.get(key);
            }
        });
        return jsondata;
    }
})

设置 jsondata 的格式:利用的是new FormData,获取表单上面的name属性

urldata 格式

/* urldata */
Object.defineProperty(HTMLFormElement.prototype, 'urldata', {
    get() {
        const urldata = [];
        Object.entries(this.jsondata).forEach(([key, value]) => {
            urldata.push(key + '=' + (value.join ? value.join() : value))
        })
        return urldata.join('&');
    }
})

urldata 格式 :利用的是new FormData,获取表单上面的name属性

扩展

选中事件

  1. 用户选中了input或者textarea里面的所有内容

select:选择某些文本时会触发事件 <input value="Try selecting some text in this element.">

input.select() 被调用的时候会选中所有的文本

  1. 用户选中文本框里面的某些内容,具体的某些内容,可用 Window.getSelection 替换,他的功能更加强大
input.addEventListener('select',function(event){
 //event.targe.selectionStart表示选中文本的起始位置,selectionEnd表示选中的终止位置
    let selectText = this.value.substring(
    event.targe.selectionStart, event.targe.selectionEnd
  );
})

扩展 Window.getSelection

  1. 可以实现选中的元素高亮变色
<span class="header-text">Put this in a headline</span>

const range = document.createRange();// 用document.createRange()创建选中的范围
const newParent = document.createElement('h1');
newParent.style.backgroundColor='red'
range.selectNode(document.querySelector('.header-text'));
range.surroundContents(newParent);

createRange

Range

selectionchange

  1. 选中的文本做一些事情,比如说分享js页面文字选中后分享到新浪微博实现
var $sinaMiniBlogShare = function(eleShare, eleContainer) {
    var eleTitle = document.getElementsByTagName("title")[0];
    eleContainer = eleContainer || document;
    var funGetSelectTxt = function() {
        var txt = "";
        if(document.selection) {
            txt = document.selection.createRange().text;    // IE
        } else {
            txt = document.getSelection();
        }
        return txt.toString();
    };
    eleContainer.onmouseup = function(e) {
        e = e || window.event;
        var txt = funGetSelectTxt(), sh = document.scrollingElement||0;
        var left = (e.clientX - 40 < 0) ? e.clientX + 20 : e.clientX - 40, top = (e.clientY - 40 < 0) ? e.clientY + sh + 20 : e.clientY + sh - 40;
        if (txt) {
            eleShare.style.display = "inline";
            eleShare.style.left = left + "px";
            eleShare.style.top = top + "px";
        } else {
            eleShare.style.display = "none";
        }
    };
    eleShare.onclick = function() {
        var txt = funGetSelectTxt(), title = (eleTitle && eleTitle.innerHTML)? eleTitle.innerHTML : "未命名页面";
        if (txt) {
            window.open('http://v.t.sina.com.cn/share/share.php?title=' + txt + '→来自页面"' + title + '"的文字片段&url=' + window.location.href);    
        }
    };
};

你以为form完了吗?

没有,光我这两天接触到的都还没写完,还有表单验证我没写了,估计要一篇文章。还有一些元素属性存在,但是我没用用过的,但是可以用的我还没有写呢


在技术的历史长河中,虽然我们素未谋面,却已相识已久,很微妙也很知足。互联网让世界变得更小,你我之间更近。

在逝去的青葱岁月中,虽然我们未曾相遇,却共同经历着一样的情愫。谁的青春不曾迷茫或焦虑亦是无奈,谁不曾年少过

在未来的日子里,让我们共享好的文章,共同学习进步。有不错的文章记得分享给我,我不会写好的文章,所以我只能做一个搬运工

我叫 sunseekers(张敏) ,千千万万个张敏与你同在,18年电子商务专业毕业,毕业后在前端搬砖

如果喜欢我的话,恰巧我也喜欢你的话,让我们手拉手,肩并肩共同前行,相互学习,互相鼓励

文档信息

Search

    Table of Contents