欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

uniapp開(kāi)發(fā)H5使用formData上傳文件解決方案

 更新時(shí)間:2023年12月06日 14:47:07   作者:QQ帝國(guó)  
我們很多時(shí)候上傳文件就是使用FormData,然而uniapp默認(rèn)不支持FormData類型數(shù)據(jù)的上傳,下面這篇文章主要給大家介紹了關(guān)于uniapp開(kāi)發(fā)H5使用formData上傳文件的相關(guān)資料,需要的朋友可以參考下

由于uniapp 的 uni.uploadFile 上傳的限制,無(wú)法實(shí)現(xiàn)上傳excel、world、ppt等類型的文件,不支持下圖的上傳方式,故只能調(diào)用原生的方法來(lái)解決。

解決方案

1、先創(chuàng)建一個(gè)原生上傳的組件

<template>
	<view class="lsj-file" :style="[getStyles]">
		<view ref="lsj" class="hFile" :style="[getStyles]" @click="onClick">
			<slot><view class="defview" :style="[getStyles]">上傳</view></slot>
		</view>
	</view>
</template>
 
<script>
import {LsjFile} from './LsjFile.js' 
export default {
	name: 'Lsj-upload',
	props: {
		// 打印日志
		debug: {type: Boolean,default: false},
		// 自動(dòng)上傳
		instantly: {type: Boolean,default: false},
		// 上傳接口參數(shù)設(shè)置
		option: {type: Object,default: ()=>{}},
		// 文件大小上限
		size: { type: Number, default: 10 },
		// 文件選擇個(gè)數(shù)上限,超出后不觸發(fā)點(diǎn)擊
		count: { type: Number, default: 9 },
		// 允許上傳的文件格式(多個(gè)以逗號(hào)隔開(kāi))
		formats: { type: String, default:''},
		// input file選擇限制
		accept: {type: String,default: ''},
		// 微信選擇文件類型 
		//all=從所有文件選擇,
		//video=只能選擇視頻文件,
		//image=只能選擇圖片文件,
		//file=可以選擇除了圖片和視頻之外的其它的文件
		wxFileType: { type: String, default: 'all' },
		// webviewID需唯一,不同窗口也不要同Id
		childId: { type: String, default: 'lsjUpload'  },
		// 文件選擇觸發(fā)面寬度
		width: { type: String, default: '100%' },
		// 文件選擇觸發(fā)面高度
		height: { type: String, default: '80rpx' },
		
		// top,left,bottom,right僅position=absolute時(shí)才需要傳入
		top: { type: [String, Number], default: '' },
		left: { type: [String, Number], default: '' },
		bottom: { type: [String, Number], default: '' },
		right: { type: [String, Number], default: '' },
		// nvue不支持跟隨窗口滾動(dòng)
		position: { 
			type: String,
			// #ifdef APP-NVUE
			 default: 'absolute',
			// #endif
			// #ifndef APP-NVUE
			default: 'static',
			// #endif
		},
	},
	data() {
		return {
			
		}
	},
	watch: {
		option(v) {
			// #ifdef APP-PLUS
			this.lsjFile&&this.show();
			// #endif
		}
	},
	updated() {
		// #ifdef APP-PLUS
			if (this.isShow) {
				this.lsjFile&&this.show();
			}
		// #endif
	},
	computed: {
		getStyles() {
			let styles = {
				width: this.width,
				height: this.height
			}
			if (this.position == 'absolute') {
				styles['top'] = this.top
				styles['bottom'] = this.bottom
				styles['left'] = this.left
				styles['right'] = this.right
				styles['position'] = 'fixed'
			}
 
			return styles
		}
	},
	mounted() {
		this._size = 0;
		let WEBID = this.childId + new Date().getTime();
		this.lsjFile = new LsjFile({
			id: WEBID,
			debug: this.debug,
			width: this.width,
			height: this.height,
			option: this.option,
			instantly: this.instantly,
			// 限制條件
			prohibited: {
				// 大小
				size: this.size,
				// 允許上傳的格式
				formats: this.formats,
				// 限制選擇的格式
				accept: this.accept,
				count: this.count
			},
			onchange: this.onchange,
			onprogress: this.onprogress,
		});
		this.create();
		
	},
	beforeDestroy() {
		// #ifdef APP-PLUS
		this.lsjFile.dom.close();
		// #endif
	},
	methods: {
		setFiles(array) {
			if (array instanceof Map) {
				for (let [key, item] of array) {
					item['progress'] = 100;
					item['type'] = 'success';
					this.lsjFile.files.set(key,item);
				}
			}
			else if (Array.isArray(array)) {
				array.forEach(item=>{
					if (item.name) { 
						item['progress'] = 100;
						item['type'] = 'success';
						this.lsjFile.files.set(item.name,item);
					}
				});
			}
			this.onchange(this.lsjFile.files);
		},
		setData() {
			this.lsjFile&&this.lsjFile.setData(...arguments);
		},
		getDomStyles(callback) {
			// #ifndef APP-NVUE
			let view = uni
				.createSelectorQuery()
				.in(this)
				.select('.lsj-file')
			view.fields(
				{
					size: true,
					rect: true
				},
				({ height, width, top, left, right, bottom }) => {
					uni.createSelectorQuery()
					.selectViewport()
					.scrollOffset(({ scrollTop }) => {
						return callback({
							top: parseInt(top) + parseInt(scrollTop) + 'px',
							left: parseInt(left) + 'px',
							width: parseInt(width) + 'px',
							height: parseInt(height) + 'px'
						})
					})
					.exec()
				}
			).exec()
			// #endif
			// #ifdef APP-NVUE
			const dom = weex.requireModule('dom')
			dom.getComponentRect(this.$refs.lsj, ({ size: { height, width, top, left, right, bottom } }) => {
				return callback({
					top: parseInt(top) + 'px',
					left: parseInt(left) + 'px',
					width: parseInt(width) + 'px',
					height: parseInt(height) + 'px',
					right: parseInt(right) + 'px',
					bottom: parseInt(bottom) + 'px'
				})
			})
			// #endif
		},
		show() {
			this.isShow = true;
			// #ifdef APP-PLUS
			this.lsjFile&&this.getDomStyles(styles => {
				this.lsjFile.dom.setStyle(styles)
			});
			// #endif
			// #ifdef H5
			this.lsjFile.dom.style.display = 'inline'
			// #endif
		},
		hide() {
			this.isShow = false;
			// #ifdef APP-PLUS
			this.lsjFile&&this.lsjFile.dom.setStyle({
				top: '-100px',
				left:'0px',
				width: '1px',
				height: '100px',
			});
			// #endif
			// #ifdef H5
			this.lsjFile.dom.style.display = 'none'
			// #endif
		},
		/**
		 * 手動(dòng)提交上傳
		 * @param {string}name 文件名稱,不傳則上傳所有type等于waiting和fail的文件
		 */
		upload(name) {
			this.lsjFile&&this.lsjFile.upload(name);
		},
		/**
		 * @returns {Map} 已選擇的文件Map集
		 */
		onchange(files) {
			this.$emit('change',files);
			this._size = files.size;
			return files.size >= this.count ? this.hide() : this.show();
		},
		/**
		 * @returns {object} 當(dāng)前上傳中的對(duì)象
		 */
		onprogress(item,end=false) {
			this.$emit('progress',item);
			if (end) {
				setTimeout(()=>{
					this.$emit('uploadEnd',item);
				},0);
			}
		},
		/**
		 * 移除組件內(nèi)緩存的某條數(shù)據(jù)
		 * @param {string}name 文件名稱,不指定默認(rèn)清除所有文件
		 */
		clear(name) {
			this.lsjFile.clear(name);
		},
		// 創(chuàng)建選擇器
		create() {
			// 若iOS端服務(wù)端處理不了跨域就將hybrid目錄內(nèi)的html放到服務(wù)端去,并將此處path改成服務(wù)器上的地址
			let path = '/uni_modules/lsj-upload/hybrid/html/uploadFile.html';
			let dom = this.lsjFile.create(path);
			// #ifdef H5
			this.$refs.lsj.$el.appendChild(dom);
			// #endif
			// #ifndef APP-PLUS
			this.show();
			// #endif
			// #ifdef APP-PLUS
			dom.setStyle({position: this.position});
			dom.loadURL(path);
			setTimeout(()=>{
				// #ifdef APP-NVUE
				plus.webview.currentWebview().append(dom);
				// #endif
				// #ifndef APP-NVUE
				this.$root.$scope.$getAppWebview().append(dom);
				// #endif
				this.show();
			},300)
			// #endif
		},
		// 點(diǎn)擊選擇附件
		onClick() {
			if (this._size >= this.count) {
				this.toast(`只允許上傳${this.count}個(gè)文件`);
				return;
			}
			
			// #ifdef MP-WEIXIN
			if (!this.isShow) {return;}
			let count = this.count - this._size;
			this.lsjFile.chooseMessageFile(this.wxFileType,count);
			// #endif
		},
		toast(msg) {
			uni.showToast({
				title: msg,
				icon: 'none'
			});
		}
	}
}
</script>
 
<style scoped>
.lsj-file {
	/* display: inline-block; */
}
.defview {
	/* background-color: #007aff;
	color: #fff;
	border-radius: 10rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 28rpx; */
}
.hFile {
	/* position: relative;
	overflow: hidden; */
}
</style>

 LsjFile.js

export class LsjFile {
	constructor(data) {
		this.dom = null;
		// files.type = waiting;//(等待上傳)|| loading(上傳中)|| success(成功) || fail(失?。?
		this.files = new Map();
		this.debug = data.debug || false;
		this.id = data.id;
		this.width = data.width;
		this.height = data.height;
		this.option = data.option;
		this.instantly = data.instantly;
		this.prohibited = data.prohibited;
		this.onchange = data.onchange;
		this.onprogress = data.onprogress;
		this.uploadHandle = this._uploadHandle;
		// #ifdef MP-WEIXIN
		this.uploadHandle = this._uploadHandleWX;
		// #endif
	}
	
	
	/**
	 * 創(chuàng)建File節(jié)點(diǎn)
	 * @param {string}path webview地址
	 */
	create(path) {
		if (!this.dom) {
			// #ifdef H5
				let dom = document.createElement('input');
				dom.type = 'file'
				dom.value = ''
				dom.style.height = this.height
				dom.style.width = this.width
			    // dom.style.visibility = 'hidden'
				dom.style.position = 'absolute'
				dom.style.top = 0
				dom.style.left = 0
				dom.style.right = 0
				dom.style.bottom = 0
				dom.style.opacity = 0
				dom.style.zIndex = 0
				dom.accept = this.prohibited.accept;
				if (this.prohibited.count > 1) {
				dom.multiple = 'multiple';
				}
				dom.onchange = event => {
					for (let file of event.target.files) {
						this.addFile(file);
					}
					this.dom.value = '';
				};
				this.dom = dom;
			// #endif
		
			// #ifdef APP-PLUS
				let styles = {
					top: '-100px',
					left: 0,
					width: '1px',
					height: '1px',
					background: 'transparent' 
				};
				let extras = {
					debug: this.debug,
					instantly: this.instantly,
					prohibited: this.prohibited,
				}
				this.dom = plus.webview.create(path, this.id, styles,extras);
				this.setData(this.option); 
				this._overrideUrlLoading();
			// #endif
			return this.dom;
		}
	}
	
	copyObject(obj) {
		if (typeof obj !== "undefined") {
			return JSON.parse(JSON.stringify(obj));
		} else {
			return obj;
		}
	}
	
	/**
	 * 自動(dòng)根據(jù)字符串路徑設(shè)置對(duì)象中的值 支持.和[]
	 * @param	{Object} dataObj 數(shù)據(jù)源
	 * @param	{String} name 支持a.b 和 a[b]
	 * @param	{String} value 值
	 * setValue(dataObj, name, value);
	 */
	setValue(dataObj, name, value) {
		// 通過(guò)正則表達(dá)式  查找路徑數(shù)據(jù)
		let dataValue;
		if (typeof value === "object") {
			dataValue = this.copyObject(value);
		} else {
			dataValue = value;
		}
		let regExp = new RegExp("([\\w$]+)|\\[(:\\d)\\]", "g");
		const patten = name.match(regExp);
		// 遍歷路徑  逐級(jí)查找  最后一級(jí)用于直接賦值
		for (let i = 0; i < patten.length - 1; i++) {
			let keyName = patten[i];
			if (typeof dataObj[keyName] !== "object") dataObj[keyName] = {};
			dataObj = dataObj[keyName];
		}
		// 最后一級(jí)
		dataObj[patten[patten.length - 1]] = dataValue;
		this.debug&&console.log('參數(shù)更新后',JSON.stringify(this.option));
	}
	
	/**
	 * 設(shè)置上傳參數(shù)
	 * @param {object|string}name 上傳參數(shù),支持a.b 和 a[b]
	 */
	setData() {
		let [name,value = ''] = arguments;
		if (typeof name === 'object') {
			Object.assign(this.option,name);
		}
		else {
			this.setValue(this.option,name,value);
		}
		
		this.debug&&console.log(JSON.stringify(this.option));
		
		// #ifdef APP-PLUS
			this.dom.evalJS(`vm.setData('${JSON.stringify(this.option)}')`);
		// #endif
	}
	
	/**
	 * 上傳
	 * @param {string}name 文件名稱
	 */
	async upload(name='') {
		if (!this.option.url) {
			throw Error('未設(shè)置上傳地址');
		}
		
		// #ifndef APP-PLUS
		console.log('has',this.files.has(name))
			if (name && this.files.has(name)) {
				await this.uploadHandle(this.files.get(name));
			}
			else {
				for (let item of this.files.values()) {
					if (item.type === 'waiting' || item.type === 'fail') {
						await this.uploadHandle(item);
					}
				}
			}
		// #endif
		
		// #ifdef APP-PLUS
			this.dom&&this.dom.evalJS(`vm.upload('${name}')`);
		// #endif
	}
	
	// 選擇文件change
	addFile(file) {
		
		let name = file.name;
		this.debug&&console.log('文件名稱',name,'大小',file.size);
		
		if (file) {
			// 限制文件格式
			let path = '';
			let suffix = name.substring(name.lastIndexOf(".")+1).toLowerCase();
			let formats = this.prohibited.formats.toLowerCase();
			if (formats&&!formats.includes(suffix)) {
				this.toast(`不支持上傳${suffix.toUpperCase()}格式文件`);
				return false;
			}
			// 限制文件大小
			if (file.size > 1024 * 1024 * Math.abs(this.prohibited.size)) {
				this.toast(`附件大小請(qǐng)勿超過(guò)${this.prohibited.size}M`)
				return false;
			}
			// #ifndef MP-WEIXIN
			path = URL.createObjectURL(file);
			// #endif
			// #ifdef MP-WEIXIN
			path = file.path;
			// #endif
			this.files.set(file.name,{file,path,name: file.name,size: file.size,progress: 0,type: 'waiting'});
			
			// #ifndef MP-WEIXIN
			this.onchange(this.files);
			this.instantly&&this.upload();
			// #endif
			
			// #ifdef MP-WEIXIN
			return true;
			// #endif
		}
	}
	
	/**
	 * 移除文件
	 * @param {string}name 不傳name默認(rèn)移除所有文件,傳入name移除指定name的文件
	 */
	clear(name='') {
		// #ifdef APP-PLUS
		this.dom&&this.dom.evalJS(`vm.clear('${name}')`);
		// #endif
		
		if (!name) {
			this.files.clear();
		}
		else {
			this.files.delete(name); 
		}
		return this.onchange(this.files);
	}
	
	/**
	 * 提示框
	 * @param {string}msg 輕提示內(nèi)容
	 */
	toast(msg) {
		uni.showToast({
			title: msg,
			icon: 'none'
		});
	}
	
	/**
	 * 微信小程序選擇文件
	 * @param {number}count 可選擇文件數(shù)量
	 */
	chooseMessageFile(type,count) {
		wx.chooseMessageFile({
			count: count,
			type: type,
			success: ({ tempFiles }) => {
				for (let file of tempFiles) {
					let next = this.addFile(file);
					if (!next) {return}
				}
				this.onchange(this.files);
				this.instantly&&this.upload();
			},
			fail: () => {
				this.toast(`打開(kāi)失敗`);
			}
		})
	}
	
	_overrideUrlLoading() {
		this.dom.overrideUrlLoading({ mode: 'reject' }, e => {
			let {retype,item,files,end} = this._getRequest(
				e.url
			);
			let _this = this;
			switch (retype) {
				case 'updateOption':
					this.dom.evalJS(`vm.setData('${JSON.stringify(_this.option)}')`);
					break
				case 'change':
					try {
						_this.files = new Map([..._this.files,...JSON.parse(unescape(files))]);
					} catch (e) {
						return console.error('出錯(cuò)了,請(qǐng)檢查代碼')
					}
					_this.onchange(_this.files);
					break
				case 'progress':
					try {
						item = JSON.parse(unescape(item));
					} catch (e) {
						return console.error('出錯(cuò)了,請(qǐng)檢查代碼')
					}
					_this._changeFilesItem(item,end);
					break
				default:
					break
			}
		})
	}
	
	_getRequest(url) {
		let theRequest = new Object()
		let index = url.indexOf('?')
		if (index != -1) {
			let str = url.substring(index + 1)
			let strs = str.split('&')
			for (let i = 0; i < strs.length; i++) {
				theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1])
			}
		}
		return theRequest
	}
	
	_changeFilesItem(item,end=false) {
		this.debug&&console.log('onprogress',JSON.stringify(item));
		this.onprogress(item,end);
		this.files.set(item.name,item);
	}
	// 上傳接口
	_uploadHandle(item) {
		item.type = 'loading';
		delete item.responseText;
		return new Promise((resolve,reject)=>{
			this.debug&&console.log('option',JSON.stringify(this.option));
			let {url,name,method='POST',header,formData} = this.option;
			let form = new FormData();
			for (let keys in formData) {
				form.append(keys, formData[keys])
			}
			form.append(name, item.file);
			let xmlRequest = new XMLHttpRequest();
			xmlRequest.open(method, url, true);
			for (let keys in header) {
				xmlRequest.setRequestHeader(keys, header[keys])
			}
			
			xmlRequest.upload.addEventListener(
				'progress',
				event => {
					if (event.lengthComputable) {
						let progress = Math.ceil((event.loaded * 100) / event.total)
						if (progress <= 100) {
							item.progress = progress;
							this._changeFilesItem(item);
						}
					}
				},
				false
			);
			
			xmlRequest.ontimeout = () => {
				console.error('請(qǐng)求超時(shí)')
				item.type = 'fail';
				this._changeFilesItem(item,true);
				return resolve(false);
			}
			
			xmlRequest.onreadystatechange = ev => {
				if (xmlRequest.readyState == 4) {
					if (xmlRequest.status == 200) {
						this.debug&&console.log('上傳完成1:' + xmlRequest.responseText)
						item['responseText'] = xmlRequest.responseText;
						item.type = 'success';
						this._changeFilesItem(item,true);
						return resolve(true);
					} else if (xmlRequest.status == 0) {
						console.error('status = 0 :請(qǐng)檢查請(qǐng)求頭Content-Type與服務(wù)端是否匹配,服務(wù)端已正確開(kāi)啟跨域,并且nginx未攔截阻止請(qǐng)求')
					}
					console.error('--ERROR--:status = ' + xmlRequest.status)
					item.type = 'fail';
					this._changeFilesItem(item,true);
					return resolve(false);
				}
			}
			xmlRequest.send(form)
		});
	}
	
	_uploadHandleWX(item) {
		item.type = 'loading';
		delete item.responseText;
		return new Promise((resolve,reject)=>{
			this.debug&&console.log('option',JSON.stringify(this.option));
			let form = {filePath: item.file.path,...this.option };
			form['fail'] = ({ errMsg = '' }) => {
				console.error('--ERROR--:' + errMsg)
				item.type = 'fail';
				this._changeFilesItem(item,true);
				return resolve(false);
			}
			form['success'] = res => {
				if (res.statusCode == 200) {
					this.debug&&console.log('上傳完成,微信端返回不一定是字符串,根據(jù)接口返回格式判斷是否需要JSON.parse:' + res.data)
					item['responseText'] = res.data;
					item.type = 'success';
					this._changeFilesItem(item,true);
					return resolve(true);
				}
				item.type = 'fail';
				this._changeFilesItem(item,true);
				return resolve(false);
			}
			
			let xmlRequest = uni.uploadFile(form);
			xmlRequest.onProgressUpdate(({ progress = 0 }) => {
				if (progress <= 100) {
					item.progress = progress;
					this._changeFilesItem(item);
				}
			})
		});
	}
}

2、使用組件

引入組件后使用

<uploadFile @getUploadSuccess="getUploadSuccess" :uploadUrl="uploadbeforeCreatedUrl" :formData="{}" formatType="png,jpg,jpeg,pdf,docx,doc,xlsx,xls,ppt,pptx">
     <image :src="addIcon" mode="scaleToFill" />
</uploadFile>
 
// uploadUrl為上傳的路徑
 
// 文件上傳成功回調(diào)
 getUploadSuccess(fileData){
        let resdata = JSON.parse(fileData.responseText);
        this.form.activityResource.push(resdata.data);
        this.$forceUpdate();
 },

效果圖

總結(jié)

到此這篇關(guān)于uniapp開(kāi)發(fā)H5使用formData上傳文件的文章就介紹到這了,更多相關(guān)uniapp用formData上傳文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JS實(shí)現(xiàn)點(diǎn)擊button按鈕切換圖片

    JS實(shí)現(xiàn)點(diǎn)擊button按鈕切換圖片

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)點(diǎn)擊button按鈕切換圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • JS實(shí)現(xiàn)的簡(jiǎn)單拖拽功能示例

    JS實(shí)現(xiàn)的簡(jiǎn)單拖拽功能示例

    這篇文章主要介紹了JS實(shí)現(xiàn)的簡(jiǎn)單拖拽功能,涉及javascript鼠標(biāo)事件響應(yīng)及頁(yè)面元素屬性動(dòng)態(tài)操作相關(guān)技巧,需要的朋友可以參考下
    2017-03-03
  • 基于javascript html5實(shí)現(xiàn)多文件上傳

    基于javascript html5實(shí)現(xiàn)多文件上傳

    這篇文章主要為大家詳細(xì)介紹了基于javascript html5實(shí)現(xiàn)多文件上傳的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 一個(gè)判斷搶購(gòu)時(shí)間是否到達(dá)的簡(jiǎn)單的js函數(shù)

    一個(gè)判斷搶購(gòu)時(shí)間是否到達(dá)的簡(jiǎn)單的js函數(shù)

    這篇文章主要介紹了一個(gè)簡(jiǎn)單的判斷搶購(gòu)時(shí)間是否到達(dá)的js函數(shù),原理很簡(jiǎn)單,找到時(shí)鐘的id,計(jì)算數(shù)值,到達(dá)搶購(gòu)時(shí)間時(shí)執(zhí)行任務(wù),需要的朋友可以參考下
    2014-06-06
  • JavaScript使用Promise控制并發(fā)請(qǐng)求

    JavaScript使用Promise控制并發(fā)請(qǐng)求

    當(dāng)我們需要同時(shí)處理多個(gè)請(qǐng)求時(shí),如何避免請(qǐng)求之間的沖突和混亂呢,這就是今天我們要探討的話題——如何使用Promise控制并發(fā)請(qǐng)求,感興趣的可以了解一下
    2023-06-06
  • 淺談小程序globalData的那些事兒

    淺談小程序globalData的那些事兒

    這篇文章主要介紹了淺談小程序globalData的那些事兒,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Chrome調(diào)試折騰記之JS斷點(diǎn)調(diào)試技巧

    Chrome調(diào)試折騰記之JS斷點(diǎn)調(diào)試技巧

    這篇文章主要介紹了Chrome調(diào)試折騰記之JS斷點(diǎn)調(diào)試技巧,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • JavaScript使用SpreadJS創(chuàng)建Excel查看器

    JavaScript使用SpreadJS創(chuàng)建Excel查看器

    在現(xiàn)代的Web應(yīng)用開(kāi)發(fā)中,Excel文件的處理和展示是一項(xiàng)常見(jiàn)的需求,小編今天將為大家展示如何借助SpreadJS來(lái)創(chuàng)建一個(gè)Excel查看器,感興趣的小伙伴可以了解下
    2023-12-12
  • JS中的二叉樹(shù)遍歷詳解

    JS中的二叉樹(shù)遍歷詳解

    這篇文章主要為大家詳細(xì)介紹了JS中的二叉樹(shù)遍歷,何為二叉樹(shù),什么是二叉樹(shù)的遍歷,感興趣的小伙伴們可以參考一下
    2016-03-03
  • d3.js 地鐵軌道交通項(xiàng)目實(shí)戰(zhàn)

    d3.js 地鐵軌道交通項(xiàng)目實(shí)戰(zhàn)

    這篇文章主要介紹了d3.js 地鐵軌道交通項(xiàng)目實(shí)戰(zhàn),本文通過(guò)實(shí)例代碼項(xiàng)目截圖給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-11-11

最新評(píng)論