首页
壁纸
直播
留言
关于
友链
统计
Search
1
tampermonkey油猴和谷歌访问助手的安装---破解谷歌访问助手
13,581 阅读
2
安装postcss-px-to-viewport,将px单位转换为视口单位的 (vw, vh, vmin, vmax) 的 PostCSS 插件(有更新postcss弃用,附带vite.config.ts文件)
3,172 阅读
3
编译asar文件与electron反编译
3,117 阅读
4
websocket封装带心跳和重连机制(vue3+ts+vite)
2,737 阅读
5
js一些小功能(持续更新)
2,439 阅读
大前端
JavaScript
CSS
HTML
框架
Vue
electron
element-ui/plus
小程序
微信小程序
uni-app
服务端
Node.js
nginx
PHP
MySQL
工具
杂记
登录
Search
标签搜索
Vue3
Vue
Axios
微信小程序
Javascript
Vuex
js
请求
request
前端
tampermonkey
Google
助手
脚本
小程序云开发
Bootstrap
壁纸
鼠标事件
跨域
css
大祥子i
累计撰写
55
篇文章
累计收到
128
条评论
首页
栏目
大前端
JavaScript
CSS
HTML
框架
Vue
electron
element-ui/plus
小程序
微信小程序
uni-app
服务端
Node.js
nginx
PHP
MySQL
工具
杂记
页面
壁纸
直播
留言
关于
友链
统计
搜索到
14
篇与
Vue3
的结果
2022-08-18
websocket封装带心跳和重连机制(vue3+ts+vite)
import { mitts } from "./tool"; /* * @Author: lzx * @Date: 2022-05-25 15:42:37 * @LastEditors: lzx * @LastEditTime: 2022-08-18 15:01:38 * @Description: Fuck Bug * @FilePath: \talk_pc\src\utils\socket.ts */ let socketUrl: any = ""; // socket地址 let websocket: any = null; // websocket 实例 let heartTime: any = null; // 心跳定时器实例 let socketHeart: number = 0; // 心跳次数 let HeartTimeOut: number = 3000; // 心跳超时时间 let socketError: number = 0; // 错误次数 // 初始化socket const initWebSocket = (url: any) => { socketUrl = url; // 初始化 websocket websocket = new WebSocket(url); websocketonopen(); websocketonmessage(); sendSocketHeart() }; // socket 连接成功 const websocketonopen = () => { websocket.onopen = function (e: any) { console.log("连接 websocket 成功", e); resetHeart(); }; }; // socket 连接失败 const websocketonerror = () => { websocket.onerror = function (e: any) { console.log("连接 websocket 失败", e); }; }; // socket 断开链接 const websocketclose = () => { websocket.onclose = function (e: any) { console.log("断开连接", e); }; }; // socket 接收数据 const websocketonmessage = () => { websocket.onmessage = function (e: any) { let msg = JSON.parse(e.data); if (msg.type === 'heartbeat') { resetHeart() console.log("心跳"); } // console.log("收到socket消息", JSON.parse(e.data)); test(msg) // 测试数据 }; }; // socket 发送数据 const sendMsg = (data: any) => { websocket.send(data); }; // socket 错误 const websocketError = () => { websocket.onerror = function (e: any) { console.log("socket 错误", e); }; }; // socket 重置心跳 const resetHeart = () => { socketHeart = 0; socketError = 0; clearInterval(heartTime); sendSocketHeart(); }; // socket心跳发送 const sendSocketHeart = () => { heartTime = setInterval(() => { if (socketHeart <= 2) { console.log("心跳发送:", socketHeart); websocket.send( JSON.stringify({ content: "", requestId: "aa9872be-d5b9-478e-aba4-50527cd3ef32", type: "heartbeat" }) ); socketHeart = socketHeart + 1; } else { reconnect() } }, HeartTimeOut); }; // socket重连 const reconnect = () => { if (socketError <= 2) { clearInterval(heartTime); initWebSocket(socketUrl); socketError = socketError + 1; console.log("socket重连", socketError); } else { console.log("重试次数已用完的逻辑", socketError); clearInterval(heartTime); } }; // 测试收到消息传递 const test = (msg: any) => { switch (msg.type) { case 'heartbeat': //加入会议 mitts.emit('heartbeat', msg) break; } } export { initWebSocket, websocketonmessage, sendMsg, websocketonopen, websocketonerror, websocketclose, websocketError, resetHeart, sendSocketHeart, reconnect, };
2022年08月18日
2,737 阅读
2 评论
2 点赞
2022-07-08
PresentationAPI使用教程(Vue3&html)
W3C在2020年12月份出台了Presentation API规范,这个api接口允许用户自由控制投放在其他屏幕上,并和投放窗口通信,查看W3C规范。演示地址:投屏演示,详细demo(Vue3/HTML)见文章末尾{alert type="error"} 特别注意:需要注意必须为https环境{/alert} 1、创建一个PresentationRequest对象,该对象将包含我们要在辅助附加显示器上显示的地址。const presentationRequest = new PresentationRequest('receiver.html'); 2、做控制及监听事件/* * @Author: lzx * @Date: 2022-07-08 15:34:16 * @LastEditors: lzx * @LastEditTime: 2022-07-08 17:14:31 * @Description: Fuck Bug * @FilePath: \test\js\index.js */ // 创建个投屏对象 const presentationRequest = new PresentationRequest(['https://blog.fxnws.com']); // 投屏网址 // const presentationRequest = new PresentationRequest(['test.html']);//投屏页面 // Make this presentation the default one when using the "Cast" browser menu. navigator.presentation.defaultRequest = presentationRequest; let presentationConnection; //监视连接是否可用 presentationRequest.addEventListener('connectionavailable', function (event) { presentationConnection = event.connection; presentationConnection.addEventListener('close', function () { console.log('> Connection closed.'); }); presentationConnection.addEventListener('terminate', function () { console.log('> Connection terminated.'); }); presentationConnection.addEventListener('message', function (event) { console.log('> ' + event.data); }); }); //监视可用的显示器 presentationRequest.getAvailability() .then(availability => { console.log('Available presentation displays: ' + availability.value); availability.addEventListener('change', function () { console.log('> Available presentation displays: ' + availability.value); }); }) .catch(error => { console.log('Presentation availability not supported, ' + error.name + ': ' + error.message); }); // 开启投屏 function startProjectionScreen () { presentationRequest.start() .then(connection => { console.log('Connected to ' + connection.url + ', id: ' + connection.id); }) .catch(error => { console.log(error); }); } //发送消息 function sendMsg () { const message = '发送消息测试'; const lang = document.body.lang || 'en-US'; console.log('Sending "' + message + '"...'); presentationConnection.send(JSON.stringify({ message, lang })); } //关闭连接,关闭连接后无法再控制弹出窗口 function closeLink () { console.log('Closing connection...'); presentationConnection.close(); } //关闭连接后,换可以重新再次连接,这里需要指定id // presentationRequest.reconnect(presentationId); //关闭弹窗,结束连接调用 function endLink () { console.log('Terminating connection...'); presentationConnection.terminate(); } 3、连接端页面消息的展示(搬运的官方)/* * @Author: lzx * @Date: 2022-07-08 15:34:16 * @LastEditors: lzx * @LastEditTime: 2022-07-08 15:34:30 * @Description: Fuck Bug * @FilePath: \test\js\test.js */ let connectionIdx = 0; let messageIdx = 0; //如果有连接建立,则调用该函数 function addConnection (connection) { connection.connectionId = ++connectionIdx; addMessage('New connection #' + connectionIdx); connection.addEventListener('message', function (event) { messageIdx++; const data = JSON.parse(event.data); const logString = 'Message ' + messageIdx + ' from connection #' + connection.connectionId + ': ' + data.message; addMessage(logString, data.lang); maybeSetFruit(data.message); connection.send('Received message ' + messageIdx); }); connection.addEventListener('close', function (event) { addMessage('Connection #' + connection.connectionId + ' closed, reason = ' + event.reason + ', message = ' + event.message); }); }; const fruitEmoji = { 'grapes': '\u{1F347}', 'watermelon': '\u{1F349}', 'melon': '\u{1F348}', 'tangerine': '\u{1F34A}', 'lemon': '\u{1F34B}', 'banana': '\u{1F34C}', 'pineapple': '\u{1F34D}', 'green apple': '\u{1F35F}', 'apple': '\u{1F34E}', 'pear': '\u{1F350}', 'peach': '\u{1F351}', 'cherries': '\u{1F352}', 'strawberry': '\u{1F353}' }; function addMessage (content, language) { const listItem = document.createElement("li"); if (language) { listItem.lang = language; } listItem.textContent = content; document.querySelector("#message-list").appendChild(listItem); }; function maybeSetFruit (message) { const fruit = message.toLowerCase(); if (fruit in fruitEmoji) { document.querySelector('#main').textContent = fruitEmoji[fruit]; } }; //文档载入后,监听连接 document.addEventListener('DOMContentLoaded', function () { if (navigator.presentation.receiver) { navigator.presentation.receiver.connectionList.then(list => { list.connections.map(connection => addConnection(connection)); list.addEventListener('connectionavailable', function (event) { addConnection(event.connection); }); }); } }); 4、接收端页面构<!-- * @Author: lzx * @Date: 2022-07-08 15:34:05 * @LastEditors: lzx * @LastEditTime: 2022-07-08 15:35:13 * @Description: Fuck Bug * @FilePath: \test\test.html --> <!doctype html> <html> <head> <meta charset="utf-8"> <title>Demo Receiver</title> <style type="text/css"> html, body { height: 100%; margin: 0; font-family: sans-serif; background: radial-gradient(ellipse at center, #333333 0%, #000000 100%); color: #fff; } #main { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 54px; } </style> <script type="text/javascript" src="引入3的代码块"></script> </head> <body> <div id="main">Hello World!</div> <ul id="message-list"> </ul> </body> </html> 5、vue3页面<template> <div class="container"> <button @click="startProjectionScreen">开启投屏</button> <button @click="sendMsg">发送消息</button> <!-- <button @click="closeLink">关闭连接</button> --> <button @click="endLink">结束调用</button> </div> </template> <script lang="ts"> // @ts-nocheck 不在当前文件中执行类型检查 import { toRefs, reactive, onMounted, watchEffect, onUnmounted } from 'vue' export default { props: {}, components: {}, setup () { const presentationRequest = new PresentationRequest(['https://blog.fxnws.com']); // 投屏网址 // const presentationRequest = new PresentationRequest(['test.html']); // 投屏本地页面 navigator.presentation.defaultRequest = presentationRequest; let presentationConnection; // 传参 const state = reactive({ }) const startProjectionScreen = () => { presentationRequest.start() .then(connection => { console.log('Connected to ' + connection.url + ', id: ' + connection.id); }) .catch(error => { console.log(error); }); } //发送消息 const sendMsg = () => { const message = '发送消息测试'; const lang = document.body.lang || 'en-US'; console.log('Sending "' + message + '"...'); presentationConnection.send(JSON.stringify({ message, lang })); } //关闭连接,关闭连接后无法再控制弹出窗口 const closeLink = () => { console.log('Closing connection...'); presentationConnection.close(); } //关闭连接后,换可以重新再次连接,这里需要指定id // presentationRequest.reconnect(presentationId); //关闭弹窗,结束连接调用 const endLink = () => { console.log('Terminating connection...'); presentationConnection.terminate(); } // 挂载 onMounted(() => { //监视连接是否可用 presentationRequest.addEventListener('connectionavailable', function (event) { presentationConnection = event.connection; presentationConnection.addEventListener('close', function () { console.log('> Connection closed.'); }); presentationConnection.addEventListener('terminate', function () { console.log('> Connection terminated.'); }); presentationConnection.addEventListener('message', function (event) { console.log('> ' + event.data); }); }); //监视可用的显示器 presentationRequest.getAvailability() .then(availability => { console.log('Available presentation displays: ' + availability.value); availability.addEventListener('change', function () { console.log('> Available presentation displays: ' + availability.value); }); }) .catch(error => { console.log('Presentation availability not supported, ' + error.name + ': ' + error.message); }); }) // 监听 watchEffect(() => { console.log('监听') }) // 页面卸载 onUnmounted(() => { console.log('页面卸载') }) return { ...toRefs(state), endLink, closeLink, sendMsg, startProjectionScreen } } } </script> <style scoped> </style> 6、详细demo附件下载隐藏内容,请前往内页查看详情2024年11月04日更新,看到评论区有部分朋友,遇到问题,我更新了相关Git完整Demo地址见下文1、vue3+ts+vite 报错 PresentationRequest 未定义 答:应该是ts未定义的报错,我当时做这个的时候,这个功能刚推出ts支持应该不完善,我也不想去定义相关的ts就直接使用// @ts-nocheck(这个指令用于告诉TypeScript编译器不在当前文件中执行类型检查)2、发现用ip访问不行,用127.0.0.1可以 答:直接用IP不行是因为没有https支持吧,我记得这个协议是需要https的支持的,具体要看下报错信息了,127.0.0.1是本机地址所以没事{alert type="warning"} 码云 {/alert}{alert type="warning"} Github {/alert}
2022年07月08日
798 阅读
43 评论
0 点赞
2022-06-21
vue3使用vue-clipboard3复制到剪切板
使用vue-clipboard3实现复制到剪切板,首先引入:npm install --save vue-clipboard3(详见)使用教程<template lang="html"> <div> <button @click="copyInfo('我是copy的内容')">点我复制</button> </div> </template> <script lang="ts"> import useClipboard from 'vue-clipboard3' export default { setup() { const { toClipboard } = useClipboard() const copyInfo = async (info) => { try { await toClipboard(info) ElMessage.success('复制成功') } catch (e) { ElMessage.warning('您的浏览器不支持复制:', e) } } return { copyInfo } } } </script>
2022年06月21日
1,363 阅读
0 评论
0 点赞
2022-06-14
Vue3使用高德地图
1、首先要在高德开发平台申请开发者账号申请key(文档)// npm引入 npm i @amap/amap-jsapi-loader --save cnpm i @amap/amap-jsapi-loader --save2、封装map.ts// 创建map.js /* * @Author: lzx * @Date: 2022-06-09 11:33:28 * @LastEditors: lzx * @LastEditTime: 2022-06-09 13:01:47 * @Description: Fuck Bug * @FilePath: \lzds\src\utils\map.ts */ import AMapLoader from '@amap/amap-jsapi-loader' // 使用加载器加载JSAPI,可以避免异步加载、重复加载等常见错误加载错误 /** * 高德地图 * @param {*} map */ const initMap = (map: any) => { AMapLoader.load({ key: "XXXXXXXXXXXXXXXXXXX", // 申请好的Web端开发者Key,首次调用 load 时必填 version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15 plugins: [ "AMap.Scale", //工具条,控制地图的缩放、平移等 "AMap.ToolBar", //比例尺,显示当前地图中心的比例尺 "AMap.Geolocation", //定位,提供了获取用户当前准确位置、所在城市的方法 "AMap.HawkEye", //鹰眼,显示缩略图 ], // 需要使用的的插件列表,如比例尺'AMap.Scale'等 }) .then((AMap) => { let map = new AMap.Map("map", {//设置地图容器id zoom: 10, //初始化地图层级 viewMode: "3D", //是否为3D地图模式 center: [116.397128, 39.916527], //初始化地图中心点位置 dragEnable: true, //禁止鼠标拖拽 scrollWheel: true, //鼠标滚轮放大缩小 doubleClickZoom: true, //双击放大缩小 keyboardEnable: true, //键盘控制放大缩小移动旋转 }); map.setDefaultCursor("pointer"); //使用CSS默认样式定义地图上的鼠标样式(default/pointer/move/crosshair) map.addControl(new AMap.Scale()); //异步同时加载多个插件 map.addControl(new AMap.ToolBar()); map.addControl(new AMap.Geolocation()); let HawkEye = new AMap.HawkEye({ position: "LT", //控件停靠位置(LT/RT/LB/RB) }); map.addControl(HawkEye); map.add( new AMap.Marker({ position: map.getCenter(), }) ); // map.add(marker); // 地图添加标记 AMapLoader.load({ // 可多次调用load plugins: ["AMap.MapType"], key: '', version: '' }) .then((AMap) => { map.addControl(new AMap.MapType()); }) .catch((e) => { console.error(e); }); // 显示地图层级与中心点信息 function logMapinfo() { let zoom = map.getZoom(); //获取当前地图级别 let center = map.getCenter(); //获取当前地图中心位置 } //绑定地图移动与缩放事件 map.on("moveend", logMapinfo); map.on("zoomend", logMapinfo); //为地图注册click事件获取鼠标点击出的经纬度坐标 map.on("click", function (e: any) { // 点击事件 }); let infoWindow = new AMap.InfoWindow({ //创建信息窗体 isCustom: false, //使用自定义窗体 anchor: "top-right", //信息窗体的三角所在位置 content: `<a href="#">XXX信息</a>`, //信息窗体的内容可以是任意html片段 offset: new AMap.Pixel(-10, -5), }); infoWindow.open(map, [116.397128, 39.916527]); //填写想要窗体信息指示的坐标 }) .catch((e) => { console.log(e); }); } export { initMap };3、引入封装的map.ts并且使用// 使用ref获取dom <div id="map" ref="map"></div> import { initMap } from '@/utils/map' const map = ref(null) initMap(map)
2022年06月14日
1,043 阅读
0 评论
26 点赞
2022-06-14
Vue3使用拼图验证码校验
1、在Vue3中使用图片拼图验证码npm i vue3-slide-verify(详见)2、代码中使用(未封装,有需要可以封装)<div> <slide-verify ref="block" slider-text="向右滑动->" :accuracy="1" @again="onAgain" @success="onSuccess" @fail="onFail" @refresh="onRefresh"></slide-verify> <button class="btn" @click="handleClick">在父组件可以点我刷新哦</button> <div>{{ msg }}</div> </div> <script> import { toRefs, reactive, ref } from 'vue' // 局部注册组件,需要单独引用组件样式 // 只提供局部引用的方式,不再采用插件形式,方便按需加载,减少主包大小 import SlideVerify from "vue3-slide-verify"; import "vue3-slide-verify/dist/style.css"; export default { components: { SlideVerify }, setup(props, { emit }) { const msg = ref(""); const block = ref(); // 传参 const state = reactive({ }) const onAgain = () => { msg.value = "检测到非人为操作的哦! try again"; // 刷新 block.value?.refresh(); } const onSuccess = (times) => { msg.value = `login success, 耗时${(times / 1000).toFixed(1)}s`; } const onFail = () => { msg.value = "验证不通过"; } const onRefresh = () => { msg.value = "点击了刷新小图标"; } const handleClick = () => { // 刷新 block.value?.refresh(); msg.value = ""; } return { block, msg, onAgain, onSuccess, onFail, onRefresh, handleClick, } } } </script>3、其他备注argumentParamTypeDescribeVersionlNumberblock length rNumberblock circle radius wNumbercanvas width hNumbercanvas height sliderTextStringSlide filled right imgsArraypicture array 背景图数组,默认值 [] accuracyNumber滑动验证的误差范围,默认值 5 showBoolean是否显示刷新按钮,默认值 true callBackEventTypeDescribeVersionsuccessFunctionsuccess callback返回时间参数,单位为毫秒failFunctionfail callback refreshFunction点击刷新按钮后的回调函数 againFunction检测到非人为操作滑动时触发的回调函数
2022年06月14日
1,266 阅读
0 评论
52 点赞
1
2
3