Laws are created and discovered, and memory is the derivation and extraction of laws
background
When I was working on the vue2 mobile terminal project, I made a quick scan code preview function on the mobile terminal. It was very useful in the debugging phase, so I wanted to move it into the vue3 project. I thought it was very simple, but I encountered several problems. stuck me for a long time
- Introduction of global variables
- custom directive
- The instructions of createApp are not shared (the instructions must have been mounted on the element when rendering)
need
When developing on the web side, if you want to quickly see the effect on the mobile phone side, scanning the code and opening it on the browser side is the most convenient choice. At the same time, if you want to preview in the app, the copy function is provided, and the webview synchronization preview is realized through the app's read and paste content + scheme jump function.
Realize ideas
- Use hmr to synchronize the debug page of the same ip
- Dynamically obtain the native IP in the development stage and inject it into the development environment
- Build the component, dynamically generate the corresponding debugging url according to the IP, and generate the corresponding QR code and copy content
- Determine whether to display the component by routing the query parameter
accomplish
Use hmr to synchronize the debug page of the same ip
Both webpack and vite provide the hmr function
Dynamically obtain the native IP in the development stage and inject it into the development environment
nodejs can easily get the native ip:
const os = require("os");
function GetIp() {
let ifaces = os.networkInterfaces();
for (let i in ifaces) {
for (let j in ifaces[i]) {
let alias = ifaces[i][j];
if (
alias.family === "IPv4" &&
alias.address !== "127.0.0.1" &&
!alias.internal
) {
return alias.address;
}
}
}
}
export default GetIp()
复制代码
After getting the ip, webpack injects it through process.env
new webpack.DefinePlugin({
'process.env': {IP: GetIp()}
})
复制代码
vite is injected through define
define: {
VITE_DEV_IP: JSON.stringify(GetIp())
}
复制代码
build components
Only the components of vue3 are shown here
<style lang="less" scoped>
.dev-code {
position: fixed;
top: 50%;
transform: translateY(-50%);
right: 0;
background-color: #ffffff;
.tips {
font-size: 0.18rem;
color: #000;
margin: 0.1rem 0;
text-align: center;
}
.close-btn {
width: 0.4rem;
height: 0.4rem;
position: absolute;
left: 0;
right: 0;
bottom: -0.5rem;
margin: auto;
img {
width: 100%;
height: 100%;
}
}
}
</style>
<template>
<Teleport to="body">
<section
class="dev-code"
v-show="visible == true"
v-clipboard:copy="url"
v-clipboard:success="Tip"
>
<qrcode :value="url" id="qrcode" />
<div class="tips">扫码手机联调</div>
<div class="tips">点击复制链接</div>
<a href="javascript:;" class="close-btn" @click.stop="visible = false">
<img src="https://xxxcdn.xxx.cn/common/close-grey.png" />
</a>
</section>
</Teleport>
</template>
<script lang="ts" setup>
// 调试用二维码
import qrcode from "../qrcode.vue";
import { ref } from "vue";
import { toast } from "../toast/useToast";
defineProps({
url: {
type: String,
// 这里vite通过define定义的全局变量会注入到window对象上,所以命名要独特
default: `${location.protocol}//${window.VITE_DEV_IP}:${location.port}${location.pathname
}${location.search.replace("debug=1", "")}`,
},
});
const visible = ref(true);
function Tip() {
toast("已成功复制,去浏览器打开吧,注意要和电脑在同一局域网哦~");
}
</script>
// 构建渲染函数
import { mountComponent } from "../../lib/utils/mount-component";
import devCodeConstructor from "./devCode.vue";
const debug = () => {
return mountComponent(devCodeConstructor);
};
export default debug;
复制代码
The rendering function can refer toprevious post
Determine whether to display the component by routing the query parameter
Add an interceptor to the router, and display the component when the specified query parameter is read in the development environment
router.afterEach((to, from) => {
if (import.meta.env.MODE === 'development'
&& !!to.query.debug
&& +to.query.debug === 1) {
debug();
}
});
复制代码
question
Introduction of global variables
Previously, webpack used DefinePlugin to inject process.env to achieve
The new framework uses vite, and vite also provides the function of global variable injection, mainly using dotenv to load additional environment variables from files in your environment directory, but dotenv files are static, I don't want other developers to have to Check the ip and write it in by yourself, all you can find is the define options to inject dynamic variables into the window object, but this method needs to pay attention, the injected data must be the string deserialized by Json.stringify, and the string itself must be reversed . Serialize it , everything is for laziness ^_^
The global variables injected by dotenv can be obtained through import.meta.env.development.xxx, you can参考官方文档, define options 也可以参考官方文档
自定义指令
自定义指令主要为了实现复制功能,可以参考我之前的一篇文章
createApp的指令不共用(render的时候指令要已经挂载到元素上)
新的createApp不会公用其他createApp实例的指令,于是对之前的方法做了一个扩展:
import { Component, createApp } from "vue";
import DirectiveExtensions from "../../directive";
export function mountComponent(rootComponent: Component) {
// 添加自定义 指令
const app = createApp(rootComponent).use(DirectiveExtensions);
const root = document.createElement("div");
document.body.appendChild(root);
return {
instance: app.mount(root),
unmount() {
app.unmount();
document.body.removeChild(root);
},
};
}
复制代码