go gui wails 图片查看工具

wails 实例2 图片查看工具

用go gui 框架 wails 做一个图片查看工具,主要的问题还是怎么把本地的图片展示出来

由于 wails webview 不能直接访问files:///协议的文件所以直接打不开,无法预览

怎么显示本地图片?

利用 wails 的资源服务,配置一个资源请求的服务,通过资源服务把本地的图片读出来,然后返回给界面显示,说干就干!!

创建项目

wails 命令直接创建一个wails vue 的项目

写前端展示的界面

做一个这样子的界面

右上角的按钮作用依次为:打开文件,自动播放,全屏,关闭,下面是图片列表,中间部分是展示图片的地方。界面比较简单。

js 复制代码
// 定义图片的地址
urlList:[
    "/e/img/img1.png",
    "/e/img/img2.png",
    "/e/img/img3.png",
]

图片的地址定义成这样子才能请求到自定义的资源服务, 以下的几种方式都请求不到

js 复制代码
files:///XXX
/e:/img/img1.png
e:/img/img1.png

也可以试下其他的方式。

写一个返回资源的服务

这个方法会接收到前端的资源请求,把传过来的路径处理下,然后读出来,返回给前端。

go 复制代码
type FileLoader struct {
	http.Handler
}

func NewFileLoader() *FileLoader {
	return &FileLoader{}
}

func (h *FileLoader) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println("---------", r.URL)

	filePath := r.URL.Path
	rootPath := filePath[0:3]
	fileDir := rootPath[1:2] + ":" + filePath[3:]

	log.Println(fileDir)
	f, err := os.OpenFile(fileDir, os.O_RDONLY, 0)
	if err != nil {
		w.WriteHeader(500)
		return
	}
	bs, err := io.ReadAll(f)
	w.Write(bs)
}
打开文件

还需要些一个打开文件的功能,打开文件,调用wails api wails.io/zh-Hans/doc...

scss 复制代码
OpenMultipleFilesDialog(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error)

可以多选文件,方法返回的是选择的文件的路径,写一个方法从前端调用这个,从而打开选择文件对话框

go 复制代码
func (a *App) OpenFileDlg() []string {
	opts := runtime.OpenDialogOptions{}
	filePath, err := runtime.OpenMultipleFilesDialog(a.ctx, opts)
	if err != nil {
		log.Println(err.Error())
		return nil
	}
	log.Println(filePath)
	return filePath
}

前端调用下

js 复制代码
openFile() {
    OpenFileDlg().then((res) => {
        res.forEach((ele) => {
            let imgFile = ele.replace(":", "");
            imgFile = "/" + imgFile.split("\\").join("/");
            this.urlList.push(imgFile);
            console.log(imgFile);
        });
        this.getImageList();
    });
},

传过来的名字是 e:img/img1.png 需要处理成 /e/img/img1.png 的形式

自动播放

这样就可以了,这里还做了一个自动播放的逻辑

js 复制代码
autoPlay() {
    if (this.timer) {
        clearInterval(this.timer);
        this.timer = null;
        this.isPlayIng = false;
    } else {
        this.isPlayIng = true;
        this.timer = setInterval(() => {
            if (this.autoPlayIndex >= this.imgList.length) {
                this.autoPlayIndex = 0;
            }
            this.curShow = this.imgList[this.autoPlayIndex];
            this.autoPlayIndex++;
        }, 1000);
    }
},
总结

主要是处理前端打开本地文件的问题,不能直接打开,需要通过资源服务,go 读出来,传给界面

界面文件,用了个UI框架 iview www.iviewui.com/view-ui-plu...

还有不完善的地方,道友们不要太认真

vue 复制代码
<template>
	<div id="imgViewApp">
		<div class="tool-bar" style="--wails-draggable: drag">
			<div class="title">
				<img :src="iconUrl" style="width: 16px; height: 16px" />
				{{ name }}
			</div>
			<div class="tool-btn">
				<div style="cursor: pointer" @click="openFile">
					<Icon type="md-albums" />
				</div>
				<div style="cursor: pointer" @click="autoPlay">
					<Icon type="md-arrow-dropright-circle" v-if="!isPlayIng" />
					<Icon type="ios-exit" v-if="isPlayIng" />
				</div>
				<div style="cursor: pointer" @click="fullScreen">
					<Icon type="md-expand" />
				</div>
				<div style="cursor: pointer" @click="closeApp">
					<Icon type="md-power" />
				</div>
			</div>
		</div>
		<div class="imageViwer">
			<Image style="height: 100%" :src="curShow.url" fit="contain" />
		</div>
		<div class="img-list">
			<div class="arror arr-left" @click="left">
				<Icon type="ios-arrow-back" />
			</div>
			<div class="img-list-warp" ref="listViewRef">
				<div v-for="(item, index) in imgList" :key="index" @click="setCurImg(item)">
					<Image :src="item.url" fit="contain" width="60px" height="80px" />
				</div>
			</div>
			<div class="arror arr-right" @click="right">
				<Icon type="ios-arrow-forward" />
			</div>
		</div>
		<footer>Made by Bogerj</footer>
	</div>
</template>

<script>
	import { WindowSetSize, WindowToggleMaximise } from "../../wailsjs/runtime/runtime";
	import { CloseApp, OpenFileDlg } from "../../wailsjs/go/main/App";
	import iconUrl from "../assets/images/logo-universal.png";
	export default {
		name: "imgView",
		data() {
			return {
				name: "图片预览",
				imgList: [],
				curShow: {},
				iconUrl: iconUrl,
				winsSize: {
					w: 800,
					h: 630,
				},
				curStart: 0,
				autoPlayIndex: 0,
				timer: null,
				isPlayIng: false,
				dataSource: [],
				urlList: [],
			};
		},
		mounted() {
			WindowSetSize(this.winsSize.w, this.winsSize.h);
			this.getImageList();
		},
		methods: {
			getImageList() {
				for (let i = 0; i < this.urlList.length; i++) {
					this.imgList.push({ url: this.urlList[i], name: i + "", id: i });
				}
				this.curShow = this.imgList.length > 0 ? this.imgList[0] : {};
			},
			fullScreen() {
				WindowToggleMaximise();
			},
			setCurImg(curImg) {
				this.curShow = curImg;
			},
			closeApp() {
				CloseApp();
			},
			right() {
				console.log("right", this.curStart);
				this.curStart += 1;
			},
			autoPlay() {
				if (this.timer) {
					clearInterval(this.timer);
					this.timer = null;
					this.isPlayIng = false;
				} else {
					this.isPlayIng = true;
					this.timer = setInterval(() => {
						if (this.autoPlayIndex >= this.imgList.length) {
							this.autoPlayIndex = 0;
						}
						this.curShow = this.imgList[this.autoPlayIndex];
						this.autoPlayIndex++;
					}, 1000);
				}
			},
			left() {
				console.log("left");
				this.curStart -= 1;
			},
			openFile() {
				OpenFileDlg().then((res) => {
					res.forEach((ele) => {
						let imgFile = ele.replace(":", "");
						imgFile = "/" + imgFile.split("\\").join("/");
						this.urlList.push(imgFile);
						console.log(imgFile);
					});
					this.getImageList();
				});
			},
		},
	};
</script>
<style>
	#imgViewApp {
		height: 100%;
		width: 100%;
		background: none;
	}
	.imageViwer {
		padding-top: 5px;
		height: calc(100vh - 155px);
		text-align: center;
	}
	.img-list {
		width: 100%;
		box-sizing: border-box;
		height: 100px;
		display: flex;
	}
	.arror {
		font-size: 30px;
		padding-top: 15px;
		height: 100px;
		transition: all 0.1s linear;
	}
	.arr-left:hover {
		color: #fff;
	}
	.arr-right:hover {
		color: #fff;
	}
	.img-list-warp {
		flex: 1;
		display: flex;
		padding: 5px;
		gap: 8px;
		overflow-x: scroll;
		overflow-y: hidden;
	}
	.img-list-warp::-webkit-scrollbar {
		height: 10px;
	}
	.img-list-warp::-webkit-scrollbar-thumb {
		border-radius: 8px;
		background-color: #d55959;
	}
	img-list-warp::-webkit-scrollbar-track {
		border-radius: 8px;
		background-color: #e7e7e7;
		border: 1px solid #cacaca;
	}

	.tool-bar {
		font-size: 12px;
		color: #000;
		font-weight: 500;
		padding: 0px 9px;
		display: flex;
		background: #fff;
		justify-content: space-between;
		align-items: center;
		height: 30px;
	}
	.tool-btn {
		display: flex;
	}
	.tool-btn div {
		margin-left: 5px;
		font-size: 18px;
	}
	.title {
		display: flex;
		justify-content: space-between;
		justify-items: center;
	}
</style>
相关推荐
2401_857600953 小时前
电商系统开发:Spring Boot框架实战
java·spring boot·后端
天草二十六_简村人5 小时前
spring-data-elasticsearch 3.2.4 实现桶bucket排序去重,实现指定字段的聚合搜索
java·spring boot·后端·spring·elasticsearch·架构·jenkins
拔剑纵狂歌5 小时前
ZooKeeper单机、集群模式搭建教程
分布式·后端·学习·zookeeper·中间件·架构·服务发现
jokerest1236 小时前
web——upload-labs——第五关——大小写绕过绕过
前端·后端
java_python源码6 小时前
[含文档+PPT+源码等]精品基于springboot实现的原生Andriod手机使用管理软件
java·spring boot·后端
技术猿188702783517 小时前
Spring Boot应用中的文件压缩与解压技术实践
java·spring boot·后端
码哥字节7 小时前
30+ 程序员降薪跳槽到银行,技术优势成了空谈。银行的职场环境,远比想象中的要复杂
后端
hlsd#7 小时前
go 集成swagger 在线接口文档
开发语言·后端·golang
大脑经常闹风暴@小猿8 小时前
Django 启用国际化支持—实现配置多国语言
后端·python·django
计算机-秋大田8 小时前
基于微信小程序的在线疫苗预约的设计与实现,LW+源码+讲解
spring boot·后端·微信小程序·小程序·vue