javaScript是一種解釋型語言,它的執行是自上而下,但是各個瀏覽器對于至上而下的理解是有細微差別的,而代碼的上下游也就是程序流又對于程序正確至關重要。
首先得了解有幾種方法能把javaScript加入到頁面中? 常見下述的前2種,其實還有更多。
1.頁面中直接引入外部js文件:<script src="my.js"></script>
2.頁面中直接寫入 js片段: <script>alert(1)</script>
3.在js中引入js文件(比較少用): document.write("<scr"+"ipt src='my.js'></scr"+"ipt>");
注意:這時候"..</script>"必須拆成"</scr"+"ipt>",否則瀏覽器可能會把父js片段關閉掉,出錯;
4.同樣在js中引用其他js片段,document.write("<scr"+"ipt>alert(1)</scr"+"ipt>");
你可能覺得這個并沒有必要,既然已經在script中了還套一層干嘛?呵呵,怎么說也是一種寫法,而且它具有其特殊的行為,稍后我們討論到。
5.使用Ajax中的xmlHttpRequest結合eval()來引入js,我最早在Dojo的代碼見到,寫的詳細些:
var ajaxRequest=getXmlHttpRequest()//省去各個瀏覽器得到xmlHttpRequest的部門
ajaxRequest.open("GET","my.js",false);//使用xmlHttpRequest對象Get方法的同步調用
ajaxRequest.send(null);
sJsFragment=ajax.responseText;//得到字符串為js片段
eval(sJsFragment);//執行js片段
注意:這里要求my.js即后來的sJsFragment內容得是非常規范的js,且沒有//開頭的注釋,怎樣檢查js是否規范呢?去http://jslint.com/
6.無所不能的Dom方法,非常好用:
var oScript=document.createElement("script");//創建一個Script元素
oScript.src="my.js";//制定src屬性
document.getElementsByTagName("head")[0].appendChild(oScript);
說明:my.js的內容會在oScript加入到文檔中之后獲得并執行。仔細看下這段容易發現這個調用是異步的,可以在文檔載入之后通過事件觸發,我用它變通了一下,作為了xmlHttpRequest的Get方法在跨域取數時的替代,獲得了很完美的效果,以后有機會專門寫篇文。
六種不少吧,可能還會有吧,而且這幾種之間還可能相互嵌套,變化無常。
其中1、2、4、6種方式引入的javaScript的執行順序是非常自然的,隨著頁面的載入以及后續的事件觸發,它們遵守先來后到、而其內部自上而下。
現代web開發中,表單是用戶與網站互動的重要方式之一。HTML5為表單提交提供了強大的功能和豐富的輸入類型,讓收集和驗證用戶輸入數據變得更加容易和安全。本文將詳細介紹HTML5表單的各個方面,包括基本結構、輸入類型、驗證方法和提交過程。
HTML表單由<form>標簽定義,它可以包含輸入字段、標簽、按鈕等元素。一個基本的表單結構如下所示:
<form action="/submit_form" method="post">
<label for="name">姓名:</label>
<input type="text" id="name" name="name" required>
<label for="email">電子郵箱:</label>
<input type="email" id="email" name="email" required>
<input type="submit" value="提交">
</form>
在這個例子中,表單有兩個輸入字段:姓名和電子郵箱。每個輸入字段都有一個<label>標簽,這不僅有助于用戶理解輸入的內容,也有助于屏幕閱讀器等輔助技術。<form>標簽的action屬性定義了數據提交到服務器的URL,method屬性定義了提交數據的HTTP方法(通常是post或get)。
HTML5提供了多種輸入類型,以支持不同的數據格式和設備。
<!-- 單行文本 -->
<input type="text" name="username" placeholder="請輸入用戶名" required>
<!-- 密碼 -->
<input type="password" name="password" required minlength="8">
<!-- 郵箱 -->
<input type="email" name="email" required placeholder="example@domain.com">
<!-- 搜索框 -->
<input type="search" name="search" placeholder="搜索...">
<!-- 數值 -->
<input type="number" name="age" min="18" max="100" step="1" required>
<!-- 滑動條 -->
<input type="range" name="volume" min="0" max="100" step="1">
<!-- 電話號碼 -->
<input type="tel" name="phone" pattern="^\+?\d{0,13}" placeholder="+8613800000000">
<!-- 日期 -->
<input type="date" name="birthdate" required>
<!-- 時間 -->
<input type="time" name="appointmenttime">
<!-- 日期和時間 -->
<input type="datetime-local" name="appointmentdatetime">
<!-- 復選框 -->
<label><input type="checkbox" name="interest" value="coding"> 編程</label>
<label><input type="checkbox" name="interest" value="music"> 音樂</label>
<!-- 單選按鈕 -->
<label><input type="radio" name="gender" value="male" required> 男性</label>
<label><input type="radio" name="gender" value="female"> 女性</label>
<!-- 下拉選擇 -->
<select name="country" required>
<option value="china">中國</option>
<option value="usa">美國</option>
</select>
<!-- 顏色選擇器 -->
<input type="color" name="favcolor" value="#ff0000">
<!-- 文件上傳 -->
<input type="file" name="resume" accept=".pdf,.docx" multiple>
HTML5表單提供了內置的驗證功能,可以在數據提交到服務器之前進行檢查。
<input type="text" name="username" required>
<input type="text" name="zipcode" pattern="\d{5}(-\d{4})?" title="請輸入5位數的郵政編碼">
<input type="number" name="age" min="18" max="99">
<input type="text" name="username" minlength="4" maxlength="8">
當用戶填寫完表單并點擊提交按鈕時,瀏覽器會自動檢查所有輸入字段的有效性。如果所有字段都滿足要求,表單數據將被發送到服務器。否則,瀏覽器會顯示錯誤信息,并阻止表單提交。
<input type="submit" value="提交">
可以使用JavaScript來自定義驗證或處理提交事件:
document.querySelector('form').addEventListener('submit', function(event) {
// 檢查表單數據
if (!this.checkValidity()) {
event.preventDefault(); // 阻止表單提交
// 自定義錯誤處理
}
// 可以在這里添加額外的邏輯,比如發送數據到服務器的Ajax請求
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表單提交并顯示JSON</title>
</head>
<body>
<!-- 表單定義 -->
<form id="myForm">
<label for="name">姓名:</label>
<input type="text" id="name" name="name">
<br>
<label for="email">電子郵件:</label>
<input type="email" id="email" name="email">
<br>
<input type="button" value="提交" onclick="submitForm()">
</form>
<script>
// JavaScript函數,處理表單提交
function submitForm() {
// 獲取表單元素
var form=document.getElementById('myForm');
// 創建一個FormData對象
var formData=new FormData(form);
// 創建一個空對象來存儲表單數據
var formObject={};
// 將FormData轉換為普通對象
formData.forEach(function(value, key){
formObject[key]=value;
});
// 將對象轉換為JSON字符串
var jsonString=JSON.stringify(formObject);
// 彈出包含JSON字符串的對話框
alert(jsonString);
// 阻止表單的默認提交行為
return false;
}
</script>
</body>
</html>
在這個例子中:
注意,這個例子中我們使用了type="button"而不是type="submit",因為我們不希望表單有默認的提交行為。我們的JavaScript函數submitForm會處理所有的邏輯,并且通過返回false來阻止默認的表單提交。如果你想要使用type="submit",你需要在<form>標簽上添加一個onsubmit="return submitForm()"屬性來代替按鈕上的onclick事件。
HTML5的表單功能為開發者提供了強大的工具,以便創建功能豐富、用戶友好且安全的網站。通過使用HTML5的輸入類型和驗證方法,可以確保用戶輸入的數據是有效的,同時提高用戶體驗。隨著技術的不斷進步,HTML5表單和相關API將繼續發展,為前端工程師提供更多的可能性。
最近筆者終于把H5-Dooring的后臺管理系統初步搭建完成, 有了初步的數據采集和數據分析能力, 接下來我們就復盤一下其中涉及的幾個知識點,并一一闡述其在Dooring H5可視化編輯器中的解決方案. 筆者將分成3篇文章來復盤, 主要解決場景如下: 如何使用JavaScript實現前端導入和導出excel文件(H5編輯器實戰復盤) 前端如何基于table中的數據一鍵生成多維度數據可視化分析報表 * 如何實現會員管理系統下的權限路由和權限菜單
以上場景也是前端工程師在開發后臺管理系統中經常遇到的或者即將遇到的問題, 本文是上述介紹中的第一篇文章, 你將收獲: 使用JavaScript實現前端導入excel文件并自動生成可編輯的Table組件 使用JavaScript實現前端基于Table數據一鍵導出excel文件 * XLSX和js-export-excel基本使用
本文接下來的內容素材都是基于H5可視化編輯器(H5-Dooring)項目的截圖, 如果想實際體驗, 可以訪問H5-Dooring網站實際體驗. 接下來我們直接開始我們的方案實現.
在開始實現之前, 我們先來看看實現效果.
導入excel文件并通過antd的table組件渲染table:
編輯table組件:
保存table數據后實時渲染可視化圖表:
以上就是我們實現導入excel文件后, 編輯table, 最后動態生成圖表的完整流程.
導入excel文件的功能我們可以用javascript原生的方式實現解析, 比如可以用fileReader這些原生api,但考慮到開發效率和后期的維護, 筆者這里采用antd的Upload組件和XLSX來實現上傳文件并解析的功能. 由于我們采用antd的table組件來渲染數據, 所以我們需要手動將解析出來的數據轉換成table支持的數據格式.大致流程如下:
所以我們需要做的就是將Upload得到的文件數據傳給xlsx, 由xlsx生成解析對象, 最后我們利用javascript算法將xlsx的對象處理成ant-table支持的數據格式即可. 這里我們用到了FileReader對象, 目的是將文件轉化為BinaryString, 然后我們就可以用xlsx的binary模式來讀取excel數據了, 代碼如下:
// 解析并提取excel數據
let reader=new FileReader();
reader.onload=function(e) {
let data=e.target.result;
let workbook=XLSX.read(data, {type: 'binary'});
let sheetNames=workbook.SheetNames; // 工作表名稱集合
let draftObj={}
sheetNames.forEach(name=> {
// 通過工作表名稱來獲取指定工作表
let worksheet=workbook.Sheets[name];
for(let key in worksheet) {
// v是讀取單元格的原始值
if(key[0] !=='!') {
if(draftObj[key[0]]) {
draftObj[key[0]].push(worksheet[key].v)
}else {
draftObj[key[0]]=[worksheet[key].v]
}
}
}
});
// 生成ant-table支持的數據格式
let sourceData=Object.values(draftObj).map((item,i)=> ({ key: i + '', name: item[0], value: item[1]}))
經過以上處理, 我們得到的sourceData即是ant-table可用的數據結構, 至此我們就實現了表格導入的功能.
table表格的編輯功能實現其實也很簡單, 我們只需要按照antd的table組件提供的自定義行和單元格的實現方式即可. antd官網上也有實現可編輯表格的實現方案, 如下:
大家感興趣的可以研究一下. 當然自己實現可編輯的表格也很簡單, 而且有很多方式, 比如用column的render函數來動態切換表格的編輯狀態, 或者使用彈窗編輯等都是可以的.
根據table數據動態生成圖表這塊需要有一定的約定, 我們需要符合圖表庫的數據規范, 不過我們有了table數據, 處理數據規范當然是很簡單的事情了, 筆者的可視化庫采用antv的f2實現, 所以需要做一層適配來使得f2能消費我們的數據.
還有一點就是為了能使用多張圖表, 我們需要對f2的圖表進行統一封裝, 使其成為符合我們應用場景的可視化組件庫.
我們先看看f2的使用的數據格式:
const data=[
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 }
];
此數據格式會渲染成如下的圖表:
所以說我們總結下來其主要有2個緯度的指標, 包括它們的面積圖, 餅圖, 折線圖, 格式都基本一致, 所以我們可以基于這一點封裝成組件的可視化組件, 如下:
import { Chart } from '@antv/f2';
import React, { memo, useEffect, useRef } from 'react';
import ChartImg from '@/assets/chart.png';
import styles from './index.less';
import { IChartConfig } from './schema';
interface XChartProps extends IChartConfig {
isTpl: boolean;
}
const XChart=(props: XChartProps)=> {
const { isTpl, data, color, size, paddingTop, title }=props;
const chartRef=useRef(null);
useEffect(()=> {
if (!isTpl) {
const chart=new Chart({
el: chartRef.current || undefined,
pixelRatio: window.devicePixelRatio, // 指定分辨率
});
// step 2: 處理數據
const dataX=data.map(item=> ({ ...item, value: Number(item.value) }));
// Step 2: 載入數據源
chart.source(dataX);
// Step 3:創建圖形語法,繪制柱狀圖,由 genre 和 sold 兩個屬性決定圖形位置,genre 映射至 x 軸,sold 映射至 y 軸
chart
.interval()
.position('name*value')
.color('name');
// Step 4: 渲染圖表
chart.render();
}
}, [data, isTpl]);
return (
<div className={styles.chartWrap}>
<div className={styles.chartTitle} style={{ color, fontSize: size, paddingTop }}>
{title}
</div>
{isTpl ? <img src={ChartImg} alt="dooring chart" /> : <canvas ref={chartRef}></canvas>}
</div>
);
};
export default memo(XChart);
當然其他的可視化組件也可以用相同的模式封裝,這里就不一一舉例了. 以上的組件封裝使用react的hooks組件, vue的也類似, 基本原理都一致.
同樣的, 我們實現將table數據一鍵導出為excel也是類似, 不過方案有所不同, 我們先來看看在Dooring中的實現效果.
以上就是用戶基于后臺采集到的數據, 一鍵導出excel文件的流程, 最后一張圖是生成的excel文件在office軟件中的呈現.
一鍵導出功能主要用在H5-Dooring的后臺管理頁面中, 為用戶提供方便的導出數據能力. 我們這里導出功能也依然能使用xlsx來實現, 但是綜合對比了一下筆者發現有更簡單的方案, 接下來筆者會詳細介紹, 首先我們還是來看一下流程:
很明顯我們的導出流程比導入流程簡單很多, 我們只需要將table的數據格式反編譯成插件支持的數據即可. 這里筆者使用了js-export-excel來做文件導出, 使用它非常靈活,我們可以自定義: 自定義導出的excel文件名 自定義excel的過濾字段 * 自定義excel文件中每列的表頭名稱
由于js-export-excel支持的數據結構是數組對象, 所以我們需要花點功夫把table的數據轉換成數組對象, 其中需要注意的是ant的table數據結構中鍵對應的值可以是數組, 但是js-export-excel鍵對應的值是字符串, 所以我們要把數組轉換成字符串,如[a,b,c]變成'a,b,c', 所以我們需要對數據格式進行轉換, 具體實現如下:
const generateExcel=()=> {
let option={}; //option代表的就是excel文件
let dataTable=[]; //excel文件中的數據內容
let len=list.length;
if (len) {
for(let i=0; i<len; i++) {
let row=list[i];
let obj:any={};
for(let key in row) {
if(typeof row[key]==='object') {
let arr=row[key];
obj[key]=arr.map((item:any)=> (typeof item==='object' ? item.label : item)).join(',')
}else {
obj[key]=row[key]
}
}
dataTable.push(obj); //設置excel中每列所獲取的數據源
}
}
let tableKeys=Object.keys(dataTable[0]);
option.fileName=tableName; //excel文件名稱
option.datas=[
{
sheetData: dataTable, //excel文件中的數據源
sheetName: tableName, //excel文件中sheet頁名稱
sheetFilter: tableKeys, //excel文件中需顯示的列數據
sheetHeader: tableKeys, //excel文件中每列的表頭名稱
}
]
let toExcel=new ExportJsonExcel(option); //生成excel文件
toExcel.saveExcel(); //下載excel文件
}
注意, 以上筆者實現的方案對任何table組件都使用, 可直接使用以上代碼在大多數場景下使用. 至此, 我們就實現了使用JavaScript實現前端導入和導出excel文件的功能.
所以, 今天你又博學了嗎?
以上教程筆者已經集成到H5-Dooring中,對于一些更復雜的交互功能,通過合理的設計也是可以實現的,大家可以自行探索研究。
地址:H5-Dooring | 一款強大的H5編輯器
如果想學習更多H5游戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數據可視化等前端知識和實戰,歡迎在《趣談前端》一起學習討論,共同探索前端的邊界。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。