让我们透过 Web Serial API 连接 COM 吧!
首先来建立页面。
准备撰写组件之前,先来建立一些全局共用的样式变数与 Class。
直接将共用变数新增至 Quasar 已存在的档案 src\styles\quasar.variables.sass
中:
$primary : #027BE3
$secondary : #26A69A
$accent : #9C27B0
$dark : #1D1D1D
$positive : #21BA45
$negative : #C10015
$info : #31CCEC
$warning : #F2C037
// 整体视觉以圆角为主,建立基准值
$border-radius-s: 12px
$border-radius-m: 20px
@import '~quasar-variables-styl'
建立档案 src\styles\global.sass
// 引入变数
@import '@/styles/quasar.variables.sass'
.c-row
display: flex
.c-col
display: flex
flex-direction: column
// 圆角基准样式
.border-radius-m
border-radius: $border-radius-m !important
.border-radius-s
border-radius: $border-radius-s !important
// 滚动条样式
::-webkit-scrollbar
width: 3px
height: 3px
::-webkit-scrollbar-track
padding: 5px
border-radius: 7.5px
::-webkit-scrollbar-thumb
border-radius: 7.5px
最後在 src\main.js
引入 global.sass
import Vue from 'vue';
import App from './app.vue';
import router from './router/router';
import store from './store/store';
import './quasar';
import i18n from './i18n';
import '@/styles/global.sass';
import 'windi.css';
Vue.config.productionTip = false;
new Vue({
router,
store,
i18n,
render: (h) => h(App),
}).$mount('#app');
由於 Web Serial API 建立成功後的 Serial Port 物件会被多个卡片共用,所以在 Vuex 中建立 core 模组,用来储存 Port 与各类系统设定。
src\store\modules\core.store.js
/**
* 管理 Port 物件、系统主要设定
*/
/**
* @typedef {import('vuex').Module} Module
*/
/** @type {Module} */
const self = {
namespaced: true,
state: () => ({
port: null,
}),
mutations: {
setPort(state, port) {
state.port = port;
},
},
actions: {
},
modules: {
},
};
export default self;
并在 Vuex 中的 modules
引入 core.store.js
。
src\store\store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
import core from './modules/core.store';
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
core,
},
});
接着建立用来选择 Port 的设定对话框,这里使用 Quasar Dialog 组件。
功能需求为:
src\components\dialog-system-setting.vue <script>
import { mapState } from 'vuex';
import to from 'safe-await';
export default {
name: 'DialogSystemSetting',
components: {},
props: {},
data() {
return {};
},
computed: {
...mapState({
port: (state) => state.core.port,
}),
notSupportSerialApi() {
return !navigator?.serial;
},
/** 判断 Dialog 是否可以关闭 */
isPersistent() {
if (this.errMsg) {
return true;
}
return false;
},
errMsg() {
if (this.notSupportSerialApi) {
return '浏览器不支援 Web Serial API';
}
if (!this.port) {
return '请选择 COM Port';
}
return null;
},
},
watch: {
/** 如果 Dialog 可以关闭,则自动关闭 */
isPersistent(val) {
if (!val) {
this.hide();
}
},
},
created() {},
mounted() {},
methods: {
hide() {
this.$refs.dialog.hide();
},
/** 开启外部连结 */
openRefWeb() {
window.open('https://caniuse.com/?search=Web%20serial%20API');
},
/** 请求选择 COM */
async requestPort() {
/** 请求连线 Port
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API#checking_for_available_ports
*/
const [err, port] = await to(navigator.serial.requestPort());
if (err) {
// 使用者取消选择不弹出错误提示
if (`${err}`.includes('No port selected by the user')) {
return;
}
/** 其余错误则透过 Quasar Notify 显示
* 参考:https://v1.quasar.dev/quasar-plugins/notify
*/
this.$q.notify({
type: 'negative',
message: `选择 COM Port 发生错误 : ${err}`,
});
console.error(`[ requestPort ] err : `, err);
return;
}
// 储存至 Vuex
this.$store.commit('core/setPort', port);
},
/** 处理 Dialog shake 事件
* 参考 https://v1.quasar.dev/vue-components/dialog#different-modes
*/
handleShake() {
if (!this.errMsg) {
return;
}
this.$q.notify({
type: 'negative',
message: this.errMsg,
});
},
},
};
src\components\dialog-system-setting.vue <template lang="pug">
q-dialog(value, :persistent='isPersistent', @shake='handleShake', ref='dialog')
// 如果浏览器不支援 Web Serial API,显示此区块
q-card.border-radius-m(v-if='notSupportSerialApi')
q-card-section.c-col.flex-center.p-30px
.text-18px.text-red.mb-30px
| 浏览器不支援 Web Serial API,请改用支援此 API 之浏览器
q-btn(@click='openRefWeb()', color='primary') 参考资料
// 否则显示此区块
q-card.border-radius-m(v-else)
q-card-section.min-w-450px
q-list
q-item-label(header)
| 系统设定
q-item.border-radius-m(@click='requestPort', clickable)
q-item-section(avatar)
q-icon(name='r_developer_board', color='grey-7')
q-item-section
q-item-label
| 选择 COM Port
q-item-label(caption)
| 点击选择指定 COM Port
q-item-section(v-if='!port', side)
q-icon(name='r_error', color='red')
safe-await
是一种包装await
的方法,可以在不使用try catch
的情况下使用await
,配合Return Early Pattern
,个人觉得这样可读性比较好 (´,,•ω•,,)
详细探讨过程与介绍可以参考作者的 Github
将 dialog-system-setting.vue
组件引入 src\app.vue
中:
src\app.vue <script>
import DialogSystemSetting from '@/components/dialog-system-setting.vue';
export default {
name: 'App',
components: {
'dialog-system-setting': DialogSystemSetting,
},
data() {
return {};
},
computed: {},
watch: {},
created() {},
mounted() {},
methods: {},
};
src\app.vue <template lang="pug">
.screen
dialog-system-setting
成功的话,目前画面应该会像下图:
浏览器不支援 API 的话,会变这样子。
如果没有选择 Port,点击 Dialog 以外的地方会有错误讯息跳出。
如果点击「选择 COM Port」,则浏览器会跳出弹出视窗,选择 Port 後会自动关闭 Dialog。
以上我们完成 Serial API 的第一步骤「选择 Port」了!
navigator.serial.requestPort()
取得 COM 存取权限以上程序码已同步至 GitLab,大家可以前往下载:
<<: Day5 用python写UI-聊聊视窗控件配置管理员-place方法
在人脸辨识中,常见的是用影像的方式来进行辨识,利用摄影机的方式来撷取影像,利用相似的方式让测试者与资...
今天简单看一下如何设定CloudFront和做图文档和程序码备份 步骤 9 设定CloudFront...
今天的影片为接续上一部的内容,以及介绍几个简单的统计函数 (还有短短的英文小教室...我要去跟英文老...
b. 分析找到的资料并给出一个对根因的假设 在取得资料之後,就要针对这些资料提出一个假设。如果对 Z...
昨天我们已经做好事前准备了,那我们今天就回到views里面,来撰写我们的程序吧! 而我们这次使用的函...