vue移动端h5中a标签下载/预览文件

需求:项目分PC端和移动端,PC端(react)以实现列表页附件下载,现需同步移动端(vue)h5页面在原有的列表页中增加一行查看(下载)附件。
只写结构,暂不考虑其他,增加附件行的代码如下:

<div>
	<span>
		附件:
		<a
			:href=''
			{{'附件名称'}}>
		</a>
	</span>
</div>

点击列表页本身的每一个方框会跳转一个详情页,同理点击下载发票附件时也会,需要处理一下点击a标签时的穿透问题。这里我给span加上一个点击事件,事件里边写上event.stopPropagation()

<span @click="stopBubble()">

methods:{
	stopBubble(){
		console.log('阻止穿透,启动!')
		event.stopPropagation()
	}
}

大体结构定下,然后考虑两个问题:

1)href里怎么写

2)附件名称的展示

先看附件名称,可能有附件,也可能没有、有附件时显示附件名称,没有附件是显示“-”,使用三目运算符判断是否有附件可以很好的解决。

{{ item.attachment?item.attachment.fileName:-}}

再看href,有附件的情况点击a标签可以下载,没有附件的情况肯定不能下载。PC端对href也使用了三目运算符,不能下载的情况给了‘#’。移动端这里我给了展示附件的div写了v-if,没有附件时就不显示附件行。

<div v-if="item.attachment">

href的拼写要获取url和token,目前已知

:href="`/api/attachments/download/${url}?access_token=${token}`"

其中url和token为变量,写法为${变量名}。
url同PC端,写法略有不同,移动端中为item.attachment.attachmentOid。
token登陆后固定,登录一次改一次。token在PC端中存放在sessionStorage中,sessionStorage.getItem(“token”)即可获取;而在移动端中,token存放在localStorage中,获取为localStorage(‘local.token’),还没完!这里是json字符串,需要把它转为json数据,,JSON.parse(localStorage(‘local.token’)).value
拿到了url和token,美滋滋的写到href里,开心!

:href="`/api/attachments/download/${item.attachment.attachmentOid}?access_token=${JSON.parse(localStorage('local.token')).value}`"

报错‘localStorage’is not defined, ‘getItem’ of undefined。惊不惊喜,意不意外!

去data()里定义个变量接收token这个值

data(){
	return {
		token: JSON.parse(localStorage('local.token')).value,
	}
}

然后href中

:href="`/api/attachments/download/${item.attachment.attachmentOid}?access_token=${token}`"

较完整代码大体如下

// html/template
<div v-if="item.attachment">
	<span @click="stopBubble()">
		附件:
		<a
			:href="`/api/attachments/download/${item.attachment.attachmentOid}?access_token=${token}`"
			{{ item.attachment?item.attachment.fileName:-}}>
		</a>
	</span>
</div>

// data
data(){
	return {
		token: JSON.parse(localStorage('local.token')).value,
	}
}

// methods
methods:{
	stopBubble(){
		console.log('阻止穿透,启动!')
		event.stopPropagation()
	}
}

这里有个问题,就是如果是vue移动端h5页面,这么写的情况下,浏览器模拟页面可以实现下载,但在真机调试却不行。

解决真机问题

用到了KK JS SDK,项目用的1.3.4版本。
KK: link.
vue移动端h5中a标签下载/预览文件_第1张图片
项目中本身就有引用过KK,在这里我只是在当前需求页面的代码文件中引入这个下载方法。
修改a标签中的href为点击事件

<a
	@click="fileDownload(item)"
	{{ item.attachment?item.attachment.fileName:-}}>
</a>

从kk引入

import { fileDown } from '@/utils/kk';

点击下载事件

async fileDownload(item){
	event.stopPropagation();
	const { origin } = window.location;
	const token = JSON.parse(localStorage('local.token')).value;
	const url = `${origin}/api/attachments/download/${item.attachment.attachmentOid}?access_token=${token}`;
	const = file.attachment.fileName;
	console.log(url); // 打印当前环境url
	this.loading = true;
	await fileDown(url,fileName); // KK下载
	this.loading = false;
	this.$toast.show({
		cintent:'下载成功',
		position:'center',
		type:'success',
	});
},

改造之后真机连接本地项目测试没问题,ok升级上开发环境再测试,下载不了!傻了吧!
出现下载不了的情况,可以打印一下当前环境的url,把它贴到浏览器地址栏看能否正常下载。以上写法在本地时真机测试没问题,url贴地址栏没问题,在开发下载不了,贴地址栏404。好的,知道问题关键所在了。
我对比了原本其他页面已有的下载,打印它的url发现是/api/attachments/view,我写的是download,改过来之后开发环境就可以下载了。
这里还可以实现文件预览,多加上一个预览的a标签,预览事件这么写

// 从kk引入预览
import { 
	fileView,
	fileDown,
} from '@/utils/kk';

//预览事件
 async kkFileView(item){
	event.stopPropagation();
	const { origin } = window.location;
	const token = JSON.parse(localStorage('local.token')).value;
	const url = `${origin}/api/attachments/view/${item.attachment.attachmentOid}?access_token=${token}`;
	const = file.attachment.fileName;
	console.log(url);
	this.loading = true;
	await fileView(url,fileName); // KK预览
	this.loading = false;
},

和下载极其相似,只是其中引的KK方法不同。

改动后代码
下载和预览做了伸缩布局的设计靠两边,a标签颜色不够明显又用css样式加了一下。

// html/template
<div 
	v-if="item.attachment"
	style="display:flex;justify-content: space-between">
	<span>
		附件:
		<a
			@click="fileDownload(item)"
			style="color:#0094ff"
			{{ item.attachment?item.attachment.fileName:-}}>
		</a>
	</span>
	<a 
		@click="kkFileView(item)"
		style="color:#0094ff">
		预览
	</a>
</div>

// KK引入文件
import { 
	fileView,
	fileDown,
} from '@/utils/kk';

// methods
methods:{
	// 下载
	async fileDownload(item){
	event.stopPropagation();
	const { origin } = window.location;
	const token = JSON.parse(localStorage('local.token')).value;
	const url = `${origin}/api/attachments/view/${item.attachment.attachmentOid}?access_token=${token}`;
	const = file.attachment.fileName;
	console.log(url); // 打印当前环境url
	this.loading = true;
	await fileDown(url,fileName);
	this.loading = false;
	this.$toast.sjow({
		cintent:'下载成功',
		position:'center',
		type:'success',
	});
},
	// 预览
	async kkFileView(item){
	event.stopPropagation();
	const { origin } = window.location;
	const token = JSON.parse(localStorage('local.token')).value;
	const url = `${origin}/api/attachments/view/${item.attachment.attachmentOid}?access_token=${token}`;
	const = file.attachment.fileName;
	console.log(url);
	this.loading = true;
	await fileView(url,fileName);
	this.loading = false;
},
}

补充部分kk.js代码

import { detectOS } from '@/platform/hmap/utils';

/**
** 文件预览
*/
export function view(url){
	return new Promise(async (resolve,reject) => {
		await ready();
		kk.file.view(url,(result)=>{
			console.log(result);
			resolve();
		},(code,error)=>{
			 console.log(code,error);
			 reject();
		});
	});
}

export function fileDown (url,fileName,type){
	return new Promise(async (resolve,reject) => {
		await ready();
		let option;
		if (type === 'temp'){
			option = { 
				url,
				path:`publice://temp/$fileName` 
			},
		}else{
			option = { 
				url,
				path:`sdcard://$fileName`,
				appearInFileManager:true, 
			},
		}
		const proxy = new kk.proxy.Download(option,(result)=>{
			conet {
				progress,
				path
			} = result;
			if(Number(progress) === 100){
				resolve(path);
			}
		},(code,msg)=>{
			console.log(msg);
			reject();
		});
		proxy.start();
	});
}

export function fileView (url,fileName){
	try{
		const os = detectOS();
		if(os === 'ios'){
			kk.file.view(url);
		}else{
			const path = await fileDown(url,fileName,'temp');
			console.log(path);
			await view(path);
		}
	} catch (error){
		console.log(error);
	}
}

下载不是很稳定,断点检查有时会卡在await。在不改动原来kk文件下载方法的基础上,再写一个不用await的下载方法。

// kk.js
export function fileDown2 (url,fileName,type,sCallback,fCallback){
	let option;
		if (type === 'temp'){
			option = { 
				url,
				path:`sdcard://file/$fileName`  // 可以存放到根目录下的指定文件夹中
			},
		}else{
			option = { 
				url,
				path:`sdcard://$fileName`,
				appearInFileManager:true, 
			},
		}
		const proxy = new kk.proxy.Download(option,(result)=>{
			conet {
				progress,
				path
			} = result;
			if(Number(progress) === 100){
				sCallback(path);
			}
		},(code,msg)=>{
			console.log(msg);
			fCallback();
		});
		proxy.start();
}

下载代码微调,引入刚刚kk写的新的下载方法。

async fileDownload(item){
	event.stopPropagation();
	let _this = this;
	const { origin } = window.location;
	const token = JSON.parse(localStorage('local.token')).value;
	const url = `${origin}/api/attachments/download/${item.attachment.attachmentOid}?access_token=${token}`;
	const = file.attachment.fileName;
	console.log(url); // 打印当前环境url
	this.loading = true;
	fileDown2(url,fileName,'temp',function(path){ // 替换原来KK的下载fileDown
		_this.loading = false;
		_this.$toast.show({
			cintent:'下载成功',
			position:'center',
			type:'success',
		});
	},function(msg){
		console.log(msg);
	}); 
},

你可能感兴趣的:(笔记)