关于图片的长按保存(原生代码暂未集成,先记录一下准备工作)
最近要实现图片的长按保存功能,百度了好多,单由前端实现的方法网上也有,不过看上去好麻烦,头疼,后来有看到博文说原生实现会简单些,咨询了老板,说原生可以实现的,我需要提供所选中图片的url,这样那就简单多了
理一下流程:页面有一个图片轮播效果,点击某一张图片,实现图片预览的功能,在此基础上长按进行图片的保存到本地,因为有好几处都用到了这个功能,所以把它封装成了个组件,完整代码看最后
声明:图片预览我引用了vant库的imgPreview
父组件:
1,引入子组件
import imgPreview from "../../comps/common/imgPreview";
2,data里首先定义了showPreview值为false
showPreview:false, // 图片预览组件标志符
3,在父组件图片轮播部分设置一个函数,点击这部分让showPreview值变为true,继而触发自己封装的图片预览组件,我的代码如下,仅供参考
<mslider :loop="isLoop" :show-dot="true" ref="slider" :auto-play="false">
<div class="img_wrapper" v-for="(item,index) in showImgs" :key="index">
<img :src="item" alt="" @click="getImg(index)" loaded @load="imgLoad">
</div>
</mslider>
// 对应的methods方法
getImg(index){
this.showPreview = true;
}
4,showPreview为true,应用子组件
父组件要传给子组件的值有两个
showPreview:是否显示图片预览组件,不出意外,绝对为true
showImgs:要传过去的预览图片的数组
<imgPreview v-if="showPreview" :imgList = showImgs @func="changePreview" :isShowPreview = showPreview></imgPreview>
// methods里面的方法,接受子组件传递过来的值并进行赋值,即子传父触发的方法
changePreview(val){
// console.log(">>>>>>>>>>>>>>>>>>>>",val); // 不出意外,绝对为false
this.showPreview = val
},
子组件
子组件不能直接改动父组件传过来的值,不然会报错,这里就另外声明了一个值flag,在子组件代替showPreview进行操作
子组件完整代码如下:
<template>
<!-- 图片预览 -->
<div id="imgPreview" >
<!-- 图片预览模块,利用touchstart,touchend模拟了一下长按事件 -->
<div v-if="flag" @touchstart="touchStart" @touchend="touchEnd">
<van-image-preview v-model="flag" :images="imgList" @change="onChange"> </van-image-preview>
</div>
<!-- 这里引用了vant的分享模块,长按弹出分享列表,里面可以自行设置选项,分享到微博,微信,盆友圈,下载本地等 -->
<van-share-sheet
v-model="showShare"
:options="options"
@select="onSelect"
:duration="0.1"
/>
</div>
</template>
<script>
import { Toast } from 'vant';
export default {
name:'',
props:['imgList','isShowPreview'],
data(){
return {
flag:this.isShowPreview, // 子组件不能改动传过来的值,不然会报错,这里就另外声明了一个值,在子组件进行操作
index:1,
showShare:false, // 分享模块的显示与否
options: [
{ name: '微信', icon: 'wechat' },
{ name: '朋友圈', icon: 'https://img.yzcdn.cn/vant/custom-icon-fire.png' },
{ name: '微博', icon: 'weibo' },
{ name: '下载', icon: 'https://img.yzcdn.cn/vant/custom-icon-light.png' },
],
touchStartX:null,
touchStartY:null,
touchEndX:null,
touchEndY:null,
touchstartTime:null,
touchendTime:null,
duration:0,
curImgSrc:null,
osType:null,
}
},
created(){
console.log(this.flag,this.isShowPreview) // 首次传过来的值必定未true
this.curImgSrc = this.imgList[0]; // 获取第一张图片src并进行赋值
console.log("this.curImgSrc>>>>>",this.curImgSrc);
// 判断设备型号
let u = navigator.userAgent
let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //g
let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
console.log("isAndroid>>>>",isAndroid,"------","isIOS>>>>>>",isIOS)
if(isAndroid){
this.osType = 'Android';
}
if(isIOS){
this.osType = 'ios';
}
console.log("this.osType---65-----",this.osType)
},
mounted(){
},
methods:{
onChange(index) {
this.index = index;
// console.log("change>>>>>>>>>>>>>",index)
// 要根据当前的index值获取到对应图片的src,长按保存图片时将该src当作参数传过去
// console.log("当前选中的图片的src",this.imgList[index]) // 这里可以拿到图片的src
},
// 选择分享模块的某个功能所执行的操作,我这边因为目前原生代码暂未集成,只是做了一个简单的toast操作
onSelect(option) {
// Toast(option.name);
if (this.osType == 'Android') {
// Android 安卓机
// 安卓机代码还未集成
console.log("安卓机")
}
if (this.osType == 'ios'){
// ios 苹果机
if(option.name == '下载'){
console.log("下载图片")
console.log("this.curImgSrc>>>>>下载",this.curImgSrc)
console.log("苹果机");
console.log(window) // 电脑打印window是没有webkit属性的,要在ios设备上进行测试,我是在苹果电脑的模拟机上进行测试的
console.log(window.webkit) // 电脑打印window
//下面是苹果机调用原生方法,JsCallObjectC是后台定义好的方法,要传递的参数你们自己商量好,其他的都是固定格式,套着用就好
// window.webkit.messageHandlers.JsCallObjectC.postMessage('{"methodName":"SaveImage","ImgUrl":"'+this.curImgSrc+'"}');
window.webkit.messageHandlers.JsCallObjectC.postMessage('{"methodName":"SaveImage","ImgUrl":"https://www.wuyoumaicai.com/image/logo.png"}');
// 苹果原生下载图片仅支持https,目前动态获取的的图片的src是http格式的,所以现在是传了个https格式的一个定死的图片,之后再更新
}else if(option.name == '微信'){
console.log("分享到微信")
console.log("this.curImgSrc>>>>>分享到微信",this.curImgSrc)
}
}
this.showShare = false;
},
touchStart(event) {
this.touchstartTime = new Date().getTime();
this.touchStartX = event.changedTouches[0].clientX // this.touchStartX按下时的横轴坐标
this.touchStartY = event.changedTouches[0].clientY // this.touchStartY按下时的纵轴坐标
},
touchEnd() {
this.touchEndX = event.changedTouches[0].clientX // this.touchEndX释放时的横轴坐标
this.touchEndY = event.changedTouches[0].clientY // this.touchEndY释放时的纵轴坐标
this.touchendTime = new Date().getTime()
this.duration = this.touchendTime - this.touchstartTime
// console.log("间隔时间为",this.duration)
// 非左右滑动
if (Math.abs(this.touchEndX - this.touchStartX) < 10 && Math.abs(this.touchEndY - this.touchStartY) < 10) {
if(this.duration >= 800){
// 时间大于800毫秒,长按
// console.log("非左右滑动时间大于800毫秒,长按")
this.showShare = true; // 分享模块显示出阿来
}else{
// 时间小于800毫秒,单纯的点击事件
// console.log("非左右滑动时间小于800毫秒,单纯的点击事件")
this.flag = false;
this.showShare = false;
// this.$emit('func',this.flag) // 同下一行
this.$emit('func',false) // 子组件修改父组件传递过来的值并返回给父组件
}
}else{
// 左右滑动
if(this.duration >= 800){
// 时间大于800毫秒,单纯的点击事件
// console.log("左右滑动时间大于800毫秒,单纯的点击事件")
this.flag = true;
this.showShare = false;
}else{
// 时间小于800毫秒
// console.log("左右滑动时间小于800毫秒,隐藏分享/下载按钮")
this.flag = true;
this.showShare = false;
// this.$emit('func',false)
}
}
},
}
}
</script>
<style lang="less" scoped>
#imgPreview{
width:100%;
}
</style>
不是尽善尽美,有啥不足,欢迎不吝赐教
调用原生接口参考链接如下:
https://www.jianshu.com/p/c35b12ffc0f1
https://blog.csdn.net/BennyShi1998/article/details/79402289/
https://blog.csdn.net/Chris__wang/article/details/103144680