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>