关于vue3:轻快图片管理系统-系统概述与内置功能介绍

<article class=“article fmt article-content”><h2>在线体验</h2><p><strong>如果你感觉我的项目不错,还望动动你的手指给点点star,让更多人看到优良的我的项目!!!</strong></p><p>为了便于大家在线体验,本零碎提供了演示地址,能够通过上面的演示地址和账号进行登录体验零碎性能。<br/><strong>演示地址</strong>: http://v2.picture.itchenliang.club/#/<br/><strong>演示账号:</strong></p><pre><code class=“yaml”>账号: guest@163.com明码: 000000</code></pre><p><strong>代码仓库地址:</strong> <br/>如果你感觉我的项目不错,还望动动你的手指给点点star,让更多人看到优良的我的项目!!!</p><ul><li>Github: https://github.com/ischenliang/quickly-picture-bed</li><li>Gitee: https://gitee.com/itchenliang/quickly-picture-bed</li></ul><h2>零碎概述</h2><p><strong>轻快图片管理系统</strong>顾名思义是一个做图片治理的零碎,和当初市面上很火的Picgo相似,然而因为Picgo是本地版的,即须要本人装置桌面端利用后能力应用,每次换一台电脑都须要重新安装一次,而后再装置指定的图床插件并配置插件,非常麻烦。</p><p>为了解决下面问题的问题,故诞生了这个<strong>轻快图片管理系统</strong>,这个是一个在线版的BS零碎,只须要装置部署一次后就能够重复应用,只须要你应用浏览器拜访装置部署地址即可,如果你不想装置部署也能够间接在演示环境上操作。</p><p><strong>轻快图片管理系统</strong>能够看做是<strong>集成多种第三方对象存储于一身的零碎</strong>,目前不同的第三方对象存储是采纳拔插式的插件形式来实现,不便后续扩大新的第三方对象存储,这种形式能够在不重新部署零碎的状况下更快的集成新的对象存储。</p><h2>与Picgo的差别</h2><p>通过本零碎,在装置部署后同样须要像Picgo那样装置指定的存储插件后能力创立存储桶,和picgo的差别在于,picgo装置图床插件后,每个插件只能配置一个存储桶,当想要配置多个时也无奈实现,但在本零碎上是能够同一个存储桶插件配置多个存储桶,而后将图片上传到指定的存储桶中,同时本零碎也新增了相册治理性能,能够将不同类别的图片进行分组治理。</p><h2>开发所应用技术</h2><p><strong>前端</strong>: Vue3.x、Vite4.x、VueRouter、Pinia、Axios、Typescript、ElementPlus、Echarts、Sass、clipboard、bytemd、monaco-editor等<br/><strong>后端</strong>: Nestjs + Express、Typescript、sequelize、axios、nodemailer、svg-captcha、jsonwebtoken<br/><strong>权限认证</strong>:RBAC(角色访问控制)模式进行认证受权<br/><strong>数据库</strong>: mysql57<br/><strong>插件</strong>: rollup、pnpm + monorepo、crypto-js、typeScript、webcomponents(工具插件)</p><h2>内置性能</h2><ul><li><p><strong>登录、注册、找回明码</strong></p><ul><li>登录: 反对账号密码登录、验证码登录两种登录形式。</li><li>注册: 须要应用邮箱账号进行注册。</li></ul></li><li><p><strong>图片上传</strong></p><ul><li>目前反对多种图片上传形式: 抉择上传、拖拽上传、粘贴复制上传、URL网络图上传、Base64上传;</li><li>反对多图上传;</li><li><p>反对一键复制多种链接图片外链格局:</p><ul><li>链接格局: URL、HTML、CSS、Markdown、超链接、论坛代码、UBB、自定义;</li><li>也反对一键复制多图的链接格局;</li></ul></li><li>反对上传预览并能够拖拽排序进而实现链接复制的程序;</li></ul></li><li><p><strong>图片治理</strong></p><ul><li>图片治理就是对在该零碎上上传过的图片记录进行治理;</li><li>该性能反对: 复制图片链接格局、删除图片、图片重命名、拖拽排序、移入指定相册等性能;</li></ul></li><li><p><strong>存储桶治理</strong></p><ul><li>存储桶治理即是对第三方对象存储的配置进行治理;</li><li>反对多桶贮存,可同时增加多个对象存储桶治理;</li><li>该性能反对: 新建存储桶、更新存储桶、禁用存储桶、删除存储桶、存储桶数据迁徙、拖拽排序等性能;</li></ul></li><li><p><strong>相册治理</strong></p><ul><li>相册治理即是对相册进行分组治理,便于用户将不同的图片进行分类管理,同时也反对间接将图片上传到相册中;</li><li>相册治理中也能够对图片进行标签配置,对不同的图片配置指定的标签便于二级分组;</li><li>该性能反对: 新建相册、编辑相册、删除相册、拖拽排序、图片间接上传到相册、模板标签治理、设定相册封面等性能;</li></ul></li><li><p><strong>插件市场</strong></p><ul><li><p>插件市场是零碎的外围性能,目前反对三大类插件:上传插件、主题插件、工具箱插件。</p><ul><li>【上传插件】简略来说就是对常见的第三方对象存储集成,目前反对数十种内置插件,其中包含: 阿里云OSS、腾讯云COS、七牛云Kodo、又拍云USS、青云qingstor等;而且还在一直开发新的插件。</li><li>【工具箱插件】能够看做是对一些罕用的工具封装,例如:uuid生成器、图片裁剪、代码转图片、图片base64编码等。</li><li>【主题插件】为了实现主题切换性能,零碎则内置了主题插件性能,和vscode相似能够通过装置指定的主题插件来达到想要的配色计划,例如:monokai主题、暗黑主题、OneDarkPro主题等,此外零碎外部还默认了一套亮色主题。</li></ul></li><li>想要应用存储桶性能的前提就是须要装置指定的插件后能力创立存储桶;</li><li>该性能反对: 插件装置、插件更新、卸载插件、启用/禁用插件等性能;</li></ul></li><li><p><strong>仪表盘 | 数据统计</strong></p><ul><li>仪表盘是对本用户在零碎上的一些应用数据进行数据统计分析,例如:有多少张图片、多少个存储桶、装置了多少个插件、多少个相册等。</li><li>同时为了便于剖析也提供了奉献图、近一年内的所有数据进行统计分析</li></ul></li><li><p><strong>知识库治理</strong></p><ul><li>思考到目前大多数人应用图床零碎都是联合着文档一起在应用,故开发了知识库治理性能,知识库治理和其余大多数平台的性能类似。</li><li>该性能反对: 创立知识库、更新知识库、复制知识库、删除知识库、一键导出知识库下的所有文档等性能;</li><li>文档治理: 知识库下有文档治理性能,能够在该知识库下创立多个文章和目录,同时还能够进行拖拽调整文档的目录程序。</li></ul></li><li><p><strong>操作日志</strong></p><ul><li>残缺的可视化日志性能,记录用户所有操作,不便事件溯源。普通用户只能查看本人的操作记录,管理员则能查看所有人员的操作记录,于此同时数据统计中的奉献图的数据起源也是从操作记录中提取。</li><li>目前反对图片操作日志、存储桶操作日志、相册操作日志、插件操作日志等;</li></ul></li><li><p><strong>个人信息保护</strong></p><ul><li>用户能够对本人的信息管理,如头像(零碎内置4组不同维度的头像供选择)、昵称、职业、性别、个人简介以及集体登录明码进行保护治理。</li></ul></li><li><p><strong>偏好设置</strong></p><ul><li>思考到每个用户的应用习惯不同,零碎提供了偏好配置核心,能够对默认复制的图片链接格局、自定义链接格局、罕用快捷键配置、图片显示名称类型、主题配置、以及各种图片的层现形式。</li></ul></li><li><p><strong>用户治理</strong></p><ul><li>多用户治理,依据不同的角色能够治理不同的数据,同时用户能够通过自主注册或者管理员在治理页面间接创立。</li><li>该性能反对: 新建用户、删除用户、更新用户、禁用/启用用户、删除用户等性能;</li></ul></li><li><p><strong>插件治理</strong></p><ul><li>插件治理是对本零碎中反对哪些内置插件进行治理,目前反对的插件类别有文件上传插件、主题插件、图片转换插件、图片解决插件、全局插件、工具箱插件等;</li><li>目前零碎上所有的插件都是通过rollup + pnpm + monorepo模式进行开发的,而后打包后公布到npm上,而后代码中通过指定的伎俩来加载该插件。</li><li>该性能反对: 新增插件、更新插件、启用|禁用插件、删除插件、拖拽排序等性能。</li></ul></li><li><p><strong>字典治理</strong></p><ul><li>对系统中常常应用的一些较为固定的数据进行保护,例如集体核心的职业、用户性别、存储桶页面不同的存储桶展现不同的图标等数据保护。</li><li>该性能反对: 新建字典、删除字典、更新字典、删除字典等性能;</li></ul></li><li><p><strong>零碎设置</strong></p><ul><li>对系统中一些罕用的数据进行保护,包含零碎名称、零碎logo、备案信息、更新日志、零碎上所应用的的图标的起源进行配置。</li></ul></li><li><p><strong>权限管制</strong></p><ul><li>残缺的权限管制性能,基于RABC进行权限管制,即针对不同的角色可调配不同的操作权限,管制对应的增删改查的能力。</li></ul></li></ul></article>

March 4, 2024 · 1 min · jiezi

关于vue3:Vue3如何使用Pinia状态管理库与持久化

<article class=“article fmt article-content”><p>大家好,我是你们的好敌人咕噜铁蛋!明天我将和大家分享如何在Vue3中应用Pinia状态治理库以及实现状态长久化的办法。作为一个Vue开发者,咱们晓得状态治理在大型应用程序中起着至关重要的作用。而Pinia作为Vue3举荐的状态治理库之一,提供了简洁弱小的状态治理解决方案,同时联合长久化性能,能够更好地满足咱们的开发需要。<br/>上面让咱们一起深刻理解如何联合Vue3和Pinia来管理应用程序的状态,并实现状态长久化吧!<br/>什么是Pinia状态治理库?<br/>Pinia是一个专为Vue3设计的状态治理库,它借鉴了Vuex的一些概念,但更加轻量灵便,使得状态治理变得更加简略直观。Pinia通过提供一种基于Vue3响应式API的状态管理机制,让咱们能够更加优雅地管理应用程序的状态。</p><h3>如何在Vue3中应用Pinia状态治理库?</h3><ol><li><p>装置Pinia<br/>首先,咱们须要在Vue3我的项目中装置Pinia。能够通过npm或yarn来进行装置:</p><pre><code class=“bash”>npm install pinia# 或yarn add pinia</code></pre></li><li><p>创立Pinia实例<br/>在Vue3我的项目的入口文件(通常是<code>main.js</code>)中,咱们须要创立一个Pinia实例,并将其挂载到应用程序上:</p><pre><code class=“javascript”>import { createApp } from ‘vue’import { createPinia } from ‘pinia’import App from ‘./App.vue’const app = createApp(App)const pinia = createPinia()app.use(pinia)app.mount(’#app’)</code></pre></li><li><p>定义和应用Store<br/>接下来,咱们能够定义一个Store来管理应用程序的状态。能够通过<code>defineStore</code>办法创立一个Store:</p><pre><code class=“javascript”>import { defineStore } from ‘pinia’export const useMyStore = defineStore({ id: ‘myStore’, state: () => ({ count: 0, }), actions: { increment() { this.count++ }, },})</code></pre><p>而后在组件中应用这个Store:</p><pre><code class=“vue”><template> <div> <p>Count: {{ $store.myStore.count }}</p> <button @click="$store.myStore.increment()">Increment</button> </div></template><script>import { defineComponent } from ‘vue’import { useMyStore } from ‘./store’export default defineComponent({ setup() { const store = useMyStore() return { store } },})</script></code></pre><p>如何实现状态长久化?<br/>在理论开发中,有时候咱们心愿将应用程序的状态长久化存储,以便在刷新页面或从新关上应用程序时可能保留之前的状态。上面介绍一种简略的办法来实现状态长久化:</p></li><li><p>应用<code>localStorage</code>进行本地存储<br/>咱们能够利用浏览器提供的<code>localStorage</code>API来进行本地存储。在Store中增加<code>init</code>办法,在创立Store实例时从<code>localStorage</code>中初始化状态:</p><pre><code class=“javascript”>import { defineStore } from ‘pinia’export const useMyStore = defineStore({ // 省略其余代码 actions: { init() { const count = localStorage.getItem(‘count’) if (count) { this.count = parseInt(count, 10) } }, },})</code></pre></li><li><p>在应用程序初始化时调用<code>init</code>办法<br/>在Vue3的入口文件中,在创立Pinia实例后,调用Store的<code>init</code>办法来初始化状态:</p><pre><code class=“javascript”>// 省略其余代码const pinia = createPinia()const myStore = useMyStore()myStore.init()// 省略其余代码</code></pre><p>通过以上办法,咱们能够实现简略的状态长久化性能,让应用程序在刷新或从新关上时可能复原之前的状态。<br/>明天介绍了如何在Vue3中应用Pinia状态治理库,并联合简略的办法实现状态长久化性能。Pinia作为一个灵便弱小的状态治理解决方案,可能帮忙咱们更好地管理应用程序的状态,晋升开发效率和用户体验。心愿本文对你有所帮忙,如果有任何问题或倡议,欢送在评论区留言,咱们一起学习提高!感激大家的浏览,咱们下期再见!</p></li></ol></article> ...

February 29, 2024 · 1 min · jiezi

关于vue3:vue3组件常用的通信方式

<article class=“article fmt article-content”><h2>形式一:props</h2><p>props是实现父组件向子组件传递信息,props的数据是只读的。</p><p>应用实例:</p><p>父组件:</p><pre><code><script setup lang=“ts”> // 导入子组件 import Child from ‘./Child.vue’ import { ref } from ‘vue’; const money = ref(1000);</script><template> <div class=“box”> <h1>我是父组件</h1> <hr /> <Child info=“我是父组件参数” :money=“money”></Child> </div></template></code></pre><p>子组件:须要应用到<strong>defineProps</strong>办法去承受父组件传递过去的数据。</p><pre><code><script setup lang=“ts”>//defineProps是Vue3提供办法,不须要引入间接应用let props = defineProps([‘info’,‘money’]); //数组|对象写法都能够</script><template> <div class=“box”> <h1>我是子组件</h1> <div style=“color: red;">{{info}}<p>{{money}}</p></div> </div> </template></code></pre><p>效果图:<br/></p><h2>形式二:emit</h2><p>emit形式是Vue3中最常见的组件通信形式,该形式用于子传父。</p><p>父组件中:</p><pre><code><template> <h1>我是父组件</h1> <p style=“color: brown;">{{ list }}</p> <hr /> <!– add是子组件要传递的事件名称,handleAdd是监听到之后执行的事件 –> <Child @add=“handleAdd”></Child></template><script setup lang=“ts”> // 导入子组件 import Child from ‘./Child.vue’; import { ref } from ‘vue’; const list = ref(”"); const handleAdd = (item: string) => { list.value = item; }; </script></code></pre><p>子组件中:</p><pre><code><script setup lang=“ts”> const emits = defineEmits([‘add’]); const handleBtn = () => { emits(‘add’, ‘哈哈哈哈,我是子组件参数’); }</script><template> <div class=“box”> <h1>我是子组件</h1> <button @click=“handleBtn”>点击我</button> </div></template></code></pre><p>成果视频:<br/></p><h2>办法三:pinia</h2><p>Pinia 是一个专门为Vue.js设计的状态治理库,它提供了一种简略和直观的形式来管理应用程序的状态。在应用Pinia时,能够轻松地创立定义状态的存储,而后将其与Vue组件绑定,使它们可能应用该状态。与Vuex相比,Pinia 更加简略易用,体积更小,同时具备更好的 TypeScript 反对和插件零碎。</p><h4>装置和配置Pinia</h4><pre><code>yarn add pinia# 或者应用 npmnpm install pinia</code></pre><p>在装置完Pinia包之后,须要在main.ts文件中导入createPinia函数并将Pinia插件与Vue应用程序绑定,如下所示:</p><pre><code>import { createApp } from ‘vue’;import { createPinia } from ‘pinia’;import App from ‘./App.vue’;const app = createApp(App);const pinia = createPinia();app.use(pinia);app.mount(’#app’);</code></pre><p>应用 createPinia() 函数创立并初始化Pinia插件实例,将其与Vue应用程序绑定应用app.use(pinia)。至此,咱们就能够应用Pinia来治理Vue应用程序的状态了。</p><p>在src下创立stores文件夹,而后在stores文件夹创立counter.ts文件,外面配置如下:</p><pre><code>import { defineStore } from ‘pinia’export const useStore = defineStore(‘storeId’, { state: () => { return { } }, getters: { }, actions: { },})</code></pre></article> ...

February 27, 2024 · 1 min · jiezi

关于vue3:vue3使用ElementPlus-upload上传文件的两种方式

1. 不应用action a: html局部(上传单个文件) <el-upload class="avatar-uploader" action="#" :limit="1" :show-file-list="false" :http-request="handleUpload" :before-upload="handleChange" accept=".png,.jpe,.jpeg" ref="uploadBanner"> <img v-if="formData.appLogo" :src="formData.appLogo" class="avatar" /> <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon> <el-icon v-if="formData.appLogo" class="logoDelete" @click.stop="clearUploadImg" ><CircleCloseFilled /></el-icon></el-upload>b: js局部 // 上传const handleChange = (rawFile) => { if (rawFile.type !== "image/jpeg" && rawFile.type !== "image/png") { ElMessage.error("只能上传jpeg/jpg/png图片"); return false; } else if (rawFile.size / 1024 / 1024 > 1) { ElMessage.error("上传图片最大不超过1MB!"); return false; } return true;};const handleUpload = async (file) => { let fd = new FormData(); fd.append("file", file.file); // 这里是申请上传接口 let result = await uploadFile(fd); if (result.code == 200) { // 后盾只返回文件名称,须要拼接 formData.value.appLogo = import.meta.env.VITE_APP_HOSTURL + import.meta.env.VITE_APP_BASEURL + "file/previewFile/" + result.data; // 去掉form表单验证的* // formRef.value.clearValidate(['appLogo']) // 上传胜利清空文件 uploadBanner.value.handleRemove(file); } else { formData.value.appLogo = ""; ElMessage.error(result.message); uploadBanner.value.handleRemove(file); }};const clearUploadImg = (file) => { formData.value.appLogo = ""; uploadBanner.value.clearFiles();};2. 应用action上传a. html局部(上传多个文件) ...

February 23, 2024 · 2 min · jiezi

关于vue3:vue3-复合式写法之ref另外的用法获取节点父组件调用子组件方法

应用ref来获取节点信息<template> <div ref="DOM">xx</div></template><script setup>/* */import {ref} from 'vue'const DOM = ref(null)console.log(DOM) // <div/>xx</div></script>应用ref 进行父组件调用子组件办法网上一些博客间接应用ref调用是不能够的,须要应用vue3的API defineExpose办法将子组件的属性办法和须要裸露进去的属性放进去才能够调用 父组件 <template> <childComponent ref="DOM" /> <button @click="handleClick">click to handle child event</button></template><script setup>import {ref} from 'vue'const DOM = ref(null)function handleClick() { DOM.value.childClickEvent()}</script>子组件 <template> <div>child component</div></template><script setup>import {defineExpose} from 'vue'function chlidClickEvent() { // }defineExpose({ childClickEvent})</script>

September 26, 2023 · 1 min · jiezi

关于vue3:关于vue异步加载组件动态路由加载组件的问题

目前应用vite搭建后盾管理系统,遇到了异步加载路由组件的问题,加上之前vue2的时候异步加载路由组件一起做个整顿,之前做过vue2,所以vue2和vue2一起做个整顿,先说vue3。 以后应用vue3创立动静组件路由办法 const dynamicRoutes = [ { ..., component: () => import('@/views/xx.vue') }]但通常的话后端会返回组件的地址,import里就会传个动静值,值为组件门路,但应用vite&vue3搭建的话会有告警 component: () => import(obj.componentPath)The above dynamic import cannot be analyzed by Vite.See https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations for supported dynamic import formats. If this is intended to be left as-is, you can use the /* @vite-ignore */ comment inside the import() call to suppress this warning.网上搜了vue3+vite有两种计划 应用vue3的API defineAsyncComponent加上正文 / @vite-ignore /应用import.meta.glob 这种办法尝试后失败,就没深入研究shadowRef和defineAsyncComponent配合应用,还没尝试

September 26, 2023 · 1 min · jiezi

关于vue3:关于-vue3-的-二维码组件vue3nextqrcode

Vue3NextQrcode应用 TypeScript 基于 awesome-qr.js 与 Vue3 开发的二维码组件。反对丰盛的配置属性,并且反对:LOGO、BackgroundImage、GIF 等。简略配置,即可应用丑陋难看的二维码~ 效果图动图(GIF) 标记(LOGO) 背景图(BackgroundImage) 装置npm i vue3-next-qrcodeProps 配置项名称类型默认值阐明版本watchTextbooleantrue是否启用主动监听内容变换后,从新渲染二维码*statusQRCodeStatusundefined二维码状态*errorDescriptionstring \VNode二维码已过期status error 状态下的形容文案*errorActionDescriptionstring从新加载status error 状态下的按钮形容文案*textstring必填二维码填充内容*sizenumber160二维码渲染尺寸*marginnumber12二维码主体四周的边距大小(以像素为单位)*correctLevelnumber1二维码纠错等级(0-3)*maskPatternnumberundefined指定二维码编码时应用的掩码图案,承受QRMaskPattern提供的值*versionnumberundefined指定二维码编码应用的版本,承受[1-40]整数*componentsComponentOptions{}用于管制二维码中的组件的选项*colorDarkstring#000000二维码上方块的色彩*colorLightboolean#ffffff二维码上方块的色彩*autoColorbooleantrue主动计算二维码背景的colorLight值*backgroundImagestringundefined二维码背景图*backgroundDimmingstringrgba(0, 0, 0, 0)背景图像上方调光蒙版的色彩*gifBackgroundURLstringundefinedgif 图链接地址*gifBackgroundArrayBufferundefinedgif 图文件流*whiteMarginbooleantrue应用红色边距而不是通明边距,通明边距会显示边距上二维码的背景*logoImagestringundefined二维码 logo*logoScalenumber0.4logo 与二维码尺寸的比例*logoMarginnumber6logo 边距尺寸*logoCornerRadiusnumber8二维码圆角尺寸*dotScalenumber1块的理论大小与残缺大小的比率,当您想要使背景的更多局部可见时,这会很有帮忙。*onSuccess(dataURL: ArrayBuffer \string \undefined) => voidnull二维码渲染胜利回调*onError(e: unknown) => voidnull二维码渲染失败回调*onReload() => voidnullstatus error 状态下点击从新加载按钮回调,如果应用了 errorAction 插槽该办法不会执行*Slots名称参数阐明版本errorAction()status error 状态下的自定义展现款式*应用示例根底二维码<script lang="ts" setup>import { Vue3NextQrcode } from 'vue3-next-qrcode'</script><template> 根底二维码 <Vue3NextQrcode text="hello" /> LOGO 二维码 <Vue3NextQrcode text="hello" logoImage="your logo image" /> BackgroundImage 二维码 <Vue3NextQrcode text="hello" backgroundImage="your logo image" /></template>GIF 二维码留神:应用 GIF URL 的时候,应该应用 gifBackgroundURL 属性。 ...

September 22, 2023 · 1 min · jiezi

关于vue3:如何基于-vue3x-编写自己的-hook

什么是 hooks函数式编程在前端开发中越来越风行,尤其是在古代前端框架 Vue3.x 和 React 16+ 中。它的长处包含代码可读性、可维护性、可测试性和复用性。 学习如何利用框架提供的钩子(hooks)编写自定义钩子函数是十分重要的技能之一。通过编写自定义钩子函数,咱们能够满足特定需要,使咱们的代码更加灵便和可扩大。 把握函数式编程和钩子的应用,可能进步咱们的开发效率,同时提供更好的用户体验和代码品质。在应用 Vue3.x 或 React 16+ 等古代前端框架时,函数式编程和自定义钩子函数将成为咱们必备的技能。 优良的 vue3.x hooks 库vue-hooks-plusvueuse两个杰出的开源库,它们简直能够满足各种场景的需要。然而,学习如何独立编写代码也是十分重要的。通过亲自动手编写代码,咱们可能深刻了解底层原理,造就本人的解决问题的能力。 起步假如你曾经理解并且把握 vue3.x ts,所以不做过多的赘述。废话不多说,间接上手~~~ useElementBounding 办法这里以该办法作为例子解说。 功能分析依据办法名称,咱们能够直观地理解到这个办法的作用是用于动静获取元素的坐标和尺寸信息。 该办法提供了一种便捷的形式来获取元素的地位和大小。通过调用这个办法,咱们能够动静地获取元素的坐标、宽度、高度等信息,以便在开发过程中进行相应的操作和布局调整。 参数剖析待监听的 dom配置监听条件 options开发配置项类型interface UseElementBoundingOptions { /** * * When the component is mounted, initialize all values to 0 * * @default true */ reset?: boolean /** * * windowResize * * @default true */ windowResize?: boolean /** * * windowScroll * * @default true */ windowScroll?: boolean /** * * immediate * * @default true */ immediate?: boolean}interface UseElementBoundingReturnType { width: Ref<number> height: Ref<number> top: Ref<number> left: Ref<number> bottom: Ref<number> right: Ref<number>}辅助函数type TargetValue<T> = T | undefined | nulltype TargetType = HTMLElement | Element | Window | Document | ComponentPublicInstanceexport type BasicTarget<T extends TargetType = Element> = | (() => TargetValue<T>) | TargetValue<T> | Ref<TargetValue<T>> function getTargetElement<T extends TargetType>(target: BasicTarget<T>, defaultElement?: T) { if (!isBrowser) { return undefined } if (!target) { return defaultElement } let targetElement: TargetValue<T> if (typeof target === 'function') { targetElement = target() } else if (isRef(target)) { targetElement = (target.value as ComponentPublicInstance)?.$el ?? target.value } else { targetElement = target } return targetElement}正式开发export default function useElementBounding( target: BasicTarget, options?: UseElementBoundingOptions,): UseElementBoundingReturnType { const { reset = true, windowResize = true, windowScroll = true, immediate = true } = options ?? {} const size = reactive({ width: 0, height: 0, top: 0, left: 0, bottom: 0, right: 0, }) // 定义更新函数 const update = () => { // 获取 dom const targetDom = getTargetElement(target) if (!targetDom) { // 组件装置后,将所有值初始化为 0 if (reset) { Object.keys(size).forEach(key => { if (keyisUseElementBoundingReturnTypeKey(key)) size[key] = 0 }) } return } if (targetDom) { // 应用 getBoundingClientRect 办法,获取元素信息 const { width, height, top, left, bottom, right } = targetDom.getBoundingClientRect() size.width = width size.height = height size.top = top size.left = left size.bottom = bottom size.right = right } } // 窗口尺寸产生更改时触发更新 if (windowResize) { useEventListener('resize', update, { // 事件监听器不会调用 preventDefault() 办法来阻止默认行为。这样能够进步滚动的性能,并且缩小滚动操作的提早。 passive: true, }) } // 窗口滚动时触发更新 if (windowScroll) { useEventListener('scroll', update, { capture: true, passive: true, }) } // 元素尺寸更改时触发更新 useResizeObserver(target, update) // 代理对象产生更改时触发更新 watch(() => getTargetElement(target), update) onMounted(() => { immediate && update() }) return { ...toRefs(size), }}残缺代码import { onMounted, reactive, toRefs, Ref, watch } from 'vue'import useResizeObserver from '../useResizeObserver'import useEventListener from '../useEventListener'import { BasicTarget, getTargetElement } from '../utils/domTarget'export interface UseElementBoundingOptions { /** * * When the component is mounted, initialize all values to 0 * * @default true */ reset?: boolean /** * * windowResize * * @default true */ windowResize?: boolean /** * * windowScroll * * @default true */ windowScroll?: boolean /** * * immediate * * @default true */ immediate?: boolean}function keyisUseElementBoundingReturnTypeKey(key: string): key is keyof UseElementBoundingReturnType { return ['width', 'height', 'top', 'left', 'bottom', 'right'].includes(key)}export interface UseElementBoundingReturnType { width: Ref<number> height: Ref<number> top: Ref<number> left: Ref<number> bottom: Ref<number> right: Ref<number>}export default function useElementBounding( target: BasicTarget, options?: UseElementBoundingOptions,): UseElementBoundingReturnType { const { reset = true, windowResize = true, windowScroll = true, immediate = true } = options ?? {} const size = reactive({ width: 0, height: 0, top: 0, left: 0, bottom: 0, right: 0, }) // 定义更新函数 const update = () => { // 获取 dom const targetDom = getTargetElement(target) if (!targetDom) { // 组件装置后,将所有值初始化为 0 if (reset) { Object.keys(size).forEach(key => { if (keyisUseElementBoundingReturnTypeKey(key)) size[key] = 0 }) } return } if (targetDom) { // 应用 getBoundingClientRect 办法,获取元素信息 const { width, height, top, left, bottom, right } = targetDom.getBoundingClientRect() size.width = width size.height = height size.top = top size.left = left size.bottom = bottom size.right = right } } // 窗口尺寸产生更改时触发更新 if (windowResize) { useEventListener('resize', update, { // 事件监听器不会调用 preventDefault() 办法来阻止默认行为。这样能够进步滚动的性能,并且缩小滚动操作的提早。 passive: true, }) } // 窗口滚动时触发更新 if (windowScroll) { useEventListener('scroll', update, { capture: true, passive: true, }) } // 元素尺寸更改时触发更新 useResizeObserver(target, update) // 代理对象产生更改时触发更新 watch(() => getTargetElement(target), update) onMounted(() => { immediate && update() }) return { ...toRefs(size), }}啰嗦两句其实代码量并不多,核心思想就是利用 vue3.x 的响应式办法进行封装。该代码 源码地址。 ...

September 22, 2023 · 3 min · jiezi

关于vue3:优雅使用-vue3x-lodash-在项目中管理封装指令

vue3.x directivesvue 指令是一种非凡的 vue.js 个性,用于在 DOM 元素上增加特定的行为或性能。指令通过在元素上应用特定的指令名称和参数来实现,能够用于操作 DOM、响应事件、绑定数据等。明天简述一下如何在我的项目中优雅的治理、封装一些罕用的指令。 前面代码基本上会逐行进行正文,以便于大家浏览。 治理指令对立治理对立包治理:通过创立 directives 文件夹,咱们能够将所有与指令相干的文件集中在一个地位,使其更易于查找和保护。这种对立的包治理构造有助于组织和治理指令相干的代码。模块化指令:在 directives/modules 文件夹中,咱们为每个指令创立一个独立的文件夹。这种模块化的构造使每个指令的逻辑和性能被封装在一个独立的文件中,不便独自治理和保护。每个指令文件夹中的进口文件 index.ts 能够用于导出指令逻辑,使其在我的项目中得以对立注册和应用。规范化命名:指令文件夹的命名须要长篇累牍,可能清晰表白指令的用处。通过规范化的命名,能够使我的项目中的指令更易于了解和辨认,进步代码的可读性和可维护性。可扩展性:通过这种治理形式,咱们能够轻松地增加新的指令。只需在 directives/modules 文件夹中创立一个新的指令文件夹,并在其中编写相应的指令逻辑即可。这种构造使我的项目具备良好的可扩展性,不便咱们依据须要增加、批改或删除指令。·├── directives├──├── index.ts├──├── modules├──├──├── some directive├──├──├──├── index.ts type.ts ...对立注册每个指令都应用 index.ts 文件对立裸露一个 CustomDirectiveFC 类型的函数,并且在根目录的 index.ts 中主动收集 modules 文件夹中的所有文件并注册这些指令。 实现公共类型(type.ts)import type { Directive } from 'vue'import type { App } from 'vue'export type { DebounceBindingOptions } from './modules/debounce/type'export type { ThrottleBindingOptions } from './modules/throttle/type'export type CustomDirectiveFC<T, K> = () => Directive<T, K>export interface DirectiveModules extends Object { default: CustomDirectiveFC<unknown, unknown>}export type AppType = App<Element>收集、注册指令利用 import.meta.glob 办法(如果是 webpack 则是应用 require.context),获取所有指令文件夹的门路。而后,遍历这些文件夹,找到蕴含 index.ts 文件的地位。在每个 index.ts 文件中,你能够导入 CustomDirectiveFC 函数。通过这种形式,你能够主动收集所有指令,并进行注册。 ...

September 22, 2023 · 4 min · jiezi

关于vue3:Vue3中的几个坑你都见过吗

Vue3 目前曾经趋于稳定,不少代码库都曾经开始应用它,很多我的项目将来也必然要迁徙至Vue3。本文记录我在应用Vue3时遇到的一些问题,心愿能为其余开发者提供帮忙。 1. 应用reactive封装根底数据类型 传统开发模式中,数据申明很简略。然而在Vue中有多个响应式变量申明形式,整体的应用规定如下: 应用reactive来封装Object,Array,Map,Set数据类型; 应用ref封装String,Number,Boolean类型。 如果应用reactive来封装根底数据类型,会产生正告,同时封装的值不会成为响应式对象。 <script setup>import { reactive } from "vue";const count = reactive(0);</script>然而,能够应用ref来封装Object、Array等数据类型,外部会调用reactive。 2. 解构reactive对象 上面代码中,count封装成了reactive对象,点击按钮时,count会自增。 <template> Counter: {{ state.count }} <button @click="add">Increase</button> </template> <script> import { reactive } from "vue"; export default { setup() { const state = reactive({ count: 0 }); function add() { state.count++; } return { state, add, }; }, }; </script>如果须要应用ES6构造赋值对state进行构造,须要应用如下的代码: <template> <div>Counter: {{ count }}</div> <button @click="add">Increase</button></template><script>import { reactive } from "vue";export default { setup() { const state = reactive({ count: 0 }); function add() { state.count++; } return { ...state, add, }; },};</script>构造复制实现之后,点击按钮,成果如下: ...

September 11, 2023 · 2 min · jiezi

关于vue3:Vue3项目文件目录详解

依照模块化的思维,比拟清晰一些的目录构造如下图 api: 用于模块化治理我的项目中所有模块的申请文件assets: 个别分为images和stylesimages:我的项目中须要用到的图片(img、png等)、icon、SVG等styles:全局的公共款式,reset等components: 对立治理我的项目中须要用到的所有.vue组件个别依据其性能进行分组directives: Vue的自定义指令,不多形容layout: 我的项目的布局.vue模板locales: 搁置国际化多语言配置文件mixins: 混入的一些配置,Vue2中用的比拟多plugins: 本人写的一些我的项目插件router: 路由治理store: Vuex全局变量治理utils: 本人封装的一些全局性的js性能文件views/pages: 业务层

September 1, 2023 · 1 min · jiezi

关于vue3:electronvitevue3vuerouter-踩坑记录

1.vue3中应用qrcodejs2 报错,如下:TypeError:Cannot read properties of undefined(reading‘_android‘)解决办法,应用qrcodejs2-fix替换qrcodejs2npm install qrcodejs2-fix const getQRCode = text => { const qrcode = new QRCode('qrcode', { text, width: 240, height: 240, colorDark: '#000000', //二维码色彩 colorLight: '#ffffff', //二维码背景色 correctLevel: QRCode.CorrectLevel.L //容错率,L/M/H}) }) return qrcode.value}

September 1, 2023 · 1 min · jiezi

关于vue3:会动的数字vue3-插件动态数字驾驶舱大屏的最爱

简介会动的数字。 疾速开始npm i moving-numbers-vue3 -S疾速利用全局注入import movingNumbers from 'moving-numbers-vue3'app.use(movingNumbers);部分注入import { MovingNumbers } from 'moving-numbers-vue3';export default { name: 'App', components: { MovingNumbers }}主参数参数类型必填项默认值参考值阐明mNumNumber 或 String√ 会动的数字。modeString×fastfast:快增;fix:定变;scroll:滚动;计算模式。decimalNumber× 小数位限度,默认不做解决。设定后处理准则:数据小数位位数大于指定数字解决。quantileShowBoolean×false 分位符号是否显示。quantileTypeNumber×4 分位符号类型:人民币:4位宰割;美元:3位宰割。办法参数类型解释示例 1<MovingNumbers class="c1" :mNum="movingNumber" :quantileShow="true"></MovingNumbers>setInterval(() => { this.movingNumber = (Math.random() * 1000000).toFixed(6); // console.log(this.movingNumber);}, 5000);</script>示例 2<MovingNumbers class="c2" :mNum="movingNumber" mode="fix" :decimal="3" :quantileShow="true" :quantileType="3"></MovingNumbers>setInterval(() => { this.movingNumber = (Math.random() * 1000000).toFixed(6); // console.log(this.movingNumber);}, 5000);</script>示例 3<MovingNumbers class="c3" :mNum="movingNumber" mode="scroll" :decimal="4" :quantileShow="true"></MovingNumbers>setInterval(() => { this.movingNumber = (Math.random() * 1000000).toFixed(6); // console.log(this.movingNumber);}, 5000);</script>上地址(npm地址)NPM ...

August 30, 2023 · 1 min · jiezi

关于vue3:Vue3中启用gzip压缩nginx配置gzip

要在Vue CLI3中启用gzip压缩,能够应用compression-webpack-plugin插件。1. 装置插件:在终端中运行以下命令装置compression-webpack-plugin插件:npm install --save-dev compression-webpack-plugin2. 批改配置:在vue.config.js文件中增加以下代码:const CompressionPlugin = require('compression-webpack-plugin');module.exports = { configureWebpack: { plugins: [ new CompressionPlugin({ algorithm: 'gzip', // 应用gzip压缩 test: /\.js$|\.html$|\.mp4$|\.*$|\.css$/, // 匹配文件名 filename: '[path][base].gz[query]', // 压缩后的文件名(放弃原文件名,后缀加.gz) minRatio: 1, // 压缩率小于1才会压缩 threshold: 10240, // 对超过10k的数据压缩 deleteOriginalAssets: false, // 是否删除未压缩的源文件,审慎设置,如果心愿提供非gzip的资源,可不设置或者设置为false(比方删除打包后的gz后还能够加载到原始资源文件) }) ] }}这将在webpack配置中增加compression-webpack-plugin插件,并配置它以压缩.js,.html和.css文件。3. 从新构建:从新构建Vue我的项目,压缩后的文件应该曾经生成了。如果构建胜利,则在dist目录下应该会看到被压缩后的文件,例如app.js.gz,app.html.gz等。 编辑 Nginx 配置文件#开启gzip压缩性能gzip on;gzip_min_length 1024;gzip_buffers 4 16k;gzip_comp_level 2;gzip_types *;gzip_vary on;

August 30, 2023 · 1 min · jiezi

关于vue3:Vue3Element-Plus的项目搭建

Vue3+Element Plus的我的项目搭建什么是Vue3和Element PlusVue3是Vue.js的最新版本,它是一个用于构建用户界面的渐进式框架。Vue3提供了更好的性能、更好的开发体验、更好的组合能力和更多的新个性,例如Proxy响应式零碎、Composition API、Teleport、Suspense等1。 Element Plus是一个基于Vue3的UI组件库,它提供了丰盛的UI组件和款式,能够让咱们轻松地构建好看和敌对的用户界面。Element Plus应用了Vue3的Composition API来实现组件,提供了更好的性能和更好的开发体验。Element Plus还提供了主题定制和国际化反对,让咱们能够依据不同的需要和场景来定制和应用UI组件2。 为什么要应用Vue3+Element Plus应用Vue3+Element Plus能够让咱们享受以下劣势: 高效和灵便:Vue3和Element Plus都应用了组件化的开发方式,让咱们能够更好地复用和组合代码,进步开发效率和灵活性。响应式和交互:Vue3和Element Plus都应用了响应式的数据绑定,让咱们能够更容易地实现数据和视图的同步,进步用户体验和交互性。优雅和好看:Vue3和Element Plus都应用了优雅的语法和好看的款式,让咱们能够更舒服地编写代码和展现界面,进步代码品质和视觉效果。 如何应用Vue3+Element Plus搭建我的项目应用Vue3+Element Plus搭建我的项目须要以下几个步骤: 创立Vue3利用咱们能够应用Vue CLI来创立Vue3利用,它是一个用于疾速开发Vue.js我的项目的命令行工具。咱们能够通过npm install -g @vue/cli命令来装置Vue CLI,并通过vue create my-project命令来创立一个新的Vue3我的项目1。2. 装置Element Plus咱们能够通过npm install element-plus --save命令来装置Element Plus,并在main.js中引入Element Plus2。例如: import { createApp } from 'vue'import ElementPlus from 'element-plus'import 'element-plus/lib/theme-chalk/index.css'import App from './App.vue'const app = createApp(App)app.use(ElementPlus)app.mount('#app')复制 3. 应用Element Plus组件咱们能够在Vue3利用中应用Element Plus提供的UI组件来展现数据和操作数据。咱们能够在template中间接应用组件标签,并在script中定义数据和办法。例如: <template> <el-button type="primary" @click="handleClick">点击我</el-button></template><script>export default { setup() { const handleClick = () => { alert('你点击了按钮') } return { handleClick } }}</script>复制 ...

August 28, 2023 · 1 min · jiezi

关于vue3:Vue3PiniaViteTS-还原高性能外卖APP项目高清

download:Vue3+Pinia+Vite+TS 还原高性能外卖APP我的项目React 是一个用于构建 Web 和原生交互界面的库,它能够让你通过组件来创立用户界面。简书是一个创作社区,它提供了一个平台让用户分享本人的文章、故事、想法等。如果你想用 React 开发简书的我的项目,那么你须要把握一些基础知识和技能,以及理解简书的业务需要和功能设计。本文将为你介绍如何从零根底入门到实战 React 开发简书的过程,心愿能对你有所帮忙。 首先,你须要装置 Node.js 和 npm,这是 React 开发的必备工具。Node.js 是一个 JavaScript 运行环境,它能够让你在服务器端执行 JavaScript 代码。npm 是 Node 的包管理器,它能够让你装置和治理 React 以及其余依赖库。 其次,你须要应用 create-react-app 来创立一个 React 利用的模板。create-react-app 是一个命令行工具,它能够帮忙你疾速搭建一个 React 开发环境,包含配置 Webpack、Babel、ESLint 等工具。你能够在终端中输出以下命令来装置 create-react-app: npm install -g create-react-app复制而后,你能够在终端中输出以下命令来创立一个名为 jianshu 的 React 利用: create-react-app jianshu复制这个命令会在当前目录下生成一个 jianshu 文件夹,外面蕴含了 React 利用的根本构造和文件。你能够在终端中输出以下命令来进入 jianshu 文件夹,并启动开发服务器: cd jianshunpm start复制这个命令会在浏览器中关上一个地址为 http://localhost:3000 的页面,显示出 React 利用的初始界面。你能够在 src 文件夹中批改代码,并实时看到页面的变动。 接下来,你须要理解 React 的基本概念和语法,包含 JSX、组件、props、state、生命周期、事件处理等。JSX 是一种相似于 HTML 的语法,它能够让你在 JavaScript 中编写 UI 元素。组件是 React 的外围概念,它是一种封装了 UI 和逻辑的可复用的代码单元。props 是组件之间传递数据的形式,它是一种只读的属性。state 是组件外部治理数据的形式,它是一种可变的状态。生命周期是组件在不同阶段执行的函数,它能够让你管制组件的渲染和更新。事件处理是组件响应用户操作的形式,它是一种绑定函数到 UI 元素上的办法。 ...

August 19, 2023 · 1 min · jiezi

关于vue3:Vue33-TS4-自主打造媲美-ElementPlus-的组件库

download:Vue3.3 + TS4 ,自主打造媲美 ElementPlus 的组件库ElementPlus 的特点ElementPlus 是由 Element 团队开发的一个全新的组件库,它齐全基于 Vue 3 的新个性和 API 进行开发,充分利用了 Vue 3 的性能劣势和组合式 API。ElementPlus 的组件不仅领有优良的设计格调和交互体验,而且反对多种主题定制和国际化,适应不同的场景和需要。ElementPlus 还提供了一套残缺的 Sketch 设计资源,不便设计师进行原型设计和视觉稿制作。 ElementPlus 的装置ElementPlus 反对通过 npm 或 yarn 装置,也反对通过 CDN 引入。装置 ElementPlus 前,须要先确保我的项目曾经装置了 Vue 3。以下是应用 npm 装置 ElementPlus 的命令: npm install element-plus --save ElementPlus 的应用ElementPlus 反对全局引入和按需引入两种形式。全局引入是指在我的项目的入口文件中一次性导入所有的组件和款式,这样能够不便地应用任何一个组件,但会减少我的项目的打包体积。按需引入是指在每个页面或组件中只导入须要应用的组件和款式,这样能够缩小我的项目的打包体积,但须要手动治理每个组件的依赖。 全局引入如果要应用全局引入的形式,能够在我的项目的入口文件(如 main.js)中增加以下代码: import { createApp } from 'vue'import App from './App.vue'import ElementPlus from 'element-plus'import 'element-plus/lib/theme-chalk/index.css'const app = createApp(App)app.use(ElementPlus)app.mount('#app')这样就能够在任何页面或组件中间接应用 ElementPlus 的组件了,例如: <template> <el-button type="primary">点击</el-button></template>按需引入如果要应用按需引入的形式,须要先装置一个插件 babel-plugin-component,它能够主动转换代码中的 import 语句,实现按需加载组件和款式。以下是装置 babel-plugin-component 的命令: ...

August 18, 2023 · 1 min · jiezi

关于vue3:jeecgbootvue3-查询区-label-文字居左实现

以系统管理中的零碎角色界面为例 操作步骤1. 通过路由或者工具找到以后代码所在的文件src/views/system/role/index.vue2. 找到 useListPage 调用,fromConfig 对象退出 labelWidth 和 rowProps 属性formConfig: { labelWidth: 65, // 设置所有的label宽 rowProps: { gutter: 24 }, // 给row加上间距 schemas: searchFormSchema,}, 3. 因为 label 文字数量并不是都一样,找到非凡的独自设置其 label 宽度。批改之后的界面成果:

August 17, 2023 · 1 min · jiezi

关于vue3:Vue中使用图片懒加载以及注意要点

外围代码 import { useIntersectionObserver } from "@vueuse/core";// 图片懒加载export const lazyPlugin = { install(app) { // 自定义指令: app.directive("img-lazy", { mounted(el, binding) { const { stop } = useIntersectionObserver( el, ([{ isIntersecting }], observerElement) => { if (isIntersecting) { //图片进入视觉入口了 el.src = binding.value; stop(); } } ); }, }); },};应用 <img v-img-lazy="baseUrl + item.url" alt="" :key="item.url" />要点: **肯定要加上:key,不然会呈现在更新数据源的时候,数据更新图片被缓存不更新的状况**

August 16, 2023 · 1 min · jiezi

关于vue3:vue3vite-env文件的配置问题

设置.env中的内容信息 留神vue3+vite 必须应用VITE结尾的配置信息 否则无奈获取如果不想应用VITE结尾本人批改就在vite.config.ts文件中增加envPrefix:“APP_” //vite.config.tsexport default defineConfig({ plugins: [vue()], envPrefix:"APP_",//APP_ 为自定义结尾名})

July 11, 2023 · 1 min · jiezi

关于vue3:推荐非常详细的vite开发笔记7k字

为什么要降级到vue3.0当将以后的技术栈从Vue 2.0降级到Vue 3.0时,有许多值得思考的理由。以下是10个降级到Vue 3.0的理由: 更好的性能: Vue 3.0引入了一种全新的响应式零碎,应用了Proxy代理,相比Vue 2.0中的Object.defineProperty,在性能方面有显著的晋升。这意味着更快的渲染速度和更高的性能。更小的文件大小: Vue 3.0通过应用模块化的设计和Tree-shaking技术,使得打包后的文件更小。这能够缩小初始加载工夫并进步应用程序的整体性能。Composition API: Vue 3.0引入了Composition API,这是一种新的组件组织形式,可能更好地组织和重用逻辑代码。相比于Vue 2.0的Options API,Composition API提供了更灵便、可组合和可保护的代码构造。TypeScript反对: Vue 3.0在设计时思考了更好的TypeScript反对,提供了更好的类型推断和类型查看。这使得在Vue 3.0我的项目中应用TypeScript更加容易和高效。Teleport: Vue 3.0引入了Teleport(传送门)个性,它能够帮忙您在DOM中的任何地位渲染组件。这对于在应用程序中创立弹出窗口、对话框或告诉等动静内容十分有用。Fragments: Vue 3.0引入了片段(Fragments)个性,能够让您在不额定减少DOM节点的状况下渲染多个元素。这进步了组件的可读性和灵活性。新的组件生命周期钩子: Vue 3.0引入了一些新的组件生命周期钩子函数(如setup),用于更好地管制组件的初始化和渲染过程。这使得编写和治理组件更加直观和灵便。更好的TypeScript反对: Vue 3.0在设计上思考到了更好的TypeScript反对,提供了更好的类型推断和类型查看。这使得在Vue 3.0我的项目中应用TypeScript更加容易和高效。更好的开发工具反对: Vue 3.0的公布也随同着更新的Vue Devtools,以反对新的API和性能。这将大大提高开发者在调试和剖析Vue 3.0应用程序时的效率。良好的生态系统反对: 只管Vue 3.0是一个较新的版本,但它曾经开始逐步取得更多的反对和生态系统的迁徙。许多罕用的Vue插件和库也已更新以反对Vue 3.0,这为降级提供了更好的反对和生态环境。这些理由强调了从Vue 2.0降级到Vue 3.0的许多劣势和潜在益处。然而,在理论降级过程中,请务必测试和验证您的应用程序是否与Vue 3.0版本兼容,并依据您的我的项目需要和工夫限度来评估降级的收益和危险。 怎么应用vue3.0呢?vite中文网:https://cn.vitejs.dev/guide/ 应用 NPM:bash $ npm create vite@latest应用 Yarn:bash $ yarn create vite应用 PNPM:bash $ pnpm create vite装置依赖项pnpm install运行pnpm dev 相熟罕用的APIVite 提供了多个罕用的 API 用于创立和配置我的项目。以下是一些常见的 Vite API: createApp(): 这是 Vite 中最罕用的 API 之一,用于创立应用程序实例。它返回一个实例,您能够应用该实例来注册全局组件、挂载应用程序以及执行其余应用程序级别的操作。import { createApp } from 'vue';const app = createApp();use(): use 办法用于注册插件或中间件。您能够应用此办法在应用程序中应用各种插件、路由器、状态治理等性能。app.use(plugin);mount(): mount 办法用于将应用程序挂载到特定的 DOM 元素上。您须要指定一个 DOM 选择器作为参数,以确定挂载的地位。app.mount('#app');component(): component 办法用于注册全局组件。您能够应用此办法将组件注册为全局可用,以便在应用程序中的任何中央应用它。app.component('my-component', MyComponent);directive(): directive 办法用于注册全局指令。您能够应用此办法注册自定义指令,以便在模板中应用它们来操作 DOM 元素。app.directive('my-directive', myDirective);provide() / inject(): provide 和 inject 办法用于在父组件中提供数据,并在子组件中注入数据。这是一种用于跨组件档次传递数据的高级技术。app.provide('myData', data);在子组件中: ...

July 4, 2023 · 7 min · jiezi

关于vue3:9-个值得推荐的-Vue3-UI-框架

本文举荐几个比拟风行的 VUE3 UI 框架,同时提供杰出的开发人员体验,正当利用,又或者学习借鉴都是不错的抉择,排名不分先后。 Ant Design VueAnt Design Vue 是一个十分成熟的框架,应用 Ant Design Vue 创立用户界面非常简单,这些组件能够适应各种图标款式、字体和彩色主题。Ant Design Vue 不断改进其 60 多个组件,根本笼罩我的项目大部份需要,而且使它们变得更好,更易于拜访。 Vue3 上的 Ant Design 包更小,感觉更轻,并且反对 SSR(还包含组合 API),Ant Design 领有成熟的简单组件,如数据表、统计框、pop 确认、模态和弹出窗口。Ant Design Vue 在 GitHub 上领有 15k+ 颗星,每周下载量为 49k,数据曾经阐明了它的受欢迎水平。 JNPFJNPF疾速开发平台是其中一个,后端深度集成java+.net 6 双技术引擎,前端采纳Vue3等技术框架,包含场景建模、界面开发、零碎对接、组件拓展、数据并发解决、动静菜单、权限校验、按钮级别权限管制等性能。 详情能够去往官网自行体验更多:www.jnpfsoft.com/?sifou 弱小的动静信息数据模型能够让应用程序疾速生成!JNPF引领低代码开发模式,帮忙解决企业我的项目70%的反复工作,让开发更多关注业务。既能疾速提高效率,节省成本,同时又不失灵活性。 BalmUIBalmUI 曾经公布了他们的 9.0 版本了,该版本反对 Vue3。Balm 基于谷歌的 Material Design,这就是为什么它看起来很相熟。Balm 附带 Vue 插件和指令,以及从简略到简单的高度可定制的组件。 BalmUI 倒退十分迅速,如果想应用 Material Design 格调,应用简单的内置指令(如 debouncing 和 UI 波纹)在创立自定义组件时能派上用场,那么它非常适合 Vue3 我的项目。 Wave UIWaveUI 在 Vue3 公布后进行了良好的定位,WaveUI 的开发是在 Vue3 仍处于 alpha 阶段时就开始了,其指标是在其 API 稳固后立刻反对它,使其成为首批 Vue3 UI 框架之一。 ...

July 4, 2023 · 2 min · jiezi

关于vue3:vue3-pinia在store使用setup模式的时候调用reset方法

pinia自身提供了一个reset办法,能够重置store const store = useStore()store.$reset()然而store如果采纳setup写法的时候,应用reset办法,因为不反对所以会报错,如下图:解决办法:在mian.ts中为pinia注册reset办法,如下: pinia.use(({ store }) => { const initialState = JSON.parse(JSON.stringify(store.$state)); store.$reset = () => { store.$patch(($state) => { Object.assign($state, JSON.parse(JSON.stringify(initialState))); }); }})然而发现了一个问题,不太明确:store中有如下两个变量: //store.tsconst obj1 = ref({})const obj2 = reactive({})//页面中应用const { obj1, obj2 } = storeToRefs(store)页面中obj1能够被重置,obj2并没有被重置,然而在main.ts中打印其实重置过了的,有晓得造成这种状况的起因吗?

July 4, 2023 · 1 min · jiezi

关于vue3:Vue3-设置全局变量

形式一:main.js 设置全局变量 import api from '@/api'app.config.globalProperties.$api = api应用全局变量,应用 getCurrentInstance 办法。 // ctx.$api 就是全局设置的变量const {proxy: { $api },} = getCurrentInstance();// ctx.$api 就是全局设置的变量const { ctx } = getCurrentInstance();形式二:vue3新的 provide/inject 性能能够穿透多层组件,实现数据从父组件传递到子组件。能够将全局变量放在根组件的 provide 中,这样所有的组件都能应用到这个变量。如果须要变量是响应式的,就须要在 provide 的时候应用 ref 或者 reactive 包装变量。

June 16, 2023 · 1 min · jiezi

关于vue3:SpringBootVue3MySQL集群-开发健康体检双系统

download:SpringBoot+Vue3+MySQL集群 开发衰弱体检双系统Vue3.0+Spring Boot实现体检套餐模块体检套餐是医疗机构提供的一种服务,它蕴含了多项体检我的项目,帮忙人们全面理解本人的身材健康状况。为了更好地治理体检套餐,许多医疗机构抉择应用信息化零碎来治理和保护。本文将介绍如何应用Vue 3.0和Spring Boot实现体检套餐模块。 技术栈在本文中,咱们将应用Vue 3.0和Spring Boot技术栈来实现体检套餐模块。Vue 3.0是一种风行的JavaScript框架,用于开发前端Web应用程序。Spring Boot是一种Java企业级框架,用于开发后端Web应用程序。 前端设计以下是实现体检套餐模块所需的前端页面: 首页 首页展现了所有可用的体检套餐,并容许用户通过搜寻性能查找特定套餐。用户能够点击任何套餐以获取更多详细信息。 详情页 详情页展现了选定的体检套餐的详细信息,包含套餐名称、价格、我的项目列表等。此页面还容许用户向购物车中增加套餐。 购物车 购物车展现了用户以后所有已抉择的体检套餐,并容许用户编辑或删除这些套餐。 后端设计以下是实现体检套餐模块所需的后端服务: 套餐治理API 套餐治理API包含创立、更新和删除套餐。此API还返回可用的套餐列表和详细信息。 购物车API 购物车API容许用户将选定的套餐增加到购物车中,并返回购物车中的套餐列表。 实现步骤以下是应用Vue 3.0和Spring Boot实现体检套餐模块的步骤: 创立Spring Boot我的项目 设计数据库,创立相应的表格 创立Spring Boot控制器,解决API申请 通过Vue CLI创立一个新的Vue 3.0我的项目 设计并实现前端页面,调用后端API获取数据 部署应用程序 论断应用Vue 3.0和Spring Boot技术栈能够轻松实现体检套餐模块。前端页面展现了套餐列表、详情以及购物车等性能,后端提供了解决API申请的控制器。通过以上步骤,您能够创立一个残缺的体检套餐管理系统。

June 14, 2023 · 1 min · jiezi

关于vue3:vue3x-使用-globalProperties-全局变量

Vue3.x 用 Composition API 中是没有this的,所以不能间接应用 this 调用 globalProperties 全局变量Composition API 应用办法// main.jsimport { createApp } from 'vue'import App from './App.vue'import storage from './plugins/storage'const app = createApp(App);app.config.globalProperties.$storage = storageapp.provide('$storage', storage)app.mount('#app')// Home.vueimport {inject} from "vue"const storage = inject('$storage')storage.setItme('name','zhangsan')Vue2.x 的应用办法// main.jsimport { createApp } from 'vue'import App from './App.vue'import storage from './plugins/storage'const app = createApp(App);app.config.globalProperties.$storage = storageapp.mount('#app')// Home.vuethis.$storage.setItme('name','zhangsan')

June 13, 2023 · 1 min · jiezi

关于vue3:vue3全局变量的使用

一、main.ts中定义 二、在页面中应用<template> <div> 全局变量 <div>办法1(应用 getCurrentInstance 的 appContext):{{way1}}</div> <div>办法2(从 getCurrentInstance 构造出 proxy):{{way2}}</div> </div></template><script lang="ts">import { defineComponent, getCurrentInstance, onMounted,reactive,toRefs} from 'vue';export default defineComponent({ name:'board', setup() { const { proxy } = getCurrentInstance() as any; const data = reactive({ way1: getCurrentInstance()?.appContext.config.globalProperties.$message, way2: proxy.$message, }) onMounted(()=>{ // 打印 console.log(data.way1,'办法1') console.log(data.way2,'办法2') }) return { ...toRefs(data), } },})</script><style scoped lang="less"></style>打印后果:页面展现:

June 13, 2023 · 1 min · jiezi

关于vue3:基于vue3的bootstrap-ui组件库出炉啦

介绍bts-vue是一个基于vue3.x和Bootstrap UI 4.x的Vue组件库!它在Bootstrap UI的根底上进行加强改良,使得bts-vue 比原始bootstrap ui更好看,体验敌对。bts-vue继承了Bootstrap的CSS响应式个性,因而它实用于各种跨端的我的项目。截止目前,它曾经蕴含了45个简略、易用、灵便的高质量组件。 文档地址:https://941477276.github.io/bts-vue/doc-site/dist/GitHub:https://github.com/941477276/bts-vue起源bts-vue组件库本来只是自己学习vue3时的一个产物,在学习的过程中逐步造成了一个体量不小的组件库,因而将其开源进去。 bts-vue组件库既能够商用,也非常适合初、中级开发者去学习vue3,学习组件库开发。 这套组件库中没有太过浅近、难以了解的代码,组件嵌套层级根本不会超过4层,因而非常适合初、中级开发者去学习它,去看它的源码,去改它的bug。 招募小伙伴一个人的精力、能力是无限的,一个好的组件库须要一个团队去保护去跟进,因而当初面向社区招募酷爱开源的小伙伴一起建设bts-vue UI! 不论你是富有经验的中高级开发,还是刚接触前端开发的萌新,都没有关系,只有你有一颗酷爱开源的心,放弃对技术的激情,都欢送你退出进来! 通过参加bts-vue UI我的项目,你能够: 学习最新的 Vite+Vue3+TS 技术学习如何设计和开发组件学习如何打包可按需加载的组件学习vite、rollup插件开发学习vite按需加载插件开发晋升组件封装能力结识一群酷爱学习、酷爱开源的敌人感兴趣的小伙伴能够增加我的微信,拉你进 bts-vue 外围开发群:

June 12, 2023 · 1 min · jiezi

关于vue3:在vue3tsvite项目中用BMap百度地图自定义定位icon不显示

自定义icon门路,不能间接应用门路地址,须要require包裹 var myIcon = new window.BMap.Icon(require("@/assets/icon.png", new window.BMap.Size(26, 32));那么问题来了,vite+typescript我的项目不容许应用动态资源加载办法require,如果应用require关键字就会报错,那必定没法显示坐标点。所以咱们应用import来解决let imgUrl = ref('')onMounted(async () => { let img = await import("/@/assets/41-placeholder.svg") imgUrl.value = img.default}应用var map = new window.BMap.Map("container"); // 创立地图实例map.centerAndZoom(point, 15);map.enableScrollWheelZoom(true); // 鼠标滚动缩放// 自定义坐标门路地址var myIcon = new window.BMap.Icon(imgUrl.value, new window.BMap.Size(26, 32));myIcon.setImageSize(new window.BMap.Size(26, 32))var marker = new window.BMap.Marker(new window.BMap.Point(116.399, 39.910), {icon: myIcon});map.addOverlay(marker);

June 8, 2023 · 1 min · jiezi

关于vue3:vuenextadmin项目使用cdn加速详细配置

首先vue-next-admin是自身是配置好cdn减速的,只是没有开启。 根目录找到.env文件,开启打包cdn减速找到utils、build.ts文件默认是正文了一些代码的,这里须要留神的就是几个变量。 prodUrl: https://unpkg.com/{name}@{version}/{path}name: 依赖包的名称var: 包裸露的全局变量名称path: cdn unpkg链接地址咱们的modules外面的变量会替换掉name,version,path。path要在unpkg网站查找对应的地址,我下载vue-next-admin我的项目的时候有五个地址配置的有问题(打包当前运行就晓得那些地址不对),我做了批改,而后打包就没问题了。最有一项,填写了残缺门路的不做替换。 import importToCDN, { autoComplete } from 'vite-plugin-cdn-import';/** * 打包相干 * 留神 prodUrl:应用的是 jsdelivr 还是 unpkg。它们的 path 可能不统一 * 文章链接:https://blog.csdn.net/qq_34450741/article/details/129766676,应用的是 jsdelivr * @description importToCDN https://github.com/mmf-fe/vite-plugin-cdn-import * @description cdn 在线引入的 cdn 地址配置。path:https://www.jsdelivr.com/ || https://unpkg.com/ * @description external 打包时,过滤包导入。参考:https://rollupjs.org/configuration-options/#external */// 这里应用unpkg// https://unpkg.com/{name}@{version}/{path}// name: 依赖包的名称// var:包裸露的全局变量名称// path cdn unpkg链接地址export const buildConfig = { cdn() { return importToCDN({ prodUrl: 'https://unpkg.com/{name}@{version}/{path}', modules: [ autoComplete('vue'), autoComplete('axios'), { name: 'vue', var: 'Vue', path: 'dist/vue.global.js', }, { name: 'vue-demi', var: 'VueDemi', path: 'lib/index.iife.js', }, { name: 'vue-router', var: 'VueRouter', path: 'dist/vue-router.global.js', }, { name: 'element-plus', var: 'ElementPlus', path: 'dist/index.full.js', }, { name: '@element-plus/icons-vue', var: 'ElementPlusIconsVue', path: 'dist/index.iife.min.js', }, { name: 'echarts', var: 'echarts', path: 'dist/echarts.min.js', }, { name: 'echarts-gl', var: 'echarts-gl', path: 'dist/echarts-gl.min.js', }, { name: 'echarts-wordcloud', var: 'echarts-wordcloud', path: 'dist/echarts-wordcloud.min.js', }, { name: 'vue-i18n', var: 'VueI18n', path: 'dist/vue-i18n.global.js', }, { name: 'jsplumb', var: 'jsPlumb', path: 'dist/js/jsplumb.min.js', }, { name: 'cropperjs', var: 'Cropper', path: 'dist/cropper.min.js', }, { name: 'sortablejs', var: 'Sortable', path: 'Sortable.min.js', }, { name: 'qrcodejs2-fixes', var: 'QRCode', path: 'qrcode.js', }, { name: 'print-js', var: 'printJS', path: 'dist/print.js', }, { name: '@wangeditor/editor', var: 'wangEditor', path: 'dist/index.js', }, { name: '@wangeditor/editor-for-vue', var: 'WangEditorForVue', path: 'dist/index.js', }, { name: 'vue-grid-layout', var: 'VueGridLayout', path: 'https://cdn.jsdelivr.net/npm/vue-grid-layout@3.0.0-beta1/dist/vue-grid-layout.umd.min.js', }, ], }); }, external: [ 'vue', 'axios', 'vue-router', 'element-plus', '@element-plus/icons-vue', 'echarts', 'echarts-gl', 'echarts-wordcloud', 'vue-i18n', 'jsplumb', 'cropperjs', 'sortablejs', 'qrcodejs2-fixes', 'print-js', '@wangeditor/editor', '@wangeditor/editor-for-vue', 'vue-grid-layout', ],};运行 npm run build打包 打包厚的index.html文件<!DOCTYPE html><html lang="zh-CN"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="keywords" content="vue-next-admin,vue-prev-admin,vue-admin-wonderful,后盾管理系统一站式平台模板,心愿能够帮你实现疾速开发。vue2.x,vue2.0,vue2,vue3,vue3.x,vue3.0,CompositionAPI,typescript,element plus,element,plus,admin,wonderful,wonderful-next,vue-next-admin,vite,vite-admin,疾速,高效,后盾模板,后盾零碎,管理系统" /> <meta name="description" content="vue-next-admin,基于 vue3 + CompositionAPI + typescript + vite + element plus,适配手机、平板、pc 的后盾开源收费管理系统模板!vue-prev-admin,基于 vue2 + element ui,适配手机、平板、pc 的后盾开源收费管理系统模板!" /> <link rel="icon" href="./favicon.ico" /> <title>vue-next-admin</title><script src="https://unpkg.com/vue@3.2.47/dist/vue.global.prod.js"></script><script src="https://unpkg.com/axios@1.3.5/dist/axios.min.js"></script><script src="https://unpkg.com/vue@3.2.47/dist/vue.global.js"></script><script src="https://unpkg.com/vue-demi@0.13.11/lib/index.iife.js"></script><script src="https://unpkg.com/vue-router@4.1.6/dist/vue-router.global.js"></script><script src="https://unpkg.com/element-plus@2.3.3/dist/index.full.js"></script><script src="https://unpkg.com/@element-plus/icons-vue@2.1.0/dist/index.iife.min.js"></script><script src="https://unpkg.com/echarts@5.4.2/dist/echarts.min.js"></script><script src="https://unpkg.com/echarts-gl@2.0.9/dist/echarts-gl.min.js"></script><script src="https://unpkg.com/echarts-wordcloud@2.1.0/dist/echarts-wordcloud.min.js"></script><script src="https://unpkg.com/vue-i18n@9.2.2/dist/vue-i18n.global.js"></script><script src="https://unpkg.com/jsplumb@2.15.6/dist/js/jsplumb.min.js"></script><script src="https://unpkg.com/cropperjs@1.5.13/dist/cropper.min.js"></script><script src="https://unpkg.com/sortablejs@1.15.0/Sortable.min.js"></script><script src="https://unpkg.com/qrcodejs2-fixes@0.0.2/qrcode.js"></script><script src="https://unpkg.com/print-js@1.6.0/dist/print.js"></script><script src="https://unpkg.com/@wangeditor/editor@5.1.23/dist/index.js"></script><script src="https://unpkg.com/@wangeditor/editor-for-vue@5.1.12/dist/index.js"></script><script src="https://cdn.jsdelivr.net/npm/vue-grid-layout@3.0.0-beta1/dist/vue-grid-layout.umd.min.js"></script> <script type="module" crossorigin src="./assets/js/index-3b8bf49e.js"></script> <link rel="modulepreload" crossorigin href="./assets/js/pinia-ce2dce77.js"> <link rel="modulepreload" crossorigin href="./assets/js/js-cookie-cf83ad76.js"> <link rel="modulepreload" crossorigin href="./assets/js/has-symbols-e8f3ca0e.js"> <link rel="modulepreload" crossorigin href="./assets/js/function-bind-22e7ee79.js"> <link rel="modulepreload" crossorigin href="./assets/js/has-26d28e02.js"> <link rel="modulepreload" crossorigin href="./assets/js/get-intrinsic-b9397c9a.js"> <link rel="modulepreload" crossorigin href="./assets/js/call-bind-1df9733d.js"> <link rel="modulepreload" crossorigin href="./assets/js/nprogress-5ada7e0c.js"> <link rel="modulepreload" crossorigin href="./assets/js/object-inspect-d11bccf2.js"> <link rel="modulepreload" crossorigin href="./assets/js/side-channel-9112baf6.js"> <link rel="modulepreload" crossorigin href="./assets/js/qs-a8db372b.js"> <link rel="modulepreload" crossorigin href="./assets/js/element-plus-ef4dc42a.js"> <link rel="modulepreload" crossorigin href="./assets/js/mitt-f7ef348c.js"> <link rel="stylesheet" href="./assets/css/nprogress-8b89e2e0.css"> <link rel="stylesheet" href="./assets/css/index-c2520709.css"> </head> <body> <div id="app"></div> <script type="text/javascript"> var _hmt = _hmt || []; (function () { var hm = document.createElement('script'); hm.src = 'https://hm.baidu.com/hm.js?d9c8b87d10717013641458b300c552e4'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(hm, s); })(); </script> <script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=wsijQt8sLXrCW71YesmispvYHitfG9gv&s=1"></script> </body></html>

June 8, 2023 · 2 min · jiezi

关于vue3:vue3setup语法糖

1.setup语法糖简介间接在script标签中增加setup属性就能够间接应用setup语法糖了。应用setup语法糖后,不必写setup函数;组件只须要引入不须要注册;属性和办法也不须要再返回,能够间接在template模板中应用。 <template> <my-component @click="func" :numb="numb"></my-component></template><script lang="ts" setup> import {ref} from 'vue'; import myComponent from '@/component/myComponent.vue'; //此时注册的变量或办法能够间接在template中应用而不须要导出 const numb = ref(0); let func = ()=>{ numb.value++; }</script>2.setup语法糖中新增的apidefineProps:子组件接管父组件中传来的propsdefineEmits:子组件调用父组件中的办法defineExpose:子组件裸露属性,能够在父组件中拿到 2.1defineProps父组件代码 <template> <my-component @click="func" :numb="numb"></my-component></template><script lang="ts" setup> import {ref} from 'vue'; import myComponent from '@/components/myComponent.vue'; const numb = ref(0); let func = ()=>{ numb.value++; }</script>子组件代码 <template> <div>{{numb}}</div></template><script lang="ts" setup> import {defineProps} from 'vue'; defineProps({ numb:{ type:Number, default:NaN } })</script>2.2defineEmits子组件代码 <template> <div>{{numb}}</div> <button @click="onClickButton">数值加1</button></template><script lang="ts" setup> import {defineProps,defineEmits} from 'vue'; defineProps({ numb:{ type:Number, default:NaN } }) const emit = defineEmits(['addNumb']); const onClickButton = ()=>{ //emit(父组件中的自定义办法,参数一,参数二,...) emit("addNumb"); }</script>父组件代码 ...

May 29, 2023 · 1 min · jiezi

关于vue3:全新升级基于Vue3新标准打造后台综合解决方案丰年留客足鸡豚

download:全新降级,基于Vue3新规范,打造后盾综合解决方案基于Vue3新规范的开发教训分享Vue3是一款现代化的JavaScript框架,它在2020年正式公布。Vue3采纳了全新的架构设计,晋升了性能和开发体验。本篇文章将具体介绍基于Vue3新规范的开发教训,包含组件化、响应式数据、生命周期函数等方面。 组件化开发Vue3在组件化开发方面有了更多的改良。首先,Vue3中的组件能够应用函数式API编写,这意味着能够更加轻松地重用组件代码。其次,Vue3引入了Composition API,该API能够让开发者更加灵便地组合组件行为,从而使得组件的开发变得更加简略和高效。 响应式数据Vue3对响应式数据的实现做出了重大改良。Vue3中应用Proxy对象代替了Object.defineProperty()办法,能够更好地监听数据变动并且反对嵌套属性的监听。同时,Vue3还提供了一些新的API,比方ref、reactive等,用来更不便地治理状态和响应式数据。 生命周期函数Vue3的生命周期函数也有所改变。Vue3中的beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed等钩子函数都被保留,然而减少了setup函数。setup函数是Composition API的一部分,它能够在组件创立之前执行,并且能够返回一个对象,该对象中蕴含了组件所须要的响应式数据和办法。 总结基于Vue3新规范的开发教训分享到此结束。总的来说,Vue3采纳了全新的架构设计,进步了性能和开发体验。组件化、响应式数据、生命周期函数等方面都有了重大改良,使得开发者更加不便地编写高质量的代码。咱们置信随着越来越多的开发者逐步应用Vue3,这款框架将会成为Web开发中的佼佼者。

May 28, 2023 · 1 min · jiezi

关于vue3:超清Vue3-React18-TS4-入门到实战

Vue3、React18和TS4是以后前端畛域中最风行的技术栈之一,它们都提供了弱小的工具和性能来帮忙开发人员构建高效、牢靠、易保护的Web应用程序。本文将介绍Vue3、React18和TS4的特点和劣势,并阐明如何将它们组合在一起构建现代化的Web应用程序。download:https://www.97yrbl.com/t-1531.html 一、Vue3Vue3是一个轻量级、高性能的JavaScript框架,能够疾速构建交互式Web界面和单页面应用程序。Vue3采纳了响应式数据绑定和虚构DOM技术,使得数据更新和视图渲染更加高效和灵便。Vue3还提供了许多新性能,例如Teleport、Composition API和TypeScript反对,能够进一步简化开发流程和加强代码品质。Vue3实用于中小型应用程序和疾速原型开发。 二、React18React18是一个风行的JavaScript库,用于构建大规模、高可扩展性的Web应用程序。React18采纳了虚构DOM技术和组件化思维,能够将UI界面合成为多个组件,实现代码复用和可维护性。React18还提供了Hooks、Server-side Rendering和TypeScript反对等性能,能够进一步加强开发效率和代码品质。React18实用于大型应用程序和简单的UI场景。 三、TypeScript4TypeScript4是一个动态类型查看器和编译器,可与JavaScript一起应用,并提供了更弱小的类型检查和编译时谬误查看性能。TypeScript4能够缩小开发人员在编写和调试代码时的谬误,并加强代码的可读性和可维护性。TypeScript4还能够与Vue3和React18等框架无缝集成,进一步提高代码品质和开发效率。 四、将Vue3、React18和TypeScript4组合应用将Vue3、React18和TypeScript4组合应用能够充分利用它们的特点和劣势,进一步提高Web应用程序的开发效率和代码品质。以下是将Vue3、React18和TypeScript4组合应用的一些最佳实际:应用Vue3和React18来构建不同模块的前端界面,例如Vue3能够用于构建用户登录和注册界面,而React18能够用于构建数据可视化和大型表格等简单的UI组件。应用TypeScript4来增强代码品质和可维护性,例如在编写Vue3或React18组件时,应用TypeScript4来增加动态类型检查和编译时谬误查看性能,能够防止许多常见的编程谬误。应用现代化的开发工具和框架来进步开发效率,例如应用VS Code编辑器、Webpack打包工具和ESLint代码查看工具等,能够大大简化开发流程并缩小谬误。将Vue3、React18和TypeScript4与其余罕用库和框架集成,例如Axios网络申请库、Redux状态治理库和Antd UI组件库等,能够进一步提高开发效率和代码品质。总之,Vue3、React18和TypeScript4是以后前端畛域中最风行的技术栈之一,它们都提供了弱小的工具和性能来帮忙开发人员构建高效、牢靠、易保护的Web应用程序。通过深刻理解Vue3、React18和TypeScript4的特点和劣势,并将它们组合在一起构建现代化的Web应用程序,咱们能够为用户提供更好的体验和更高质量的产品。

May 23, 2023 · 1 min · jiezi

关于vue3:Vite4MobileGPT基于vue3vant4移动端仿ChatGPT聊天模板

随着最近openAi推出了Iphone版ChatGPT利用APP。标记着chatgpt曾经步入了挪动畛域。 空闲之余使用vite4.x构建了一个mobile版chatgpt聊天实例。 vue3-mobileGPT 反对红色/暗黑两种主题模式。 技术栈编辑器:Cursor框架技术:vite4+vue3+vue-router+pinia2组件库:Vant^4.3.1 + ve-plus^0.3.2代码格式化:highlight.js^11.7.0markdown组件:vue3-markdown-it数据存储:pinia-plugin-persistedstate^3.1.0款式解决:sass^1.62.1 我的项目构造基于vite4构建我的项目,采纳vue3 setup编码开发。 vue3组件库vant 一款轻量级、可定制化的挪动端UI组件库。目前 Vant 官网提供了 Vue 2 版本、Vue 3 版本和微信小程序版本。vant4反对vue3版本。 # Vue 3 我的项目,装置最新版 Vantnpm i vant# Vue 2 我的项目,装置 Vant 2npm i vant@latest-v2https://vant-contrib.gitee.io/vant/#/zh-CN/ 入口配置main.jsmain.js引入总款式、路由/状态治理、公共组件配置。 import { createApp } from 'vue'import './style.scss'import App from './App.vue'import Router from './router'import Store from './store'import Plugins from './plugins'const app = createApp(App)app.use(Router)app.use(Store)app.use(Plugins)app.mount('#app')引入公共插件新建一个plugins/index.js文件,用来引入一些公共配置文件。 ...

May 23, 2023 · 3 min · jiezi

关于vue3:onMounted-is-called-when-there-is-no-active-component-已解决

最近写vue3+ts和组合式API遇到了下面的问题,代码如下: <template> </template><script setup lang="ts">import { useStore } from 'vuex'import { useRoute } from 'vue-router'import { onMounted } from 'vue'const store = useStore()store.dispatch('initMenus')const route = useRoute()onMounted(() =>{ console.log(route.path)})</script><style lang="scss" scoped></style>这个是因为在这个组合式onMounted之前调用了store.dispatch('initMenus') 外部蕴含async/await 解决办法: If you are using async setup(), make sure to register lifecycle hooks before the first await statement. 只有把代码程序调整如下,报错即可隐没: <template> </template><script setup lang="ts">import { useStore } from 'vuex'import { useRoute } from 'vue-router'import { onMounted } from 'vue'const route = useRoute()onMounted(() =>{ console.log(route.path)})const store = useStore()store.dispatch('initMenus')</script><style lang="scss" scoped></style>心愿能够帮到你。 ...

May 19, 2023 · 1 min · jiezi

关于vue3:VUE3添加静态配置文件实现编译后修改后端URL

需要以前用Angular的时候,因为应用了拦截器+Nginx代理,所以不存在批改后端地址的问题。但当初的我的项目没有那么标准,后端地址是写死在我的项目里,而且间接跨域这就诞生了一个需要:能不能在VUE编译之后,在不批改源码的状况下,还能批改后端地址呢?本文来探讨这个问题。 步骤其实很简略。 第一个原理:Vite编译时不会批改public文件夹的内容,而是一成不变的把内容放到index.html所在目录。 第二个原理:JS(TS)能够读取JSON中的数据,而JSON不会参加编译。 基于以上两个原理。 在src目录下,新建public文件夹,创立config.json文件 编辑config.json增加须要的变量以对象字段的模式,任意增加: 在须要申请的中央减少援用IDE可能不会自动识别,能够手动援用: // 依据理论状况替换变量名称import {baseURL} from '/public/config.json'间接应用变量名即可const uploadImgUrl = baseURL + "system/upload/uploadFile"; const uploadExcelUrl = baseURL + "system/enterprise/importData"; 总结过于简略,没有总结

May 18, 2023 · 1 min · jiezi

关于vue3:vue3tssetup支持全局变量提示

vue3 ts setup写法,反对全局变量提醒。vue3 ts版本通过app.config.globalProperties挂载全局变量,一些插件也会在此装置全局可用的变量。参考官文:https://cn.vuejs.org/api/application.html#app-config-globalpr...,然而挂载的变量没有类型定义,被当作了any类型,无奈通过ctrl查看变量下的属性和办法。 上面是在main.ts里挂载全局变量,鼠标放到变量上发现是any类型: 在component里应用挂载的变量,无奈辨认挂载的变量类型: 全局挂载的变量无奈辨认类型,因而无奈提供代码提醒, 也不利于代码重构,谬误查看等。须要给全局变量建设类型关联,上面是vue的解决形式:vue通过利用ts的模块扩大个性,给挂载的变量指定类型,参考官文:https://cn.vuejs.org/guide/typescript/options-api.html#augmen...globalProperties是ComponentCustomProperties类型,原生是没有咱们挂载下来的变量的,因而用上面的形式扩大这个类型定义:在src下写一个d.ts的类型定义文件,依照官网的文档扩大类型定义,至此$bus $api被扩大到了ComponentCustomProperties类型里,proxy就是ComponentCustomProperties类型,有了关联关系,代码提醒就有了。 一些vue专用的插件或者库,个别会在本人的d.ts里定义vue的扩大类型,如pinia.d.ts定义了反对vue2及vue3的扩大类型: 上面解决下setup模式下proxy提醒问题:setup模式下须要通过proxy拜访全局变量,在ts里援用proxy须要解决代码提醒问题,这样写在js中没有问题:在ts里会正告proxy不存在,这是ts的联结类型导致的,proxy是ComponentInternalInstance下的属性,但getCurrentInstance返回的可能是null。这个正告能够疏忽,也能够强转为any类型,但这样就无奈利用ts的提醒能力了。要利用ts的提醒能力须要强转为类型ComponentInternalInstance: const { proxy } = getCurrentInstance() as ComponentInternalInstance ;import的正告打消了,不过代码里应用的中央还有正告:proxy可能存在也可能不存在,因而须要用可选链操作符改下代码:至此用上了ts的类型提醒,打消了所有正告。不过每个proxy后须要跟个可选链操作符,这让人感觉不爽,上面的办法能够解决这种问题: 引入proxy时抉择上面两种写法之一即可,都是比拟举荐的写法: import { onMounted, onUnmounted, ref, reactive, getCurrentInstance, ComponentInternalInstance, ComponentPublicInstance } from 'vue';// 写法一:应用可选链操作符 + 强转类型const proxy = getCurrentInstance()?.proxy as ComponentPublicInstance;或者:// 写法二:2次强转类型const proxy = (getCurrentInstance() as ComponentInternalInstance).proxy as ComponentPublicInstance;至此齐全反对了ts,有了代码提醒,类型查看。ts的类型查看,联结类型的确比拟麻烦,须要消耗不少精力解决类型问题。

May 18, 2023 · 1 min · jiezi

关于vue3:解决-TypeErrorparentComponentctxdeactivate-is-not-a-function-报错

报错详情: runtime-core.esm-bundler.js:6055 Uncaught (in promise) TypeError: parentComponent.ctx.deactivate is not a function at unmount (runtime-core.esm-bundler.js:6055:33) at patch (runtime-core.esm-bundler.js:5027:13) at sharedContext.activate (runtime-core.esm-bundler.js:2420:13) at processComponent (runtime-core.esm-bundler.js:5465:37) at patch (runtime-core.esm-bundler.js:5058:21) at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:5680:17) at ReactiveEffect.run (reactivity.esm-bundler.js:185:25) at instance.update (runtime-core.esm-bundler.js:5714:56) at updateComponent (runtime-core.esm-bundler.js:5539:26) at processComponent (runtime-core.esm-bundler.js:5472:13)router-view官网示例: <router-view v-slot="{ Component, route }"> <!-- 留神 v-if="route.meta.isKeepAlive"放在keep-alive标签上不会失效 --> <keep-alive> <component :is="Component" v-if="route.meta.isKeepAlive"></component> </keep-alive> <component :is="Component" v-if="!route.meta.isKeepAlive"></component> </router-view>咱们只有为component动静组件增加一个惟一属性key即可: <router-view v-slot="{ Component, route }"> <!-- 留神 v-if="route.meta.isKeepAlive"放在keep-alive标签上不会失效 --> <keep-alive> <component :is="Component" :key="route.name" v-if="route.meta.isKeepAlive"></component> </keep-alive> <component :is="Component" :key="route.name" v-if="!route.meta.isKeepAlive"></component> </router-view>

May 12, 2023 · 1 min · jiezi

关于vue3:vue3使用vitepluginssr实现ssr

最近想用vue做个简略的网站,体验下建站的全流程,写篇文章记录下vue开发过程。 之前的vue开发默认都是用了单页面利用,这次做的时候想到了SEO,决定尝试下SSG模式部署。 为什么用SSR/SSG集体网站想要有天然流量,必定要依赖百度、bing等搜索引擎网站的展现,权重越高越容易被展现,这就是要做好SEO。VUE默认状况下都是生成的单页面利用,即SPA。然而SPA 对 SEO 优化不敌对。 比方网站有10个页面,SPA是生成独立的利用,齐全加载后在浏览器渲染,因而搜索引擎无奈获取到残缺的页面内容。 应用SSR的形式就是把利用生成残缺的10个独立页面,只是须要在服务端运行node程序实时生成html,比拟消耗资源。 另一种形式是在build的时候间接生成10个html,应用nginx部署在服务器上,就能够获取页面残缺内容,更利于SEO,这就是SSG。 应用vite-plugin-ssr实现SSR我的网站是基于vue3开发,调研之后,决定应用vite-plugin-ssr来实现SSG,上面介绍下具体实现。 vite-plugin-ssr官网:https://vite-plugin-ssr.com/ 1.我的项目构造这里倡议间接应用vite-plugin-ssr提供的vue示例程序,其中曾经把必要的配置都写好了,能够间接进行二开,十分不便,上面的性能介绍也次要基于这个示例开展。 示例的Git地址:https://github.com/brillout/vite-plugin-ssr/tree/main/examples/vue-full 2.目录及次要文件介绍开发时,间接在pages/目录下建本人的页面就能够,url门路就是文件门路├── components│   └── Counter.vue├── package-lock.json├── package.json├── pages //在这里创立网站的页面│   ├── index.page.vue //这里默认是“/”门路展现的页面│   └── star-wars│   ├── filterMovieData.ts│   ├── index│   │   ├── index.page.server.ts│   │   └── index.page.vue │   ├── movie│   │   ├── index.page.route.ts│   │   ├── index.page.vue│   │   └── onBeforeRender.ts│   └── types.ts├── readme.md├── renderer│   ├── Link.vue│   ├── PageShell.vue //app.ts中设置的主入口,其余vue页面通过slot加载过去│   ├── _default.page.client.ts //只在浏览器端执行的代码│   ├── _default.page.server.ts //在服务端渲染的时候应用的代码│   ├── _error.page.vue│   ├── app.ts //相似于传统vue我的项目中的main.js,主入口│   ├── getPageTitle.ts│   ├── logo.svg│   ├── types.ts│   └── usePageContext.ts├── tsconfig.json├── types.d.ts└── vite.config.ts //vite的配置文件,外面曾经设置好了ssr形式渲染3.build生成示例代码中能够间接执行npm run build进行渲染,执行实现之后,生成的页面会在根目录的dist文件中,这里截取一部分构造如下, ...

May 10, 2023 · 2 min · jiezi

关于vue3:Vue3ChatGPT基于vite4xvue3pinia2模仿chatgpt聊天AI实例

前言随着chatgpt智能聊天继续火爆,越来越多的开发者参加其中。明天给大家分享vite4.x搭建繁难网页版仿ChatGpt聊天程序Vue3ChatGPT。 技术框架编辑工具:Cursor框架技术:Vue3+Vite4.x+Pinia2组件库:VEPlus (基于vue3桌面端组件库)国际化多语言:vue-i18n^9.2.2代码高亮:highlight.js^11.7.0本地存储:pinia-plugin-persistedstate^3.1.0markdown解析:vue3-markdown-it vue3-chatgpt 反对两种布局模板、dark+light模式、全屏+半屏展现、Markdown语法解析、侧边栏收起等性能。 我的项目构造 基于vite4.x构建我的项目,采纳vue3 setup语法糖编码。 main.js入口文件import { createApp } from 'vue'import App from './App.vue'// 引入Router和Storeimport Router from './router'import Store from './store'// 引入插件配置import Plugins from './plugins'const app = createApp(App)app.use(Router).use(Store).use(Plugins).mount('#app')vite.config.js配置文件import { defineConfig, loadEnv } from 'vite'import vue from '@vitejs/plugin-vue'import { resolve } from 'path'import { parseEnv } from './src/utils/env'// https://vitejs.dev/config/export default defineConfig(({ mode }) => { const viteEnv = loadEnv(mode, process.cwd()) const env = parseEnv(viteEnv) return { plugins: [vue()], // base: '/', // mode: 'development', // development|production /*构建选项*/ build: { // minify: 'esbuild', // 打包形式 esbuild(打包快)|terser // chunkSizeWarningLimit: 2000, // 打包大小正告 // rollupOptions: { // output: { // chunkFileNames: 'assets/js/[name]-[hash].js', // entryFileNames: 'assets/js/[name]-[hash].js', // assetFileNames: 'assets/[ext]/[name]-[hash].[ext]', // } // } }, esbuild: { // 打包去除 console.log 和 debugger drop: env.VITE_DROP_CONSOLE ? ['console', 'debugger'] : [] }, /*开发服务器选项*/ server: { // 端口 port: env.VITE_PORT, // 是否浏览器主动关上 open: env.VITE_OPEN, // 开启https https: env.VITE_HTTPS, // 代理配置 proxy: { // ... } }, resolve: { // 设置别名 alias: { '@': resolve(__dirname, 'src'), '@assets': resolve(__dirname, 'src/assets'), '@components': resolve(__dirname, 'src/components'), '@views': resolve(__dirname, 'src/views'), // 解决vue-i18n正告提醒:You are running the esm-bundler build of vue-i18n. 'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js' } } }})公共布局模板整体分为顶部导航栏、左侧菜单栏、右侧主体栏。 ...

May 7, 2023 · 3 min · jiezi

关于vue3:vue3-父组件给子组件传递泛型不用JSX

最近在封装一个组件,应用的时候心愿父组件能给子组件传递一个泛型,在网上搜了半天,答案都是说要用jsx能力实现。具体写法如下: 应用JSX这段代码来自Eluxjs的示例我的项目elux-vue-antd-admin,感兴趣的能够看下。父组件: (为缩小篇幅,代码删了很多,当伪代码看吧) const Component = defineComponent<Props>({ props: ['listPathname', 'mergeColumns'] as any, setup(props) { return () => { return ( <MTable<ListItem> // 这里应用子组件MTable,传递泛型ListItem size={tableSize} commonActions={commonActions} selection={selection} loading={listLoading === 'Start' || listLoading === 'Depth'} /> ); }; },});export default Component;子组件:(子组件比拟麻烦) interface Props<T = Record<string, any>> extends TableProps<T> { class?: string; columns: MColumns<T>[]; selectedRows?: Partial<T>[]; selection?: MSelection<T>;}const Component = defineComponent<Props>({ name: styles.root, props: [ 'class', 'columns' ] as any, setup(props: Props) { return () => { const {class: className = '', dataSource, onChange, rowKey = 'id', loading, size, bordered, locale, scroll} = props; return ( <div class={styles.root + ' ' + className}> {headArea.value} <Table columns={columnList.value} rowSelection={rowSelection.value} onChange={onChange} size={size} /> </div> ); }; },}) as any;export default Component as <T>(props: Props<T>) => JSX.Element;这里应用 Component as <T>(props: Props<T>) => JSX.Element; 来做到接管泛型,但生产它的父组件必须用 jsx。因为我的项目不不便用jsx,我找了很久如何用template来传递泛型,终于找到了! ...

May 5, 2023 · 2 min · jiezi

关于vue3:VUE3ElementPlus简单实现大图预览解决elimage没有事件接口的问题

需要本文想要实现的款式是,通过任意事件,比方点击图片或点击按钮,触发一个全屏的图片预览。 看一看element官网中的例子: 点击这个图片就会呈现全屏的大图预览 这个大图能够自在缩放,多张图片能够切换,而且大图的url和小图的url并没有关系。 但element这个<el-image>组件存在一个问题:它的大图必须通过点击小图触发,而文档上并没有点击事件的接口。 这就意味着,无奈实现“点击其余自定义的按钮来显示大图”,只能“点击<el-image/>小图”来调用它外部的事件。 其余的解决办法——<el-image-viewer/>其余文章中给出了一个方法: element中的大图实质是另一个组件<el-image-viewer/>,“点击小图显示大图”的过程就是<el-image>点击之后显示了<el-image-viewer/>。尽管<el-image-viewer/>没有在文档中被给出,但能够间接应用,只须要额定的管制它的显隐即可。 具体用法能够看链接。 本文的办法——用代码触发“点击”事件本文的办法比较简单粗犷,共两步: 把小图的宽高设为0在须要时用代码模仿一下小图的点击事件这样标准吗?显然是不标准,但下班的代码又不是开源我的项目,能跑即可,要什么自行车。 先来看文档中给出的示例代码: <template> <div class="demo-image__preview"> <el-image style="width: 100px; height: 100px" :src="url" :zoom-rate="1.2" :preview-src-list="srcList" :initial-index="4" fit="cover" /> </div></template><script lang="ts" setup>const url = 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'const srcList = [ 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg', 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg', 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg', 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg', 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg', 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg', 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg',]</script><style scoped>.demo-image__error .image-slot { font-size: 30px;}.demo-image__error .image-slot .el-icon { font-size: 30px;}.demo-image__error .el-image { width: 100%; height: 200px;}</style>在依赖环境正确的状况下,复制到适合地位就能够失常应用。 接下来对它进行批改。 1.获取援用要想模仿点击,前提就是获取dom元素的援用。VUE中有三种获取的形式,本文以最简略的document形式举例。给元素加个id: <el-image id="show-image" style="width: 100px; height: 100px" :src="url" 其余参数略 />此时,如果在ts中执行document.getElementById('show-image').click()就能够显示大图了。 这一步测试胜利之后就能够把document.getElementById('show-image').click()绑定到其余事件上,比方某个按钮的点击,这样就实现了“点击按钮显示大图” 2.设置宽高为0因为<el-image-viewer/>和<el-image/>齐全就是两个组件,所以小图不会影响大图,间接置0即可: <el-image id="show-image" style="width: 100px; height: 100px" :src="url" 其余参数略 />此时页面上就不会再显示它了,而触发事件依然能失常显示大图。 ...

May 4, 2023 · 1 min · jiezi

关于vue3:vue3-vite4-中-配置px转rem

下载依赖:amfe-flexible: 挪动端适配文档: https://www.npmjs.com/package/amfe-flexible下载: npm install amfe-flexiblepostcss-pxtorem: px转rem文档: https://www.npmjs.com/package/postcss-pxtorem下载: npm install postcss-pxtorem 2.引入配置:main.ts:/ px转rem /import "amfe-flexible";vite.config.ts: /* 引入px转rem */const postCssPxToRem = require("postcss-pxtorem");在css局部增加: css: { // 此代码为适配挪动端px2rem postcss: { plugins: [ postCssPxToRem({ rootValue: 37.5, // 1rem的大小(管制1rem的大小 点位:px) propList: ["*"], // 须要转换的属性,这里抉择全副都进行转换 }), ], },},3.设置,在App.vue中初始化: onMounted(() => { /* px转rem */ const baseSize = 38; /* 设置 rem 函数 */ function setRem() { /* 以后页面宽度缩放比例,可依据本人须要批改 */ const scale = document.documentElement.clientWidth / 1920; /* 设置页面根节点字体大小 */ document.documentElement.style.fontSize = baseSize * Math.min(scale, 2) + "px"; } /* 初始化 rem */ setRem(); window.onresize = () => { /* 扭转窗口大小时从新设置 rem */ setRem(); });});

April 28, 2023 · 1 min · jiezi

关于vue3:向着Vue3进发Vue27升级指南

北京工夫7月1号,Vue2.7正式公布,Vue2.7反对你的我的项目在不降级Vue3的状况下应用Vue3的个性,例如Composition Api、setup、Css v-bind等。 与此同时,Vue2.7也是Vue2.X的最终主要版本,在这个版本之后,Vue2将进入LTS(长期反对),即从当初开始继续18个月,Vue2将不再接管新性能。 对于一些老我的项目来说,当降级Vue3老本过大而你又垂涎Vue3新的api和代码组织形式时,那Vue2.7无疑是最佳抉择,这能够让还在应用Vue2的同学更好的学习并过渡到Vue3。 接下来笔者将以一个Vue2的我的项目,将其降级到Vue2.7并记录该过程,欢送感兴趣的小伙伴浏览。 降级前版本:vue: 2.6.14,vue-cli: 4.0.0一、删除node_modules和package-lock.json为了确保咱们前面降级的依赖版本是正确的,在一开始时咱们间接先将我的项目的node_modules和package-lock.josn删除,避免出现各种缓存问题。 二、降级过程1. vue-cli脚手架降级当初咱们先依照要求降级脚手架的版本,Vue2.7对于要求vue-cli版本要求如下: 如果你的vue-cli是v4版本的,那么你须要将其降级到~4.5.18如果你的vue-cli是v5版本的,那么你须要将其降级到~5.0.6 // package.json{ "devDependencies": { // "@vue/cli-plugin-babel": "^4.0.0", // "@vue/cli-plugin-eslint": "^4.0.0", // "@vue/cli-service": "^4.0.0", // 批改为 "@vue/cli-plugin-babel": "^4.5.18", "@vue/cli-plugin-eslint": "^4.5.18", "@vue/cli-service": "^4.5.18", }}2. vue版本升级// package.json{ "dependencies": { // "vue": "2.6.14", "vue": "2.7.0", // vue2.7 不再须要vue-template-compoler,所以能够将其删除 // "vue-template-compiler": "2.6.14", }}3. @vue/composition-api有些人可能曾经在Vue2的我的项目应用上了@vue/composition-api,这时你须要将我的项目中所用到的导入更新为vue: // import { ref } from '@vue/composition-api'import { ref } from 'vue'但@vue/composition-api里的一些API,如createApp,并未齐全在Vue2.7里移植,所以如果你用到了这些API,那还是应用持续应用@vue/composition-api,若你用到的API都是Vue2.7里有的,则能够将@vue/composition-api从依赖中删去了。 三、应用通过下面的改变后,当初能够重新安装依赖并运行起来了,接着就能够品味Vue3的新写法了。 <template> <div> <el-button @click="decrease">-</el-button> <el-button>{{ count }}</el-button> <el-button @click="increase">+</el-button> </div></template><script setup>import { ref } from 'vue'let count = ref(1)const decrease = () => { count.value--}const increase = () => { count.value++}</script>另外,Vue2.7反对在模板表达式中应用ESNext语法,这意味着能够在template里应用可选链了,以往在Vue2中,template里并不反对可选链写法,当初在Vue2.7里的template中则能够欢快的应用可选链了 ...

April 23, 2023 · 1 min · jiezi

关于vue3:vue3-模板编译-30-行代码实现-sync-修饰符

v-bind 的 .sync 修饰符在 vue3 已移除 但为了更深刻的理解 vue3 模板编译 和 AST,所以我尝试用 AST 实现 .sync 修饰符 vite.config.ts import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import { transformSync } from './transformSync'export default defineConfig({ plugins: [ vue({ template: { compilerOptions: { nodeTransforms: [transformSync] } } }) ]}) transformSync.ts import { createSimpleExpression, DirectiveNode, SimpleExpressionNode, TemplateChildNode } from '@vue/compiler-core'import { remove } from '@vue/shared'const ELEMENT = 1const DIRECTIVE = 7// 创立事件表达式// e.g. @arg="exp"const createEventExpression = (arg?: SimpleExpressionNode, exp?: SimpleExpressionNode) => ({ type: DIRECTIVE, name: 'on', arg, exp, loc: undefined, modifiers: [] } as unknown as DirectiveNode)/** * 将 `.sync` 修饰符转换为 `@update:xxx` * * e.g. * * `<AAA :xxx.sync="value" />` * * ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ * * `<AAA :xxx="value" @update:xxx="value = $event" />` */export function transformSync(node: TemplateChildNode) { if (node.type === ELEMENT) { const { props } = node for (let i = 0; i < props.length; i++) { const dir = props[i] // 判断属性是否有 sync 修饰符 if (dir.type == DIRECTIVE && dir.modifiers.includes('sync')) { remove(dir.modifiers, 'sync') const { arg, exp } = dir // @update:xxxx const name = createSimpleExpression('update:' + arg?.loc.source, true) // value = $event const val = createSimpleExpression(exp?.loc.source + ' = $event') // 为元素增加 @update:xxx="value = $event" props.push(createEventExpression(name, val)) } } }} 以上就是残缺代码了 ...

April 20, 2023 · 2 min · jiezi

关于vue3:译Ref-vs-Reactive使用Vue3组合式API该如何选择

原文地址:Ref vs. Reactive: What to Choose Using Vue 3 Composition API? 官网文档相干章节:响应式根底 、深刻响应式零碎 本文参考官网文档联合集体了解做了局部批改,不足之处恳请批评指教! 我喜爱 Vue3 的组合式 API,然而它提供了两种响应式 state 办法:ref 和 reactive 。应用 refs 时到处须要 .value 显得很轻便,然而应用 reactive 又会很容易在解构时失落响应式。 在这篇文章中,我将解释该如何抉择应用 reactive, ref 或者两者搭配应用。 太长不看版:默认应用 ref ,在须要分组应用时抉择 reactive 。Vue3 中的响应式在解释 ref 和 reactive 之前,须要先简略理解一下 Vue3 中的响应式根底。 提醒 如果你曾经理解了 Vue3 中的响应式原理,能够跳过这一章节 原生 JavaScript 并没有提供任何响应式机制,来看上面这个例子: let price = 10.0const quantity = 2const total = price * quantityconsole.log(total) // 20price = 20.0console.log(total) // ⚠️ 后果仍旧是 20在响应式零碎中,咱们冀望 total 在 price 或 quantity 扭转时更新。然而 JavaScript 通常不会这样做。 ...

April 14, 2023 · 5 min · jiezi

关于vue3:sheetJs导出excel

这里以vue+element为例:我的项目遇到这样一个需要,将下列表格导出为excel: 1.装置xlxs依赖 npm i xlsx次要的导出excel的办法有aoa_to_sheet和json_to_sheet两种,这里我次要介绍下后者,次要导出流程如下: const XLSX = require("xlsx")var wb = XLSX.utils.book_new()//arr就是咱们所导出的数据let fdXslxws = XLSX.utils.json_to_sheet(arr)XLSX.utils.book_append_sheet(wb, fdXslxws, 'sheet1')XLSX.writeFile(wb, "测试.xlsx")2.json_to_sheet的应用,简略来说就是json数据导出excel数据依据官网所说,最初所须要的数据就是这个格局,即为上文所说的arr [{"日期": "2016-05-02","姓名": "王小虎","地址": "北京"},{"日期": "2016-05-02","姓名": "张三","地址": "北京"},{"日期": "2016-05-02","姓名": "李四","地址": "上海"}]故,只须要将咱们data中的table数据转换为此类格局即可。残缺代码如下: <script>const XLSX = require("xlsx")export default { data() { return { tableData: [{ date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄' }, { date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄' }, { date: '2016-05-01', name: '王小虎', address: '上海市普陀区金沙江路 1519 弄' }], tableHeader: [ { title: '日期', map: 'date' }, { title: '姓名', map: 'name' }, { title: '地址', map: 'address' }, ] } }, methods: { exportExcel() { var wb = XLSX.utils.book_new() let arr = [] let newHeaderObj = {} this.tableHeader.map(item => { newHeaderObj[item.map] = item.title }) this.tableData.map((el, idx) => { let obj = {} for (let x in newHeaderObj) { obj[newHeaderObj[x]] = el[x] } arr.push(obj) }) let fdXslxws = XLSX.utils.json_to_sheet(arr) XLSX.utils.book_append_sheet(wb, fdXslxws, 'sheet1') XLSX.writeFile(wb, "测试.xlsx") } }}</script>也有按需合并单元格等诸多弱小性能,感兴趣的能够去官网看下!以下附上xlsx依赖地址和中文文档 ...

April 14, 2023 · 1 min · jiezi

关于vue3:实现-effect-返回-runner

effect测试 //effect.spec.ts it('runner', () => { // runner 就是 effect(fn) 返回一个函数,执行该函数就相当于从新执行了一次传入 effect 的 fn // 同时执行 runner 也会将 fn 的返回值返回 let foo = 1 const runner = effect(() => { foo++ return 'foo' }) expect(foo).toBe(2) // 调用 runner const r = runner() expect(foo).toBe(3) // 获取 fn 返回的值 expect(r).toBe('foo') })//effect.tslet activeEffect class ReactiveEffect{ private _fn constructor(fn){ this._fn = fn } run(){ activeEffect = this let res =this._fn() //返回执行后的fn return res }}export function effect(fn){ const _effect = new ReactiveEffect(fn) _effect.run() //通过bind扭转this指向 return _effect.run.bind(_effect) }

April 12, 2023 · 1 min · jiezi

关于vue3:实现-effect-reactive-依赖收集触发依赖

实现 effect & reactive 依赖收集&触发依赖创立effect.spec.ts单测 import { reactive } from "../reactive"import { effect } from "../effect"describe('effect', () => { it('happy path', () => { const user = reactive({ age: 10, }) let nextAge effect(() => { nextAge = user.age + 1 }) expect(nextAge).toBe(11) // update user.age++ expect(nextAge).toBe(12) }) })//effect.tsclass ReactiveEffect{ private _fn constructor(fn){ this._fn = fn } run(){ activeEffect = this this._fn() }}export function effect(fn){ const _effect = new ReactiveEffect(fn) _effect.run()}let activeEffectconst targetMap = new WeakMap()//收集依赖export function track(target, key){ let depsMap = targetMap.get(target) if(!depsMap){ depsMap = new Map() targetMap.set(target,depsMap) } let dep = depsMap.get(key) if(!dep){ dep = new Set() depsMap.set(key,dep) }//判断是否曾经收集过依赖,没有就间接增加 dep.add(activeEffect)}//触发依赖export function trigger(target, key){ let depsMap = targetMap.get(target) let deps = depsMap.get(key) console.log(deps) for(const effect of deps){ effect.run() }}//reactive.tsimport { track,trigger } from "./effect"export function reactive(raw){ return new Proxy(raw,{ get(target,key){ const res = Reflect.get(target,key) //设置依赖 track(target, key) return res }, set(target,key,value){ const res = Reflect.set(target,key,value) //触发依赖 trigger(target, key) return res } })}执行yarn test effect失去 ...

April 11, 2023 · 1 min · jiezi

关于vue3:Element-Plus按需引入图标

自从应用了vue3就须要降级element ui到plus了。而相应的图标库也须要独自引入,这篇文章来记录一下 全局全副引入 和 按需引入 的办法。引入全副图标// main.ts// if you're using CDN, please remove this line.import * as ElementPlusIconsVue from '@element-plus/icons-vue'const app = createApp(App)for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component)}按需引入图标<template> <ul class="vat-theme-setting"> <li v-for="item in theme_items"> <a href="#"> <el-icon class="icon"><component :is="item.icon" /></el-icon> <p>{{ item.label }}</p> </a> </li> </ul></template><script setup lang="ts">// 按需引入图标import { Menu, BrushFilled, ShoppingCart, CopyDocument, Delete} from '@element-plus/icons-vue'const theme_items = [ {label: '主题配置', icon: BrushFilled}, {label: '随机换肤', icon: Menu}, {label: '购买源码', icon: ShoppingCart}, {label: '拷贝源码', icon: CopyDocument}, {label: '清理缓存', icon: Delete},]</script><style lang="scss" scoped> </style>成果如下: ...

April 6, 2023 · 1 min · jiezi

关于vue3:附源码vue3vite4arcodegign-vue-tsx版本踩坑记录

文章结尾附源码 vue3、typescript、pinia、Arco Design齐全应用tsx,根本涵盖了vue3罕用写法,欢送补充 特点TypeScript - 代码齐全应用 TypeScript 书写。PiniaArco Design - 字节翻版ant-design,vue组件库。@vueuse/core - 实用函数集mitt - mitt封装eventBus hooks 用法npm run npm:$ npm run prepare$ npm i$ npm run devyarn:$ yarn prepare$ yarn$ yarn dev代码提交:$ npm run lit-staged$ yarn lint-staged格调修复实现后:$ git commit -m "fix(): bug修复"具体参照commitlint.config已装置三方组件库@vueuse/core(实用函数集)@arco-design/web-vue (字节)gsap(javascript动画库)mitt(实现vue勾销的eventbus(公布与订阅性能))vite-plugin-imagemin 图片压缩 "resolutions": { "bin-wrapper": "npm:bin-wrapper-china"}unplugin-vue-components (按需导入组件)vite-plugin-style-import (按需导入款式)vite-plugin-compression (开启GZIP压缩)vite-plugin-cdn-import (cdn引入)@vitejs/plugin-legacy (传统浏览器反对)--->对vue3来说无意义,Proxy决定了vue3不反对ie11,但对react或其余可通过此实现反对mockjs、vite-plugin-mock踩坑记录enmu type ts作用域与js作用域抵触 'no-shadow': 'off', '@typescript-eslint/no-shadow': 'error',tsx中的transtion、KeepAlive、动静组件创立(SFC写法无需思考) import { Transition, KeepAlive, createVNode } from 'vue'; <Transition name="fade" mode="out-in"> <div key={route.path} style={{ height: '100%' }}> {route.meta.ignoreCache ? ( createVNode(Component) ) : ( <KeepAlive include={cacheList.value}> {createVNode(Component)} </KeepAlive> )} </div> </Transition>v-slots两种写法(SFC写法无需思考) ...

April 3, 2023 · 1 min · jiezi

关于vue3:vue3中useRouter执行后返回值是undefined问题

useRouter肯定要放在setup办法内的顶层,否则作用域扭转useRouter()执行返回的是undefined。 正确应用 <script setup>import { useRouter } from 'vue-router';const router = useRouter();const toLogin = () => { router.push({ name: 'login' });};</script>谬误应用 <script setup>import { useRouter } from 'vue-router';const toLogin = () => { const router = useRouter(); //router为 undefine router.push({ name: 'login' });};</script>

April 1, 2023 · 1 min · jiezi

关于vue3:从vue2到vue3的学习之路手稿

vue2和vue3的不同点vue2基于defineProperty 的 getter,setter 来实现的vue3基于es6的proxy(),解决了对象新增属性,数组值变动视图不更新等问题。 选项式api不同点全局 API 利用实例vue2没有app的概念,有些办法间接放在了全局中,比方Vue.component。vue3引入了app的概念 import{createApp}from'vue'const app =createApp({})app.component("xx")弃用EventBus$on,$off 和 $once 实例办法已被移除,组件实例不再实现事件触发接口。所以,eventbus不能用了。改成tiny-emitter。用法如下: import emitter from '@ali/act-util/emitter';emitter.emit('xx',()=>{});emitter.on('xx',()=>{});emitter.off('xx')nextTick不再能在全局this.$nextTick中取到(undefined is not a function) import { nextTick } from 'vue'nextTick(() => { // 一些和 DOM 无关的货色})Data 选项不再反对间接用object类型定义属性。只能通过function返回object的形式。此外,当来自组件的 data() 及其 mixin 或 extends 基类被合并时,合并操作当初将被浅层次地执行。不要再用mixin了,改成用组合式api开发。v-if 与 v-for 的优先级比照vue2.x里v-for会优先作用,vue3.x里v-if会优先作用。slotslot不能放在div上,必须放在template上。 //vue2<div slot="content"> </div>//vue3<template v-slot:content> </template>Transition的css名称v-enter改成v-enter-fromv-leave改成v-leave-from移除过滤器filters从 vue 3.x 开始,过滤器已移除,且不再反对。this.$set()从 vue 3.x 开始,因为有proxy了,所以不能再用this.$set()给对象加kv了。$on,$off和 $once新增emits确保所有组件都应用 emits 选项记录其事件。 <script> data() { return { myNum: 999 } }, emits: ['submit'], template: `<div @click="$emit('submit', 89)"> 小明 </div>`</script>组合式api响应式 API:外围improt {ref,computed} from 'vue';ref() 对于data里定义的值js里用须要家xx.value。template间接用xx即可。computed(()=>{})计算属性reactive()包一层响应式对象,扭转对象值和ref值都双向扭转readonly()承受一个对象 (不论是响应式还是一般的) 或是一个 ref,返回一个原值的只读代理watchEffect()做异步操作的 ...

March 17, 2023 · 1 min · jiezi

关于vue3:vue3-如何让-axios-请求的数据显示在页面上

我让 chatgpt 给了我一段 『vue3 axios demo代码』 <template> <div> <h1>Vue3 Axios Demo</h1> <button @click="fetchData">Fetch Data</button> <ul> <li v-for="item in data" :key="item.id">{{ item.title }}</li> </ul> </div></template><script>import axios from 'axios';import { reactive } from 'vue';export default { setup() { const state = reactive({ data: [], }); const fetchData = async () => { const response = await axios.get('https://jsonplaceholder.typicode.com/posts'); state.data = response.data; }; return { fetchData, data: state.data, }; },};</script> 而且 chatgpt 说,响应数据会显示在页面上 ...

March 14, 2023 · 1 min · jiezi

关于vue3:记一次较完整的vue3koa2简单项目开发经验总结

 最近上头让我写个我的项目简略的官方网站,需要很简略,有前后端,前端负责获取要跳转的外链进行跳转和介绍视频的播放,后端负责传回外链和须要播放的视频。我拿到需要,想了想,这样子的需要就用不着数据库了,后端写个配置文件,传回固定的数据就能够了,视频嘛,就通过流的形式传给前端。 确定好了实现形式,那就撸起袖子开干。通过简略思考,应用vue3+koa2的形式来做。所有从简,装置vue3-cli和koa2来新建前后端我的项目。 一.vue3前端我的项目搭建 通过npm install -g @vue/cli或者yarn global add @vue/cli装置好vue/cli,再通过vue create 我的项目名(本人用英文代替掉我的项目名)新建对应的我的项目。接下来,npm install 装置一遍全副依赖,通过 npm 给本人的我的项目加个配套的element-plus,即通过npm install element-plus --save装置好element-plus。再在main.js文件里援用。 import ElementPlus from 'element-plus'import 'element-plus/dist/index.css'createApp(App).use(ElementPlus).mount('#app')二.koa2后端我的项目搭建 具体的需要页面就不形容,次要就是两个get申请去申请后端。那么后端怎么做呢?一样的,先通过 npm install koa-generator -g 装置 koa2,再通过 koa2 我的项目名 创立好我的项目,最初 npm install 装置一遍全副依赖。而后 npm start 跑一遍,能跑起来就是弄好了。 三.前后端联调须要做的本地代理配置1.前端方面:若有文件vue.config.js,则在外面写上 proxy 代理规定,若没有文件,则新建一个在我的项目顶层再写上代理规定。规定大抵如下: module.exports = { publicPath: './', outputDir: './dist', productionSourceMap: false, lintOnSave: false, devServer: { port: 8808,//前端跑起来的端口 disableHostCheck: true, hotOnly: false, compress: true, watchOptions: { ignored: /node_modules/, }, proxy: {//代理规定,代理到本地3000端口,应用“/api”重写门路到“/” "/api": { target: "http://127.0.0.1:3000/", changeOrigin: true, // target是域名的话,须要这个参数 secure: false, // 设置反对https协定的代理 ws: false, pathRewrite: { "^/api": "/" }, }, } }, chainWebpack: config => { config.plugins.delete('preload') config.plugins.delete('prefetch') }, css: { sourceMap: false, }, };2.后端方面:在我的项目的app.js文件内补充对应的代理规定,大抵规定如下: ...

March 14, 2023 · 4 min · jiezi

关于vue3:vue3-自定义渲染器-canvas-写一个贪吃蛇

前言因为 canvas 画图太麻烦,所有用 PixiJS 代替 DEMO源码实现原理main.tsimport { createRenderer } from 'vue'import { isOn } from '@vue/shared'import { useResizeObserver } from '@vueuse/core'import * as PIXI from 'pixi.js'import patchEvents from './patchEvent'import App from './App.vue'import { set } from './utils'// 创立画布const app = new PIXI.Application({ backgroundColor: '#242424' })app.stage.sortableChildren = trueconst canvas = app.view as HTMLCanvasElementcanvas.id = 'canvas'document.body.appendChild(canvas)// 设置 canvas 为满尺寸useResizeObserver(canvas, ([entry]) => { app.renderer.resize(entry.contentRect.width, entry.contentRect.height)})// 自定义渲染器const renderer = createRenderer<PIXI.DisplayObject | null, PIXI.Container>({ createElement(type, isSVG, isCustomizedBuiltIn, props) { return new PIXI[type]() as PIXI.Container }, insert(el, parent, anchor) { if (!el || !parent) return const i = parent.children.indexOf(anchor) if (i > -1) parent.addChildAt(el, i) else parent.addChild(el) }, remove(el) { el?.removeFromParent() }, patchProp(el, key, preVal, nextVal) { if (!el) return if (typeof el[key] === 'function') { el[key](...nextVal) } else if (isOn(key)) { patchEvents(el, key, nextVal) } else { set(el, key, nextVal, ':') } }, createText(text) { return new PIXI.Text(text) }, createComment(text) { const comment = new PIXI.Text(`<!-- ${text} -->`) comment.visible = false return comment }, setText(node: PIXI.Text, text) { node.text = text }, setElementText() {}, parentNode(node) { return node?.parent }, nextSibling(node) { return node?.parent.children[node.parent.getChildIndex(node) + 1] }})renderer.createApp(App).mount(app.stage)App.vue<template> <!-- 顶部 --> <Graphics :zIndex="1"> <Graphics :beginFill="[0x2d333b]" :drawRect="[0, 0, width, 55]" endFill :alpha="0.75" /> <Text text=" SNAKE" :x="12" :style:lineHeight="55" style:fill="white" /> <Sprite :texture="Texture.from('https://huodoushigemi.github.io/docx2vue/assets/github-540f5a2f.svg')" :x="256" :y="5" :width="45" :height="45" cursor="pointer" @click="toGithub" /> </Graphics> <!-- 网格 --> <template v-for="i in maxX"> <Graphics :x="i * size" :lineStyle="[1]" :moveTo="[0, 0]" :lineTo="[0, maxY * size]" /> </template> <template v-for="i in maxY"> <Graphics :y="i * size" :lineStyle="[1]" :moveTo="[0, 0]" :lineTo="[maxX * size, 0]" /> </template> <!-- 食物 --> <Text text="" :x="food[0] * size" :y="food[1] * size" :style:fontSize="size / 1.4" :style:lineHeight="size" /> <!-- 蛇身 --> <template v-for="p in snake"> <Graphics :x="p[0] * size" :y="p[1] * size" :beginFill="[0]" :drawRect="[0, 0, size, size]" endFill /> </template> <Text text="按空格 暂停/持续" :x="maxX * size * 0.45" :y="maxY * size * 0.8" :style:fill="0xcccccc80" /> <Text v-if="!isActive" text="暂停中……" :x="maxX * size * 0.45" :y="maxY * size * 0.85" :style:fill="0xcccccc80" /></template><script setup lang="ts">import { computed, ref } from 'vue'import { useIntervalFn, useWindowSize } from '@vueuse/core'import { Texture } from 'pixi.js'type Point = [x: number, y: number]// 网格数量const num = 10const { width, height } = useWindowSize()const size = computed(() => Math.min(width.value, height.value) / num)// 边界const maxX = computed(() => (width.value / size.value) >> 0)const maxY = computed(() => (height.value / size.value) >> 0)// 蛇身const snake = ref<Point[]>([ [2, num >> 1], [1, num >> 1], [0, num >> 1]])// 食物const food = ref<Point>(genFood())// 方向let direction = 'ArrowRight'let nextDirection = directionwindow.addEventListener('keydown', e => { // 按空格 暂停/持续 if (e.key == ' ') return isActive.value ? pause() : resume() // ↑ ↓ ← → if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) return if (direction == 'ArrowUp' && e.key == 'ArrowDown') return if (direction == 'ArrowDown' && e.key == 'ArrowUp') return if (direction == 'ArrowLeft' && e.key == 'ArrowRight') return if (direction == 'ArrowRight' && e.key == 'ArrowLeft') return nextDirection = e.key})// loopconst { resume, pause, isActive } = useIntervalFn(() => { direction = nextDirection const head = snake.value[0] let next!: Point if (direction == 'ArrowUp') next = [head[0], head[1] - 1] if (direction == 'ArrowDown') next = [head[0], head[1] + 1] if (direction == 'ArrowLeft') next = [head[0] - 1, head[1]] if (direction == 'ArrowRight') next = [head[0] + 1, head[1]] // 撞墙 if (!isRange(next)) return pause(), alert('撞墙身亡,游戏完结') // 自尽 if (snake.value.slice(0, -1).some(e => isSamePoint(e, next))) return pause(), alert('咬到本人,游戏完结') snake.value.unshift(next) // 吃到食物 if (isSamePoint(next, food.value)) { food.value = genFood() } else { snake.value.pop() }}, 250)function toGithub() { const a = document.createElement('a') a.href = 'https://github.com/huodoushigemi/vue-canvas-snake.git' a.target = '_blank' a.click()}// p1 == p2function isSamePoint(p1: Point, p2: Point) { return p1[0] == p2[0] && p1[1] == p2[1]}// 是否越界function isRange(p: Point) { return p[0] >= 0 && p[0] < maxX.value && p[1] >= 0 && p[1] < maxY.value}// 生成随机数function random(max: number, min = 0) { return (min + Math.random() * (max - min)) >> 0}// 生成食物function genFood() { let point!: Point do point = [random(maxX.value), random(maxY.value)] while (snake.value.some(e => isSamePoint(e, point))) return point}</script>

March 6, 2023 · 4 min · jiezi

关于vue3:Nuxt3实战系列之安装Nuxt3报错问题解决

报错景象Nuxt3最新版本3.2.2也公布了一段时间了,抱着钻研学习的态度,笔者想用Nuxt3开发一个RBAC权限管理系统,后果依照官网的命令装置我的项目脚手架时候间接报错,提醒 Failed to download template from register:fetch failed 刚开始认为是须要用vpn搭梯子,后果配置代理后,仍然报错,也不晓得到底咋回事。总不至于对于Nuxt3的学习就要止步于此了吧?想想本人前几天还装置过一次,都胜利装置了的。不晓得有没有其余小伙伴有遇到这个问题且找到解决方案了。 解决方案还好笔者之前拉取过一次,本着助人为乐的态度,笔者将Nuxt3的脚手架我的项目也提交到了github开源仓库,如果有须要的小伙伴,能够自取,我会定期更新,放弃和官网的代码统一。我的项目地址如下: Nuxt 3 Minimal Starter (github.com) 代码拉取到本地,装置完依赖(笔者应用的pnpm),能够胜利运行,能够看到是最新的3.2.2: 结语博客原创地址:Nuxt3实战系列之装置Nuxt3 欢送批评指正,或者与我交换探讨前端技术~ 分割我:whitney1289(微信),iwhitney@163.com(邮箱)

February 28, 2023 · 1 min · jiezi

关于vue3:vite-vue3-项目通过-importmetaenv-获取自定义的变量

最近应用 vite + vue3 开发新我的项目,遇到非 vite.config.js 文件,通过 import.meta.env 获取不到 .env.[mode] 文件自定义变量的问题,心愿此文章能够帮忙更多遇到此问题的小伙伴!怎么解决此问题?不卖关子了,间接上解决方案,既然间接通过 import.meta.env 拿不到,咱们能够尝试通过 process.env 的形式来获取。 具体做法如下: 新建一个 loadEnv.js 的文件; import * as dotenv from 'dotenv'// 通过 dotenv 配置须要加载指定 .env 文件,这样 process.env 打印到得就是对应得文件了// 这里的 mode 是咱们启动时候的参数,npm run build:test 失去的 mode 就是 testexport function loadEnv(mode) { const ret = {} // 在应用之前咱们先指定加载哪个环境变量 dotenv.config({ path: `.env.${mode}` }) Object.keys(process.env).forEach(envName => { const realName = process.env[envName].replace(/\\n/g, '\n') ret[envName] = realName // 向 process.env 上扩大咱们定义的 VITE 环境变量 process.env[envName] = realName }) return ret}装置 dotenv 帮忙咱们加载指定的环境变量; ...

February 23, 2023 · 1 min · jiezi

关于vue3:vue3直白教程梳理

1、setup script 用法:<script setup lang="ts">// 在这里写vue的逻辑</script><template> <div>哈哈</div></template>2、ref & reactive & 事件 阐明:1、ref:须要响应式的常量,赋值时须要xxx.value2、reactive:须要响应式的对象或者数组,可间接应用或赋值3、事件:在setup script中,间接定义事件 用法:<script setup lang="ts">import { ref, reactive } from 'vue'// 常量const name = ref('小明')// 对象、数组const user = reactive({ name: '小红', gender: '女'})const handleAdd = () => { arr.push({ name: '哈哈哈' })}</script><template> <button @click="switchName"> 我叫 {{name}},性别{{user.gender}} </button> <button @click="handleAdd">新增</button></template>3、computed & watch & watchEffect 阐明:1、computed:计算函数2、watch:监听函数,可监听常量和援用变量,可传immediate和deep。可监听对象也可只监听对象的某个属性3、watchEffect:跟watch差不多,然而watchEffect不须要阐明监听谁,用到谁就监听谁 用法:<script setup lang="ts">import { ref, reactive, computed,watch, watchEffect } from 'vue'// 常量const name = ref('小明')// 对象、数组const user = reactive({ name: '小红', gender: '女'})// computed计算出userTextconst userText = computed(() => { return `我叫${user.name},我是${user.gender}的`})// 监听user对象watch(user, (next) => { console.log('user被批改了', next)}, { immediate: false, // 首次执行 deep: true // 深度监听对象})// 可监听对象的某个属性,这里监听user.genderwatch(() => user.gender, (next, pre) => { console.log('user.gender被批改了', next, pre)})// 不须要阐明监听谁// 用到user.gender就监听user.genderwatchEffect(() => { const gender = user.gender console.log('user.gender被批改了', gender)})</script><template> <div>{{ userText }}</div></template>4、生命周期 ...

February 23, 2023 · 3 min · jiezi

关于vue3:使用Nuxt3创建一个项目模版的相关配置以及遇到的一些问题

Arco Nuxt3 Admin这四个应用 nuxt3 和 Arco Design 创立的简略我的项目模版,上面是一些创立我的项目的相干配置和遇到的一些问题 我的项目地址 初始化创立这里我应用 pnpm 创立,详情查看Nuxt3 Installation pnpm dlx nuxi init arco-nuxt3-admincd arco-nuxt3-adminpnpm install运行启动 http://localhost:3001/ pnpm run dev默认 3000 端口,能够在 nuxt.config.ts 中更改 export default defineNuxtConfig({ devServer: { port: 3001, },});打包打包后的我的项目在 .output 目录下 pnpm run build装置库arco-design装置pnpm install @arco-design/web-vue配置创立 plugins/arco-design.ts 文件; import ArcoVue from "@arco-design/web-vue";// 此处引入css则不须要在nuxt.config.ts配置import "@arco-design/web-vue/dist/arco.css";export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(ArcoVue);});在 nuxt.config.ts 配置 plugins; css 在一个中央引入即可 //nuxt.config.tsexport default defineNuxtConfig({ // 引入arco-design款式 css: ["@arco-design/web-vue/dist/arco.css"], // 插件形式引入arco-design组件 plugins: ["@/plugins/arco-design"],});引入 js 库判断客户端加载在引入某些第三方 js 库时,会报错"window is undefined",能够判断是否在客户端,应用到时再加载; ...

February 21, 2023 · 2 min · jiezi

关于vue3:vue3-getCurrentInstance函数为什么可以获取到组件实例

1、疑难在vue3中应用过getCurrentInstance函数获取组件实例的同学,不晓得你们在应用了getCurrentInstance函数后会不会去想为什么getCurrentInstance函数是一个全局性的函数,它能够获取到组件实例?它是怎么实现的? 2、实现原理原理为: vue定义了一个全局的currentInstance变量,在执行组件的setup函数前将currentInstance变量赋值为以后组件实例(组件实例早曾经创立好了),接着执行setup函数,setup函数执行结束后将currentInstance变量置为null;至此currentInstance变量更新结束这里又引发另一个疑难:一个页面中有几十上百个平行或嵌套的组件,调用getCurrentInstance的时候怎么能确保获取的就是以后组件的实例呢? 这得益于js是单线程的,在同一个宏工作中所有代码都是从上往下执行的,并且vue组件也是从整个组件树中从上往下初始化(能够了解为组件的setup函数是从整个组件树中从上往下开始执行,它们是串行的),有了这2个根底条件getCurrentInstance函数的实现形式就行的通。currentInstance值变动过程组件setup执行程序留神:getCurrentInstance函数只有在setup函数中的同步代码中调用才无效,在异步代码中有效(如:Promise、事件、网络申请、setTimeout),因为setup函数自身执行结束后currentInstance变量的值会被置为null 这个点在之前的vue官网文档中是有阐明的,但当初的vue官网文档中曾经找不到getCurrentInstance函数的文档了(截止工夫:2023-02-21)

February 21, 2023 · 1 min · jiezi

关于vue3:从零开始搭建Vue组件库

 前言: 组件设计是通过对性能及视觉表白中元素的拆解、演绎、重组,并基于可被复用的目标,造成规范化的组件,通过多维度组合来构建整个设计方案,將这些组件整顿在一起,便造成组件库。本文咱们次要讲述基于VantCLI的自建组件库。VantCLI是一个基于Vite实现的Vue组件库构建工具,通过VantCLI能够疾速搭建一套性能齐备的Vue组件库。 建设组件库的意义 首先组件库能够给咱们降本提效,其次能够放弃视觉格调对立以及交互统一,能够帮忙咱们疾速构建应用场景,便于多个我的项目后续迭代降级。 视觉格调对立以及交互的一致性,能够缩小用户学习老本造就用户习惯,让产品领有良好的用户体验。比方一个四级地址的抉择组件,在整个产品中应该就一种交互方式,如果一会是滚动抉择,一会是点击抉择,会让用户操作起来比拟焦躁,对立交互能够缩小用户学习老本。 新产品上线后,还须要一直的去欠缺,在迭代过程中可能会新增其余性能,这时候咱们就能够只批改组件库一套代码,所有不同我的项目雷同组件就能够达到了迭代降级的成果。 如何创立组件库 一、梳理组件清单 首先梳理出我的项目中款式雷同的模块,和产品探讨将来会有哪些布局,现有的组件是否可能满足需要,是否须要补充设计方案,清单整顿结束后,将每一个组件建成一个独立工作,像日常需要那样,不便随时更新应用。 二、场景整合 把本人变成产品的深度用户,把现有线上产品残缺体验一遍,绘制用户行为门路,并和需求方沟通了解后续打算,将组件的所有的以后/潜在利用场景总结进去,尽可能不脱漏场景。 三、组件库框架选型 看了开源的Vue3组件库,总结了一些前端目前风行的趋势,列出来多个版本和框架的,本文只探讨Vue3版本。 1、element-plus:经典中的经典,全面反对Vue3 2、tdesign-vue-next:鹅厂优质UI组件,配套工具完美,设计工整,文档清晰 3、arco-design-vue:字节跳动开源UI组件库,大厂逻辑,设计文档完满 4、ant-design-vue:蚂蚁前端UI库,面向企业级中后盾 5、naive-ui:宝藏VueUI库,VueUI新星,从Vue3起步 6、vant:有赞团队开源挪动UI组件库,全面反对Vue3 7、nutui:京东出品,挪动端敌对,面向电商业务场景 8、vuetify:老牌VueUI,基于谷歌的MaterialDesign款式开发 9、varlet-Varlet:一个基于Vue3开发的Material格调挪动端组件库,全面拥抱Vue3生态,由社区建设起来的组件库团队进行保护。 四、组件库搭建 咱们以VantCLI为例来具体分析具体搭建过程: 1、首先确保本地node版本^12.13.0||^14.15.0||>=16.0.0 2、执行以下命令能够疾速创立一个基于VantCLI的我的项目 yarn create vant-cli-app 3、手动装置 # 通过 npmnpm i @vant/cli -D# 通过 yarnyarn add @vant/cli -D# 通过 pnpmpnpm add @vant/cli -D 4、手动配置 ...

February 17, 2023 · 2 min · jiezi

关于vue3:如何在Nuxt3中设置接口代理

背景可能很多人会纳闷,为啥咱们都用了服务端渲染框架,还须要用接口代理呢?其实大多数团队,都是前后端拆散的架构,曾经用 Java 或者其余后端语言开发并部署好了接口服务。这种状况下,咱们天然只须要将前端的申请通过代理转发给服务端的server就好了。Nuxt3 中提供的 useFetch 办法封装了很多网络申请的细节,不过该办法会因为渲染模式的不同在应用上也存在着一些差别。上面笔者就将会讲述如何在各种状况下为 useFetch 办法配置申请的代理。 如何配置?1.渲染模式为客户端渲染时Nuxt3 最新的正式版应用了nitro做为 dev server, 在其官网文档中,有阐明如何配置代理: { devProxy: { '/proxy/test': 'http://localhost:3001', '/proxy/example': { target: 'https://example.com', changeOrigin: true } }}咱们须要将该配置代理的选项搁置到 nuxt.config.ts 文件的 nitro 选项中,如下: export default defineNuxtConfig({ // ...other setting server: false, // 不开启服务端渲染 nitro: { devProxy: { "/api": { target: "http://localhost:3001", // 这里是接口地址 changeOrigin: true, prependPath: true, }, }, },});该形式针对服务端渲染的场景也能失效,然而仅会针对产生在客户端测的申请进行代理。比方设置了server: false或者因为一些交互行为而触发的网络申请。 const { data: userinfo } = await useFetch("/api/userinfo", { server: false,});2.渲染模式为服务端渲染或者预渲染时当咱们必须得在服务端进行渲染且也须要对服务端的申请进行代理转发的话,上述办法配置是不可行的。笔者寻遍全网,发现很多解决方案是装置一些Nodejs的第三方库去实现接口代理的。其实没有必要,笔者在nitro的官网文档中找到了计划,即配置routeRules参数。 ...

February 17, 2023 · 1 min · jiezi

关于vue3:Nuxt3实战系列之网络请求篇

Nuxt3提供了4种形式使得咱们能够异步获取数据 useAsyncDatauseLazyAsyncData (useAsyncData+lazy:true)useFetchuseLazyFetch (useFetch+lazy:true)4种形式中,其实外围的就是useAsyncData和useFetch。这两个办法不同于Nuxt2中的asyncData和fetch。接下来咱们先来好好剖析下这两个办法。 useAsyncData咱们晓得,在Nuxt2中,asyncData办法相似于一个生命周期函数,它在服务端或路由更新之前被调用。办法的参数是以后页面的上下文对象,咱们个别是利用 asyncData办法来获取数据并返回给以后组件,以防止申请放在客户端执行时带来的数据提早呈现问题。 export default { data() { return { project: 'default' } }, asyncData(context) { return { project: 'nuxt' } }}在Nuxt3中,useAsyncData能够看做是异步获取数据场景的一个封装,而且变成了一个被动调用函数,原则上能够在任何机会调用。 // 用法const { data: Ref<DataT>,// 返回的数据后果 pending: Ref<boolean>,// 是否在申请状态中 refresh: (force?: boolean) => Promise<void>,// 强制刷新数据 error?: any // 申请失败返回的错误信息} = useAsyncData( key: string, // 惟一键,确保雷同的申请数据的获取和去重 fn: () => Object,// 一个返回数值的异步函数 options?: { lazy: boolean, server: boolean } // options.lazy,是否在加载路由后才申请该异步办法,默认为false // options.server,是否在服务端申请数据,默认为true // options.default,异步申请前设置数据data默认值的工厂函数(对lazy:true选项特地有用) // options.transform,更改fn返回后果的函数 // options.pick,只从数组中指定的key进行缓存)从api的设计中能够看出,useAsyncData没有限度咱们发动网络申请的形式,同时它还裸露了申请状态,减少了刷新管制,以及对反复获取数据的去重管制等。应用示例如下: ...

February 14, 2023 · 2 min · jiezi

关于vue3:vue3公司自用项目实战入门vue3router4antdvpinia实现

一.为什么学typescriptvar三大框架都是用ts写的,做个类比,如果你不晓得阿拉伯数字和加减法,怎么解应用题?同理不会ts如何应用vue开发工作我的项目? 二.开发环境筹备1.装置node,https://nodejs.org/en/,下载安装,一路默认下一步 ,输出node -v显示版本胜利 2.装置ts,npm install -g typescript,输出tsc -v显示版本 阐明胜利 3.装置vscode https://code.visualstudio.com/ 三.新建一个Helloworld 文件夹,用vscode关上,而后新建app.ts,外面就写一句 console.log('hello world') 而后在vscode 终端输出 tsc app.ts ,如果报错 先输出 set-ExecutionPolicy RemoteSigned 最初看到生成一个编译同名app.js阐明胜利了。你说我想看看打印成果,整个index.html <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="app.js"></script></head><body> </body></html>console.log('hello world')改成console.log('真香')终端按上箭头,从新tsc app.ts,看浏览器控制台,能看到真香。 三、typescript基础知识1.模块治理 传统教程该讲数据类型了,咱们先放放间接将外围的模块治理,因为根底的数据类型number string 不讲你也会,高级的数据类型讲到了当初你也不明确怎么用。就说一件事,ts下怎么定义各种数据类型省的遇见ts外面类型报错,你就懵圈了,这里跟js是不一样的。 就简要提一嘴,常见的就是定义数组: let num = 0;let str = '彬哥好帅';//下面的没区别,上面说不一样的//js这么写是没问题的://定义数组,第一种:let person: string[] = ['张三', '帅彬'];//第一种有个毛病,比方我要解决一个数组过程中split的时候,可能会呈现,[1,'张三',2,'帅彬'],这样你定义成string就报错两种类型let worker: [number, string] = [1, "张三",2,"帅彬"];//记住以上两种数组就够用了,接下来咱们说说数组外面套对象{},这个最罕用,以前咱们在js下定义一个数组含对象//js下let worker = [ {1, "张三"}, {2, "帅彬"} ];//ts下 这样写interface Worker { id: number; name: string;}let worker: Worker[] = [ { id: 1, name: "张三" }, { id: 2, name: "帅彬" }];//你在我的项目中很可能遇到一种状况就是你通过对象的key的值去索引对象的value,比方worker[//这里是什么也可能是动静的变量],//这种状况怎么定义?interface Worker { id: number; [key: string]: string;//要害是这一句,前面你甭管它叫啥只有是string类型编译就不错}let worker: Worker[] = [ { id: 1, name: "张三" }, { id: 2, jobName: "帅彬" }];最初一句,数据类型你不晓得也不要用any,不要用any,不要用any,因为往往报any的时候,意味着你代码写的有问题。 ...

January 2, 2023 · 10 min · jiezi

关于vue3:Vue3-JSX-写法笔记

Vue3 是能够用 JSX 语法间接写的, 大体能够从 https://sfc.vuejs.org/ 的示例看到,其中 <div> 会编译为 h('div'), 具体参考 https://vuejs.org/guide/extra... .残缺的组件定义形如: import { defineComponent, PropType } from 'vue';import { onMounted, ref, watch } from 'vue';const App = defineComponent({ name: "App" props: { appId: { type: String as PropType<string>, default: '', }, }, emits: [], setup(props, {emit, expose, slots}) { return () => ( <div>TODO</div> ); },});export default App;其中 name 调试中组件的名字,props 须要用这样的写法用 Object 格局传入,emits 能够用字符串格局制订实际, 而 emit 函数从参数中拿到,slots 也是从参数当中拿到,expose 也是从参数当中失去的,留神最终的 render 函数, 范畴与 setup 函数有区别,其中 setup 函数只会被执行一次, 而 render 函数可能屡次执行.而须要响应式追踪的逻辑, 须要写在 setup 函数里边, 否则行为不能达到预期,有了 JSX, 原有的 v-if v-else 能够和 React 同样间接写了, ...

December 26, 2022 · 1 min · jiezi

关于vue3:vue3vitetselementplus-自定义主题

我我的项目应用vite,并且在按需导入时自定义主题。我的项目依赖: "@element-plus/icons-vue": "^2.0.10","axios": "^1.2.0","crypto-js": "^4.1.1","echarts": "^5.4.0","element-plus": "^2.2.25","pinia": "^2.0.26","vue": "^3.2.45","vue-router": "^4.1.6"一、通过SCSS变量更换主题色我我的项目应用了SCSS,theme-chalk也是应用SCSS编写而成,因而能够间接批改Element Plus的款式变量。在packages/theme-chalk/src/common/var.scss文件中能够查找SCSS变量。 1、新建一个款式文件,例如: src/assets/styles/element/index.scss /* 只须要重写你须要的变量即可 */@forward 'element-plus/theme-chalk/src/common/var.scss' with ( $colors: ( 'primary': ( 'base': green, ), ),);// 如果只是按需导入,则能够疏忽以下内容。// 如果你想导入所有款式:// @use "element-plus/theme-chalk/src/index.scss" as *;下面index.css的内容援用自element Plus官网。留神:最初一部分须要,并不是按官网所说按需导入可疏忽。 2、应用scss.additionalData来编译所有利用 scss 变量的组件。import { defineConfig } from 'vite'import { fileURLToPath, URL } from 'node:url'import vue from '@vitejs/plugin-vue'import vueJsx from '@vitejs/plugin-vue-jsx'// element plus按需主动导入组件import AutoImport from 'unplugin-auto-import/vite'import Components from 'unplugin-vue-components/vite'// 按需导入element组件import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'import Icons from 'unplugin-icons/vite'import IconsResolver from 'unplugin-icons/resolver'import path from 'path'const postCssPxToRem = require("postcss-pxtorem")const pathSrc = path.resolve(__dirname, 'src')// https://vitejs.dev/config/export default defineConfig({ server: { host: '0.0.0.0' // 通过ip+port拜访服务器 }, plugins: [ vue(), vueJsx(), AutoImport({ // Auto import functions from Vue, e.g. ref, reactive, toRef... // 主动导入 Vue 相干函数,如:ref, reactive, toRef 等 imports: ['vue'], resolvers: [ ElementPlusResolver(), // 主动导入Element Plus相干函数,如:ElMessage, ElMessageBox... (带款式) // 主动导入图标组件 IconsResolver({ prefix: 'Icon', // <IconCarbonApps /> // extension: 'jsx', }), ], dts: path.resolve(pathSrc, 'auto-imports.d.ts'), }), Components({ resolvers: [ // Auto register Element Plus components // 主动导入 Element Plus 组件 ElementPlusResolver(), // 主动注册图标组件 IconsResolver({ // prefix: 'i', // 默认前缀i, false, 就可不是用前缀 // 实际上应用的时候,要加上 i-ep- 前缀,并举荐改成短横线命名 // <el-icon><i-ep-arrow-right-bold /></el-icon> // {prefix}-{collection}-{icon} // this is optional, default enabling all the collections supported by Iconify enabledCollections: ['ep'] // element-plus图标库 }) ], dts: path.resolve(pathSrc, 'components.d.ts'), }), Icons({ autoInstall: true, // compiler: 'jsx', // or 'solid' 不知是不是与<IconCarbonApps />无关 }), ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) // resolve(__dirname, 'src'), } }, css: { preprocessorOptions: { scss: { additionalData: '@use "src/assets/styles/element/index.scss" as *;', }, }, postcss: { plugins: [ postCssPxToRem({ rootValue: 64, // 1rem的大小 propList: ['*'], // 须要转换的属性,这里抉择全副都进行转换 }) ] }, },})二、通过 CSS 变量设置element用css变量重构了简直所有组件的款式零碎。它兼容SCSS变量零碎。element应用SCSS的函数主动生成须要用到的css变量。能够动静地扭转组件内的个别变量,以便更好地自定义组件款式,而不须要批改SCSS文件从新编译一次。之后,每个组件的css变量名称和作用将被写入到对应的组件文档中。就像这样: ...

December 3, 2022 · 2 min · jiezi

关于vue3:Vue登录验证功能

实现一个网页未登录时主动跳转至登录界面?在地址栏输出url之后,如果以后localStorage中并未存储==token==并且咱们要去的网页并不是登录页面,可想而知,该当强制跳转至登录页面。这里就能够利用vue-router的路由守卫来实现。 利用beforeEach,当token存在或者要去往的页面是登录页面(我要登录总还是能够的吧~),间接放行;否则,利用next跳转至登录界面(路由为'/login')// src/router/index.jsrouter.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (token || to.path === '/login') { next() } else { next('/login') }})用户名与明码正确后登录又如何跳转至首页(或者其余页面)?实现了下面的束缚之后,咱们就能够来实现登录性能了。 当用户名明码正确之后,点击登录,但这时咱们还无奈跳转至首页,因为下面的路由守卫中还须要token,咱们应能从后端获取到token,并将该token存入localStorage中,并利用router.replace('/')来进行路由跳转。 以下是一个小例子: // 利用element plus的表单性能const submitForm = (formRef) => { formRef.validate((valid) => { if (valid) { // 如果表单校验胜利并且用户名和明码正确,则将token存储起来,并跳转至首页 if (loginForm.value.username === 'admin' && loginForm.value.password === 'admin') { localStorage.setItem('token', 'i have token!') router.replace('/') } } else { console.log('error') } })}

November 24, 2022 · 1 min · jiezi

关于vue3:vue3使用antdesign中分页组件国际化设置

默认是英文。 设置国际化1.先引入文件 import { ConfigProvider } from 'ant-design-vue' import zhCN from 'ant-design-vue/es/locale/zh_CN'2.而后导出 zhCN 3.标签应用

November 7, 2022 · 1 min · jiezi

关于vue3:Taro-自动部署微信支付宝小程序附带动态修改支付宝体验版版本号

背景:应用taro3同时开发 微信小程序 + 支付宝小程序;排除根底API性能外根本不须要双平台打包上传;而且在本地打包完微信应用开发者工具上传;再次打包支付宝应用支付宝开发者工具上传;绝对繁琐;所以应用ci机器人配合jenkins达到提交代码主动部署双平台并且发送飞书音讯告诉1. 微信小程序主动上传体验版1.1 装置相干插件依赖小程序继续集成 借助该文档的plugin-mini-ci插件进行机器人主动部署性能 1.2 微信小程序机器人部署代码配置打包配置批改 // config/index.jsconst CIPluginOpt = { // 微信小程序 weapp: { appid: 'appid', // 在开放平台下载的密钥文件;放到根目录的门路;见下图 privateKeyPath: 'private.appid.key' }, // 版本号 version: '0.0.2', // 版本公布形容 desc: '版本形容'// ....其余代码const config = { // 其余代码 plugins:[['@tarojs/plugin-mini-ci', CIPluginOpt], '@tarojs/plugin-html', 'taro-plugin-pinia'], }}1.3 设置主动上传体验版白名单增加打包后上传ip白名单 1.4 配置npm打包+上传命令 // package.json "build:weapp:upload": "taro build --type weapp --upload",应用npm run build:weapp:upload 即可实现本地打包后胜利上传到体验版 至此微信小程序本地打包主动部署到体验版曾经实现![撒花] 2. 支付宝小程序主动上传到体验版前言:支付宝小程序体验版版本号绝对严格(须要本次上传的版本号必须大于上次的版本号)2.1 装置相干插件依赖(和1雷同)小程序继续集成 借助该文档的plugin-mini-ci插件进行机器人主动部署性能 2.2 批改上传前版本号能够手动的批改版本号而后持续也能够应用nodejs批改版本号而后持续(本我的项目应用计划)2.3 支付宝小程序机器人部署代码配置打包配置批改 // config/index.js// 引入package.json内的版本号import packageData from '../package.json'const CIPluginOpt = { // 微信小程序 weapp: { appid: 'appid', // 在开放平台下载的密钥文件;放到根目录的门路;见下图 privateKeyPath: 'private.appid.key' }, // 支付宝小程序 alipay: { appId: '支付宝小程序appid', toolId: '应用工具生成(见2.3.1), privateKeyPath: '私钥应用工具生成(见2.3.1)' }, // 版本号(如果是微信小程序就固定002;能够不必更新体验版二维码图片;其余间接读package.json的版本号) version: process.argv.includes('weapp') ? '0.0.2' : packageData.version, // 版本公布形容 desc: '版本形容'// ....其余代码const config = { // 其余代码 plugins:[['@tarojs/plugin-mini-ci', CIPluginOpt], '@tarojs/plugin-html', 'taro-plugin-pinia'], }}2.3.1 生成配置须要的 toolId装置工具npm install alipay-dev -g工具初始化配置 ...

November 4, 2022 · 1 min · jiezi

关于vue3:vue3-使用wangeditor封装和自定义上传文件

1、根本配置,官网教程https://www.wangeditor.com/ 2、封装组件/** initValue: 父组件传递过去的富文本框初始值,这里会实时监听,更新初始值,搁置在弹窗中应用,没有钩子函数的更新。 getEditorContent() 办法,父组件通过这个办法获取富文本编辑器的内容,包含数组格局的和html格局的内容*/<template> <div v-html="valueHtml"></div> <div style="border: 1px solid #ccc"> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" /> <Editor style="min-height: 100px; overflow-y: hidden; text-align: left;" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode" @onCreated="handleCreated" @onChange="handleChange" /> </div></template><script setup>import '@wangeditor/editor/dist/css/style.css' // 引入 cssimport { onBeforeUnmount, ref, shallowRef, onMounted, nextTick, watch } from 'vue'import { Editor, Toolbar } from '@wangeditor/editor-for-vue'import axios from 'axios'// 初始值const props = defineProps({ initValue: String})const emits = defineEmits(['getEditorContent'])// const emits = defineEmits([''])let mode = ref('default')// 编辑器实例,必须用 shallowRefconst editorRef = shallowRef()// 内容 HTMLconst valueHtml = ref('')// 模仿 ajax 异步获取内容onMounted(() => { nextTick(() => { // 界面节点更新完当前再批改值。 valueHtml.value = props.initValue })})// 工具栏配置const toolbarConfig = { toolbarKeys: [ // 菜单 key 'headerSelect', 'bold', // 加粗 'italic', // 斜体 'through', // 删除线 'underline', // 下划线 'bulletedList', // 无序列表 'numberedList', // 有序列表 'color', // 文字色彩 'insertLink', // 插入链接 'fontSize', // 字体大小 'lineHeight', // 行高 'uploadImage', // 上传图片 'delIndent', // 缩进 'indent', // 增进 'deleteImage',//删除图片 'divider', // 分割线 'insertTable', // 插入表格 'justifyCenter', // 居中对齐 'justifyJustify', // 两端对齐 'justifyLeft', // 左对齐 'justifyRight', // 右对齐 'undo', // 撤销 'redo', // 重做 'clearStyle', // 革除格局 'fullScreen' // 全屏 ]}const editorConfig = { placeholder: '请输出内容...', // 配置默认提醒 // readOnly: true, MENU_CONF: { // 配置上传服务器地址 uploadImage: { // 小于该值就插入 base64 格局(而不上传),默认为 0 base64LimitSize: 5 * 1024, // 5kb // 单个文件的最大体积限度,默认为 2M // maxFileSize: 1 * 1024 * 1024, // 1M // // 最多可上传几个文件,默认为 100 // maxNumberOfFiles: 5, // 抉择文件时的类型限度,默认为 ['image/*'] 。如不想限度,则设置为 [] allowedFileTypes: ['image/*'], // 自定义上传 async customUpload(file, insertFn) { // 文件上传 const formData = new FormData(); formData.set('file', file) // 这里依据本人我的项目封装状况,设置上传地址 axios.defaults.headers.common['Authorization'] = 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX2tleSI6IjVhYzc3MDQxLTE3NGItNDEwZC1hOTJlLTVkYzU0YmRhMjllNiIsInVzZXJuYW1lIjoiYWRtaW4ifQ.GhdthjLmw4NP2WV2owYQS70tacRM-pX7NqI7Mo0_j_hatiqtSrqAr0RJC40osRETiQo_dacZcvNqATLsJHL77A' let result = await axios.post('https://zxc.test.cn/file/upload', formData) // 插入到富文本编辑器中,主见这里的三个参数都是必填的,要不然控制台报错:typeError: Cannot read properties of undefined (reading 'replace') insertFn(result.data.data.url, result.data.data.name, result.data.data.name) } } }}// 组件销毁时,也及时销毁编辑器onBeforeUnmount(() => { const editor = editorRef.value if (editor == null) return editor.destroy()})const handleCreated = (editor) => { editorRef.value = editor // 创立富文本编辑器}const handleChange = (info) => { // info.children 数组蕴含了数据类型和内容,valueHtml.value内容的html格局 emits('getEditorContent', info.children, valueHtml.value)}watch(()=>props.initValue, (value) => { // 父组件获取初始值 valueHtml.value = value})</script>3、应用父组件<wang-editor :initValue="form.baseInfo.descInfo" @getEditorContent="onEditorChange"></wang-editor>import WangEditor from '@/components/WangEditor'const onEditorChange = (arr, html) => { console.log(arr, html)}

November 1, 2022 · 2 min · jiezi

关于vue3:vue3tauri聊天室taurirust跨端实例tauri仿微信

上一篇有给大家分享Tauri创立多窗口利用实际。明天分享最新开发的Tauri+Vite3客户端聊天实例我的项目。 tauri-vue3-chat 基于 tauri+vue3+vite3+element-plus+v3layer 等技术开发仿微信客户端利用。 实现了发送图文音讯、图片+视频+网址预览、拖拽发送图片、朋友圈等性能。反对tauri关上多个窗体、主题换肤等性能。 技术框架编辑器:VScode应用技术:tauri+vue^3.2.37+vite^[email protected]UI组件库:element-plus^2.2.17 (饿了么vue3组件库)弹窗组件:v3layer(基于vue3自定义pc端弹窗组件)滚动条组件:v3scroll(基于vue3模仿滚动条组件)矢量图标:阿里iconfont字体图标库 tauri多开窗体tauri提供了多种创立新窗口的办法,依据我的项目需要,本人封装了一个前端多窗口生成器。 // 对于const openAboutWin = () => { createWin({ label: 'about', title: '对于', url: '/about', width: 430, height: 330, resizable: false, alwaysOnTop: true, })}// 主题换肤const openThemeSkinWin = () => { createWin({ label: 'skin', title: '换肤', url: '/skin', width: 630, height: 400, resizable: false, })}// 朋友圈const openQzoneWin = () => { createWin({ label: 'fzone', title: '朋友圈', url: '/fzone', width: 550, height: 700, resizable: false, })}反对如下参数配置 ...

October 29, 2022 · 3 min · jiezi

关于vue3:超细的tab标签页缓存方案Vue2Vue3

theme: fancy超细tab标签页缓存应该具备简略配置就能缓存页面反对标签页刷新一键敞开其余标签页地址跳转主动关上或切换对应标签页放弃滚动地位反对多级缓存反对手动删除标签页缓存蕴含 Vue2 和 Vue3 两种实现计划快捷入口vue2 demo: https://xiaocheng555.github.i... (PC关上食用更佳) vue3 demo: https://xiaocheng555.github.i... (PC关上食用更佳) 代码: https://github.com/xiaocheng5... 效果图: Vue2 实现计划实现缓存毫无疑问,缓存用的是 <keep-alive> 组件,用 <keep-alive> 包裹路由组件,从而缓存tab标签页。 <keep-alive> 组件有个 include 属性,在 include 数组里增加或者移除组件名可让tab标签页增加或删除缓存;为了对立治理,把缓存的操作写到vuex里。 缓存标签页: <keep-alive ref="alive" :include="caches"> <router-view></router-view></keep-alive>操作 caches 缓存: // src/store/cache.jsimport Vue from 'vue'export default { namespaced: true, state: { caches: [] }, actions: { // 增加缓存的路由组件 addCache ({ state, dispatch }, componentName) { const { caches } = state if (!componentName || caches.includes(componentName)) return caches.push(componentName) }, // 移除缓存的路由组件 removeCache ({ state, dispatch }, componentName) { const { caches } = state const index = caches.indexOf(componentName) if (index > -1) { return caches.splice(index, 1)[0] } }, // 移除缓存的路由组件的实例 async removeCacheEntry ({ dispatch }, componentName) { const cacheRemoved = await dispatch('removeCache', componentName) if (cacheRemoved) { await Vue.nextTick() dispatch('addCache', componentName) } } }}2、缓存做成可配置 ...

October 25, 2022 · 6 min · jiezi

关于vue3:Vue3-也能做游戏飞翔的思否猫挖坑警告

大家晓得,作为一个开发者社区,10 月 24 日不搞点事件有点说不过去。于是思否经营同学找到我,邀请我出一篇文章,以思否猫为主题进行开发。我当即就许可了,写代码写文章嘛,小事一桩。 我不想走寻常路,看了思否猫的造型后,当即决定用 Web 技术做一个横版航行游戏。而且要用 OpenCV + 面部辨认来管制,还要用语音管制发炮。能够说,过后想的很好。然而,现实很饱满,事实很骨感,当初看着只写了一半的代码,悔不当初啊…… 0. 技术预研先说论断: Web 语音辨认临时难堪大用OpenCV 在现代化浏览器的性能足够具体来说,我不太确定 Web 语音辨认(STT)的实现机制,比方:是本地集成模型,还是要发给服务器,辨认了再返回给客户端?实测的成果不太现实,响应速度太慢,兴许做个别的利用尚可,搞游戏就齐全不可行,从发声到失去后果至多须要 10s。不过兼容性还能够,Android、iOS、桌面都能用。 OpenCV 我找到了 这个我的项目,尽管没有文档,然而有 demo 页,成果不错,响应速度很快,基本上能够满足操控所需。 所以我决定: 如果工夫足够,那么我就用 Web Audio 中的音量 API 制作发炮性能。即只有声音够大就开炮,而不是最后构想的要念特定单词(我甚至 YY 念不同的单词发不同的炮)。OpenCV 肯定要用,不然不够酷。能够说,我这会儿都还太过自信。 1. 其它技术选型做游戏,有些同学可能会想到 Cocos、Unity 等技术,至多也要在 <canvas> 里画图。不过,对于一款简略的横版航行游戏,我感觉 DOM 就足够了。没有很简单的图层关系、没有很多元件须要做断定,固定思否猫在屏幕中线高低飞,撞到墙就失败,我甚至能够利用 InsersectionObserver 帮忙做碰撞检测。 于是我决定: 还是基于 Vue3 + Vite 来做,至多非游戏的交互局部(开始游戏、显示问题、显示处分等)就很简略游戏内容用 DOM 来实现,根本 position: relative + absolute 就足够碰撞检测用 IntersectionObserver 来实现2. 创立 Vite 我的项目谋定就能够开始动了。比拟意外的是,我厂最近忽然特地忙,加上国庆节亲戚来广州玩时攒了不少事件(“国庆后国庆后……”),所以空余工夫很少,始终拖到本周一才开始入手。 (嗯,先铺垫着,咱们来看代码。) 创立 Vite 我的项目很简略,咱们参考官网文档即可: pnpm create vite sf-cat-flying --template vue接着,装置我的罕用依赖,因为游戏比较简单,就不须要 vue-router 那些了: ...

October 21, 2022 · 2 min · jiezi

关于vue3:vue3全家桶之状态管理器pinia的使用

Pinia (发音为 /pinj/,相似英文中的 “peenya”) 是最靠近无效包名 piña(西班牙语中的 pineapple,即“菠萝”)的词。 菠萝花实际上是一组各自独立的花朵,它们联合在一起,由此造成一个多重的水果。 与 Store 相似,每一个都是独立诞生的,但最终它们都是互相分割的。 它(菠萝)也是一种原产于南美洲的美味寒带水果。 pinia作为vue官网举荐的状态管理器,先不说别的,看文档用一下再说pinia的用法多少会和vuex有些不同,缓缓学习在找不一样的中央。 pinia劣势为 JS 开发者提供适当的 TypeScript 反对以及 autocompletion 性能。反对服务端渲染pinia应用须要通过办法来定义状态,并且定义状态 import { defineStore } from 'pinia'两种办法定义状态,一种为选项式,一种为函数式(文档中称说与组件 setup() 相似) // 选项式用法export const useCounterStore = defineStore('counter', { state: () => { return { count: 0 } }, actions: { increment() { this.count++ }, },})// 函数式用法export const useCounterStore = defineStore('counter', () => { const count = ref(0) function increment() { count.value++ } return { count, increment }})(可先略过)如果用选项式的话,Pinia 也提供了一组相似 Vuex 的 map helpers。你能够用和之前一样的形式来定义 Store,而后通过 mapStores()、mapState() 或 mapActions()应用 ...

October 20, 2022 · 5 min · jiezi

关于vue3:Vue3构建开发遇到的错误

npm ERR! code ERESOLVEnpm ERR! ERESOLVE could not resolve可能npm有问题,可能依赖包之间有抵触,命令行提醒 加上 --legacy-peer-deps

October 15, 2022 · 1 min · jiezi

关于vue3:未设置标题的文章

vue-awesome-console,一个舒服的 vue3 打印变量的工具它能够帮忙你在 console.log(某些响应变量) 的时候,从一大堆的 Proxy computed ref 对象及其办法中解脱进去,分心打印你想看到的原始值。当然,它也齐全能够像console.log一样,打印一般的js数据类型、窗口节点对象用法:// 在src/app.js等根文件下import vlog from 'vue-awesome-console'// 你能够抉择将 vlog 办法挂在 console 对象上,而后像应用 console.log 一样应用 console.vlog// 同时你也能够依据我的项目中的开发/生产模式,进行不同的应用形式if ( process.env.NODE_ENV === 'development' ) { window.console.vlog = vlog} else { window.console.vlog = () => {}}情景个别的 console.log 打印比方在某组件中,打印 vue-router , const route = useRoute() 中的 route,其后果是: {Proxy {path: ComputedRefImpl, name: ComputedRefImpl, params: ComputedRefImpl, query: ComputedRefImpl, hash: ComputedRefImpl, …}// 开展后{Proxy {path: ComputedRefImpl, name: ComputedRefImpl, params: ComputedRefImpl, query: ComputedRefImpl, hash: ComputedRefImpl, …}[[Handler]]: Object[[Target]]: ObjectfullPath: ComputedRefImpl {dep: undefined, __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}hash: ComputedRefImpl {dep: undefined, __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}matched: ComputedRefImpl {dep: Set(2), __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}meta: ComputedRefImpl {dep: undefined, __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}name: ComputedRefImpl {dep: undefined, __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}params: ComputedRefImpl {dep: Set(1), __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}path: ComputedRefImpl {dep: undefined, __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}query: ComputedRefImpl {dep: undefined, __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}redirectedFrom: ComputedRefImpl {dep: undefined, __v_isRef: true, _dirty: false, effect: ReactiveEffect, _setter: ƒ, …}[[Prototype]]: Object[[IsRevoked]]: falseconsole.vlog 打印以上的 route 变量{path: '/home/welcome', name: 'welcome', params: {…}, query: {…}, fullPath: '/home/welcome', …}// 开展后fullPath: "/home/welcome"matched: (2) [{…}, {…}]meta: {}name: "welcome"params: {}path: "/home/welcome"query: {}redirectedFrom: {fullPath: '/home/welcome', path: '/home/welcome', query: {…}, hash: '', name: 'welcome', …}[[Prototype]]: Object兴许你认为 JSON.parse(JSON.stringify(obj)) 能够起雷同的作用,当然,你得容忍某些情景下,某些变量在这个貌似深拷贝的办法下报错或数据失落什么的/滑鸡注:以后仅实用于 vue3

October 13, 2022 · 2 min · jiezi

关于vue3:vue3封装一个带动画的关闭按钮

预览成果: 实现源码: <template> <MenuBtn :open="openMenu" :size="24" /></template><template> <div :class="`menu ${open?'open':''}`" :style="`width:${size}px;height:${size}px`"> <span :style="` transition-duration:${duration}ms; transform:${open?`translateY(${(size-2)/2}px) rotate(-45deg)`:`translateY(${size/6}px)`}; `" /> <span :style="` transition-duration:${duration}ms; ${open?`opacity: 0;transform: rotate(-45deg)`:''} `" /> <span :style="` transition-duration:${duration}ms; transform:${open?`translateY(${-(size-2)/2}px) rotate(45deg)`:`translateY(-${size/6}px)`}; `" /> </div></template><script setup>// 这里用了vue3的专用写法。vue2写法,自行实现。const {open, size, duration} = defineProps({ open: { type: Boolean, default: false, required: true, }, size: { type: Number, default: 24, required: false }, duration: { type: Number, default: 300, required: false }});</script><style scoped lang="scss">.menu { position: relative; display: flex; align-items: center; justify-content: space-between; flex-direction: column; span { height: 2px; border-radius: 2px; display: flex; width: 100%; background-color: #333; }}</style>源码阐明:带有变量的款式,都写在行内了,因为这样适宜用在任意场景下。 ...

October 13, 2022 · 1 min · jiezi

关于vue3:Vue3的组件通信

1. props用 props 传数据给子组件有两种办法,如下 办法一:混合写法 // Parent.vue 传送<child :msg1="msg1" :msg2="msg2"></child><script>import child from "./child.vue"import { ref, reactive } from "vue"export default { data(){ return { msg1:"这是传级子组件的信息1" } }, setup(){ // 创立一个响应式数据 // 写法一 实用于根底类型 ref 还有其余用途,上面章节有介绍 const msg2 = ref("这是传级子组件的信息2") // 写法二 实用于简单类型,如数组、对象 const msg2 = reactive(["这是传级子组件的信息2"]) return { msg2 } }}</script>// Child.vue 接管<script>export default { props: ["msg1", "msg2"],// 如果这行不写,上面就接管不到 setup(props) { console.log(props) // { msg1:"这是传给子组件的信息1", msg2:"这是传给子组件的信息2" } },}</script>办法二:纯 Vue3 写法(语法糖) ...

October 10, 2022 · 3 min · jiezi

关于vue3:Vue3-admin后台模板

没有什么比图片更有说服力,是的正如你所见,vue-admin-beautiful是开源admin框架中vue+element-ui的最佳实际,目前已实现四种布局(综合布局、画廊布局、纵向布局、横向布局),为来将反对分组布局,四种主题(默认、陆地之心、绿荫草场、光荣典藏)共计16种布局主题搭配。简体中文 | English <div align="center"><img width="200" src="https://fastly.jsdelivr.net/gh/chuzhixin/image/logo/vab.png"/><h1> vue-admin-better</h1> <p>春已至,万物始,愿所有美妙纷沓而来!</p></div> 个性 40+高质量单页 RBAC 模型 + JWT 权限管制 10 万+ 我的项目理论利用 良好的类型定义 开源版本反对收费商用 跨平台 PC、手机端、平板️ 后端路由动静渲染 地址 vue2.x + element-ui(收费商用,反对 PC、平板、手机)⚡️ vue3.x + element-plus(alpha 版本,收费商用,反对 PC、平板、手机)⚡️ vue3.x + ant-design-vue(beta 版本,收费商用,反对 PC、平板、手机)⚡️ vue3.x + vite + arco admin pro 演示地址(vue2.x 付费版本,反对 PC、平板、手机) admin plus 演示地址(vue3.x 付费版本,反对 PC、平板、手机) pro 及 plus 购买地址 authorization Vue Shop Vite 商城(付费版本)行将公布,敬请期待! github 仓库地址 码云仓库地址<!-- ## 备份地址(反对 https 网站自动更新) ...

October 4, 2022 · 2 min · jiezi

关于vue3:Vue3-React18-TS4-入门到实战的积分回

download:Vue3 + React18 + TS4 入门到实战的积分回Vue 组件间的通信形式前言在Vue组件库的开发过程中,组件之间的通信一直是一个重要的课题。诚然官网的Vuex状态治理打算可能很好的解决组件之间的通信问题,然而组件库外部对Vuex的使用经常比较沉重。本文列举了几种实用的不使用Vuex的组件间通信方法,供大家参考。 组件之间通信的场景在进入咱们明天的主题之前,咱们先来总结下 Vue 组件之间通信的几种场景,一般可能分为如下几种场景: 父子组件之间的通信兄弟组件之间的通信隔代组件之间的通信父子组件之间的通信父子组件之间的通信应该是 Vue 组件通信中最简略也最常见的一种了,概括为两个部分:父组件通过 prop 向子组件传送数据,子组件通过自定义事件向父组件传送数据。 父组件通过 prop 向子组件传送数据Vue 组件的数据流向都遵循单向数据流的原则,所有的 prop 都使得其父子 prop 之间形成了一个单向上行绑定:父级 prop 的更新会向下流动到子组件中,然而反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的利用的数据流向难以理解。 额定的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件外部改变 prop。如果你这样做了,Vue 会在阅读器的控制台中收回警告。 父组件 ComponentA: <component-b title="welcome">子组件 ComponentB: {{title}} 16.子组件通过自定义事件向父组件传送数据在子组件中可能通过 $emit 向父组件发生一个事件,在父组件中通过 v-on/@ 进行监听。 子组件 ComponentA: <component-b :title="title" @title-change="titleChange">子组件 ComponentB: <div @click="handleClick">{{title}}这个例子非常简略,在子组件 ComponentB 外面通过 $emit 派发一个事件 title-change,在父组件 ComponentA 通过 @title-change 绑定的 titleChange 事件进行监听,ComponentB 向 ComponentA 传送的数据在 titleChange 函数的传参中可能获取到。 兄弟组件之间的通信状态晋升写过 React 的同学应该对组件的 状态晋升 概念并不陌生,React 外面将组件按照职责的不同划分为两类:展示型组件(Presentational Component) 和 容器型组件(Container Component)。 ...

September 28, 2022 · 3 min · jiezi

关于vue3:vue3部分知识梳理

1、script-setup 模式中父组件获取子组件的数据 咱们能够应用全局编译器宏的defineExpose宏,将子组件中须要裸露给父组件获取的参数,通过 {key: vlaue}形式作为参数即可,父组件通过模版 ref 形式获取子组件实例,就能获取到对应值: // 子组件<script setup> let name = ref("pingan8787") defineExpose({ name }); // 显式裸露的数据,父组件才能够获取</script>// 父组件<Chlid ref="child"></Chlid><script setup> let child = ref(null) child.value.name //获取子组件中 name 的值为 pingan8787</script>留神: 全局编译器宏只能在 script-setup 模式下应用;script-setup 模式下,应用宏时无需 import能够间接应用;script-setup 模式一共提供了 4 个宏,包含:defineProps、defineEmits、defineExpose、withDefaults。 2、配置全局自定义参数 在 Vue2.x 中咱们能够通过 Vue.prototype 增加全局属性 property。然而在 Vue3.x 中须要将 Vue.prototype 替换为 config.globalProperties 配置: // Vue2.xVue.prototype.$api = axios;Vue.prototype.$eventBus = eventBus;// Vue3.xconst app = createApp({})app.config.globalProperties.$api = axios;app.config.globalProperties.$eventBus = eventBus;应用时须要先通过 vue 提供的 getCurrentInstance办法获取实例对象: // A.vue<script setup lang="ts">import { ref, onMounted, getCurrentInstance } from "vue";onMounted(() => { const instance = <any>getCurrentInstance(); const { $api, $eventBus } = instance.appContext.config.globalProperties; // do something})</script>3、v-model 变动 ...

September 28, 2022 · 2 min · jiezi

关于vue3:2022全面升级Vue3-TS-仿知乎专栏企业级项目完结内置文档

download:2022全面降级Vue3 + TS 仿知乎专栏企业级我的项目完结内置文档Spring5源代码5-Bean生命周期后处理器 次要解释三种生命周期加强剂: bean factorypostprocessor:bean factory后处理器bean definitionregistrypostprocessor:bean定义注册后处理器插手容器的启动豆后处理器:豆后处理器bean后处理器MergedBeanDefinitionPostProcessorsmartinstantiationwarebeanpostprocessorinstantiationwarebeanpostprocessor回调接口DisposableBean(咱们临时不解释销毁计划)1.1什么是BeanPostProcessor?BeanPostProcessor是Spring提供的一个十分重要的扩大接口,Spring中的很多性能也是通过BeanPostProcessor实现的(目前看到的最典型的就是AnnotationAwareaspectJaoutProxyCreator的注入)。 1.2 bean post处理器的类型BeanPostProcessor在Spring中有很多子类(idea中有46个),比方 InstantiationAware后处理器适配器:在Spring的bean加载过程中起着十分重要的作用。AnnotationawareaspectjautoproxyCreator:当属性在bean创立期间被注入时,它起作用。aspectjawaareadvisorrotoproxycreator:Aspect的AOP性能也取决于BeanPostProcessor的个性。1.3发明机会BeanFactoryPostProcessor:在Spring开始时染指BeanDefinition的创立。 beanPostProcessor:首先,创立与Bean对应的Bean定义。第二个是Bean实例的创立。在Spring容器中,Bean的创立不仅仅是通过反射来实现的,在创立过程中还须要思考Spring容器中Bean的一些属性,所以BeanDefinition中不仅蕴含了Bean类文件的信息,还蕴含了Spring容器中以后Bean的一些属性,比方容器中的作用域、懒加载、别名等信息。当Bean被实例化时,它须要依赖相应的BeanDefinition来提供相应的信息。。 BeanPostProcessor参加了Bean的创立过程。所以必须在一般Bean之前创立。实际上,BeanPostProcessor是在Spring启动时刷新容器时创立的。 BeanPostProcessor的BeanDefinition创立计时和一般的Beans没有什么区别,都是在Spring启动时在BeanFactoryPostProcessor中实现的(精确的说是在ConfigurationClassPostProcessor中实现的)。 然而,BeanPostProcessor的实例创立优先于一般bean的创立,在Spring启动期间将调用abstractapplicationcontext # registerbeanpostprocessors办法。在这个办法中,Spring将从容器中获取BeanPostProcessor类型的所有beanName,通过beanFactory.getBean办法获取相应的实例,对它们进行排序,并在BeanFactory.beanPostProcessors属性中注册它们。当容器须要执行BeanPostProcessor办法时,能够间接从beanPostProcessors中获取。 2.案例定义几个测试类来实现bean的后处理器: bean definition registry post processor: /** BeanFactory的后处理器,优先级排序,已排序*/@组件公共类mybean definition registry postprocessor实现bean definition registry postprocessor {公共mybean definitionregistrypostprocessor(){system . out . println(" mybean definition registry postprocessor ");}@Override //立刻执行public void postprocessbean factory(configurablelistablebean factory)抛出BeansException {system . out . println(" mybean definition registry postprocessor....postProcessBeanFactory ... ");} @Override //首先执行public void postprocessbean definition registry(bean definition registry)抛出BeansException {system . out . println(" mybean definition registry postprocessor...postprocessbean definition registry ... ");//加强bean定义信息的注册,比方本人注册组件。 ...

September 23, 2022 · 2 min · jiezi

关于vue3:为了学习-Vue3我做了一个微信匿名朋友圈

缘起编程这种货色,必须要实践加实战,能力真正把技能学到。所以,笔者就想着通过一些实战利用来感受一下 Vue3 的设计哲学以及作者们的劳动结晶。那么,做点啥好呢?忽然想到当初大家都不怎么爱发微信朋友圈了,毕竟微信这样一个体量的超级 APP,里边都是你的亲戚,共事,老板啥的,有点牢骚话,也不好意思发呀。既然如此,那么就做一个匿名的朋友圈吧,这样,不想让熟人圈子看到的货色,不就有中央藏了吗哈哈哈(想想都有点小冲动了!) 撸码说干就干,笔者迅速的就初始化了工程,开始了搬砖之旅。开发该我的项目应用的操作系统是 MBP,技术栈是 Vue3 + Vue Router + Axios 这套罕用组合,UI 组件库抉择了 Vant,另外,应用了 dayjs 进行日期解决,也用了 lodash 库,便于间接应用一些工具函数。 登录既然是发朋友圈,那必定是须要登录态的,为了不想有繁冗的登录注册流程,笔者打算间接接入微信公众号的 JSSDK, 实现微信的受权登录。当然,这里边坑还是有点多,笔者已另写文章用以记录。感兴趣的人可空降至 Vue 微信开发中受权登录的优雅实现。笔者在本我的项目中,接入的是微信静默受权形式,这种受权登录形式用户简直无感知,但也无奈获取用户微信的昵称和头像,不过既然咱主打的是匿名,那不正好匹配了需要嘛(本人当产品的感觉真难受,需要说砍就砍了,哈哈哈哈) 获取不到用户的头像和昵称,在显示上,是不是会显的过于空洞了呢?是的,笔者思考到了。这个问题好说,间接在服务端生成一个昵称库,每来一个用户就随机调配一个不就能够啦!至于头像嘛,本想着也按昵称那样,弄一个头像库的。后果在一次因缘偶合下,笔者发现了这样一个我的项目: boringavatarsgithub 这个我的项目能够依据一串随机 hash 值来生成一个对应的头像图片,贼有意思,应用也非常简单,相似如下: import Avatar from "boring-avatars";<Avatar size={40} name="Maria Mitchell" variant="marble" colors={["#92A1C6", "#146A7C", "#F0AB3D", "#C271B4", "#C20D90"]}/>;我怅然的在我的项目中应用了它。 公布动静用户登录后,第一件事天然是公布动静了。发动静这个性能其实不简单,也就是填写表单后提交到服务端。界面我参考了一下微信发朋友圈的设计,而后减少了一个标签,大略如下: 这里波及到了文件上传,思考到服务器带宽无限,笔者应用了七牛云存储作为动态资源服务器,通过客户端直传的形式实现了图片上传。客户端直传祺事很简略,不论是七牛云还是其余云厂商的文件治理服务,都能够应用表单上传的形式(也就是 间接 post 申请传递 formdata 的形式)上传,下边是笔者应用 Axios 进行上传的示例: const formData = new FormData();formData.append("file", file); // file对象formData.append("token", token); //通过服务端获取的上传凭证formData.append("key", key); //资源名,能够自行设定规定生成const uploadUrl = "http://up-z2.qiniu.com";axios .request({ url: uploadUrl, method: "post", onUploadProgress(progressEvent) { // 上传进度 }, data: formData, timeout: 0, headers: { "Content-Type": "multipart/form-data" }, }) .then((res) => { // 上传后的文件信息 console.log(res.data); });图片上传其实波及的细节很多,包含上传体验优化啊,图片压缩啊,加水印啊,批量上传,断点续传,分片上传,拜访鉴权啊等等。因为工夫关系,笔者临时没去一一实现,下次笔者肯定独自具体分享下对于图片上传性能的各种细节。 ...

September 23, 2022 · 2 min · jiezi

关于vue3:vue3组合式开发构建之HTMLJS-和-VUE文件乱谈

三种类型文件在vue3组合式开发时有三种构建文件,后缀别离为.html、.js 和 .vue。搞不懂这些不同的文件干麻,全部都是.js 或全部都是.vue不好吗?懵懵懂懂照着教程这样写着,反正都是一阵import乱引,随着学习的深刻,缓缓思考着这些文件间的关系和这样做的原理。一点浅解,在此乱谈 .html<div id="app"></div><script type="module" src="/src/main.js"></script> //src导入法<script type="module"> import test from './src/main.js'</script> //import引入法html是万物之始!通过原始标签能够搁置 html、JS、CSS 。留神这里的type="module",开启了import引入标准。在标签内用src="main.js"与在代码行里用import引入的区别: 标签内引入,门路后面不必加“&nbsp . ”,引入即执行,/main.js文件不必export default导出代码行用import引入,要加“&nbsp . ”,/main.js文件要用export default导出.html文件能够搁置 html 标签,通过<script>能够搁置 JS 代码,通过<style>能够搁置CSS。.jsimport { createApp} from 'vue'import App from './App.vue'import router from './router.js'import 'bootstrap/dist/css/bootstrap.min.css'import 'bootstrap/dist/js/bootstrap.min.js'createApp(App).use(router).mount("#app") //router要在mount之前,否则<router-link>标签不失效//将下面归一行式的另类离开式写法,此写法能够通过app.的形式生成全局变量、组件等const app=createApp(App) app.use(router) app.mount("#app")//如.html文件是代码行import引入,此处要用export default导出export defaultappapp.use(router)app.mount("#app")js是万能之神!通过函数能够操作 html、JS、CSS 。留神默认导出必须用export default 要用import引入的文件,必须用export、export default导出才能够.js文件能够搁置 JS 代码,不能间接搁置html标签,只能通过js办法间接搁置 html 标签。.vue<script setup> </script ><template><Hello/></template><style scoped>.logo {height: 6em}</style> Vue是众神之子!可得心应手的操作 html、JS、CSS 处处便当。留神<script >标签内的setup和<style>标签内的scoped。 Vue 文件包函三局部:逻辑 (Script),模板 (template) 和款式 (style)Vue 文件默认导出(template)局部(不需用 export default 语句),不会默认导出(Script)与(style)局部(Script)局部可通过export default追加到默认里,import后通过lo.setup().count.value应用追加的变量。留神留神<script >标签内的setup的语法糖。没有语法糖,默认导出要用setup()办法,在办法里应用retun{}才行,代码如下: ...

September 21, 2022 · 1 min · jiezi

关于vue3:Vue-Admin-Better文档-Vue-Admin-Plus源码-Vue-Admin-Pro源码

简体中文 | English <div align="center"><img width="200" src="https://fastly.jsdelivr.net/gh/chuzhixin/image/logo/vab.png"/><h1> vue-admin-better</h1> <p>春已至,万物始,愿所有美妙纷沓而来!</p></div> 个性 40+高质量单页 RBAC 模型 + JWT 权限管制 10 万+ 我的项目理论利用 良好的类型定义 开源版本反对收费商用 跨平台 PC、手机端、平板️ 后端路由动静渲染 地址 vue2.x + element-ui(收费商用,反对 PC、平板、手机)⚡️ vue3.x + element-plus(alpha 版本,收费商用,反对 PC、平板、手机)⚡️ vue3.x + ant-design-vue(beta 版本,收费商用,反对 PC、平板、手机)⚡️ vue3.x + vite + arco admin pro 演示地址(vue2.x 付费版本,反对 PC、平板、手机) admin plus 演示地址(vue3.x 付费版本,反对 PC、平板、手机) pro 及 plus 购买地址 authorization Vue Shop Vite 商城(付费版本)行将公布,敬请期待! github 仓库地址 码云仓库地址<!-- ## 备份地址(反对 https 网站自动更新) ...

September 21, 2022 · 2 min · jiezi

关于vue3:vue3功能详解

HTML文本响应间接文本变量<span>Message: {{ msg }}</span>文本由双大括号内的变量(组件实例中 msg 属性)的值代替。同时每次 msg 属性更改时它也会同步更新。标签属性变量<span v-text="msg"></span>变量放在标签v-text属性里,会笼罩本标签内的文本和后辈标签的文本,要慎用。v-html 与 v-text 相似,v-html会编译 html 代码后输入文本HTML属性响应写法<div v-bind:id="msg"></div>v-bind:属性="msg",简写 :属性="msg"如果绑定的值是 null 或者 undefined,那么该属性将会从渲染的元素上移除。布尔型属性空字符串 (即 <button disabled="">) 时,该属性不会移除,而当其为其余非true时, 该属性会移除。动静绑定多个属性<div v-bind="object"></div>不带“ :属性 ”,赋值一个对象,对象能够包函多个属性。 const object = {id: 'container',class: 'wrapper'}编辑中,前面的内容是些速记的一些乱七八的,后继会欠缺,倡议不用看前面的内容。 被编译成组件 setup() 函数的内容。这意味着与一般的 <script> 只在组件被首次引入的时候执行一次不同,<script setup>中的代码会在每次组件实例被创立的时候执行申明的顶层的绑定 (包含变量,函数申明,以及 import 引入的内容) 都能在模板中间接应用import 导入的内容也会以同样的形式裸露。意味着能够在模板表达式中间接应用导入的 helper 函数,并不需要通过 methods 选项来裸露它<script setup>范畴里的值也能被间接作为自定义组件的标签名应用因为组件被援用为变量而不是作为字符串键来注册的,在 <script setup> 中要应用动静组件的时候,就应该应用动静的:is来绑定。<component :is="Foo" />。递归组件???命名空间组件????顶层 await????引入的组件命名须要首字母大写???!!一般<script>, 只会执行一次有些setup()之外的配置项在script setup中不实用,能够联合一般script一起应用。setup()在组件创立之前执行,是组合式 API 的入口setup中的生命周期,应用时须要导入其中 beforeCreate 和 created 间接写在setup中 申明响应式状态 import { reactive } from 'vue'const state = reactive({ count: 0 })function increment() { state.count++}<script setup> 中的顶层的导入和变量申明可在同一组件的模板中间接应用。你能够了解为模板中的表达式和 <script setup> 中的代码处在同一个作用域中。 ...

September 20, 2022 · 1 min · jiezi

关于vue3:2022全面升级Vue3-TS-仿知乎专栏企业级项目完结无密含资料

download:2022全面降级Vue3 + TS 仿知乎专栏企业级我的项目完结无密含材料一条SQL语句从头到尾1.一段SQL是怎么诞生的?SQL语句都诞生在客户端。生成一条SQL次要有两种形式,一种是开发人员自己手工编写,另一种是相干的ORM框架主动生成。一般MySQL运行过程中收到的SQL大多是ORM框架生成的,比如Java中的MyBatis和Hibernate框架。同时,SQL生成的时机一般与用户的请求无关。当用户在零碎中执行操作时,通常会生成一条SQL。例如,咱们在阅读器上输出以下URL: 此时会先请求掘金的服务器,而后掘金外部实现中的ORM框架会根据请求的参数生成一条SQL,类似于上面的伪SQL: select * from金爵_article其中userid = 862486453028888 这个SQL大抵意义是:根据用户请求的“作者ID”,查问掘金数据库文章表中该作者的所有文章信息。从下面的案例可能显著感觉到,在用户阅读器上看到的数据一般来自于数据库,而数据库执行的SQL来自于用户的操作。这两者是互补的,包含任何写操作(增加、删除、更改),本质上也会转换成SQL的片段。让我举一个简略的例子: 请求URL(请求URL)https://www.xxx.com/user/regi... 请求参数(请求参数){User_name:“竹子爱熊猫”,user _ pwd:“123456”,用户_性别:“男”,用户_电话:“18888888888”,......} 这里对用户明码的处理不够谨严,不做加密也不必在意~复制代码例如,在上述用户注册的情况下,当用户点击网页上的“注册”按钮时,将向目标网站的服务器发送post请求,而后将根据请求参数生成一条SQL,如下所示:insert into table_user(用户名,用户明码,用户性别,用户电话,....)价值观(“竹子爱熊猫”、“123456”、“男”、“188888888”,...);复制代码也就是说,一条SQL的诞生源于一个用户的请求。在开发程序时,SQL的一般逻辑会由业务层的代码决定,而具体的SQL语句会根据用户的请求参数和事先定制的“SQL骨架”做出。当然,在Java程序或者其余语言编写的程序中,只能生成SQL,SQL的真正执行需要数据库来实现。第二,SQL在执行之前将经历的一个过程通过上一步,一个完整的SQL就诞生了。为了让SQL失常执行,咱们将首先获得一个数据库连接对象。上一篇对于MySQL架构的文章,已经讲过MySQL的连接层有一个叫“连接池”的小工具的保护,不过相信大家都接触过这个货色,比如C3P0,德鲁伊,DBCP等等在Java里。 至此,咱们可能在这里思考一个问题。数据库保护自己的连接池,为什么咱们还需要在MySQL客户端保护一个数据库连接池?接下来咱们聊聊。 2.1、数据库连接池的必要性家喻户晓,当你要用Java创建数据库连接时,首先会读取配置文件中的连接地址、账号密码等信息,而后发动网络请求,根据配置的地址信息获取数据库连接对象。在这个过程中,因为涉及到网络请求,此时必然会经历TCP三次握手的过程。同时,在获得连接对象并实现SQL操作后,将开释数据库连接。这时分就需要经历TCP挥动四次的过程。 从下面的描述中可能清晰地感知到,Java中创建和敞开数据库连接的过程实际上耗费了大量的成本,而且程序上线后,还需要频繁的数据库操作。所以,如果每次操作数据库都获得一个新的连接对象,那么整个Java程序至多有四分之一的工夫要做TCP三次握手/四次wave的工作,对整个零碎的后果不堪设想。.... 正是因为以上原因,才出现了家喻户晓的“数据库连接池”。“数据库连接池”的思维和“线程池”是一样的,会把数据库连接到这个宝贵的资源上,用池技术来保护这个资源。也意味着当前需要进行数据库操作时,不需要自己建立连接,而是可能间接从“数据库连接池”中获取,用完之后放回连接池,达到重用的成果。 当然,连接池中保护的连接对象不会一直存在。当长时间不执行SQL操作时,连接池也会销毁这些连接对象,必要时再从新创建。然而什么时候创建,什么时候销毁,限度连接数等等,都是交给连接池来实现,不需要开发者自己关注。 好了~,回到后面抛出的问题,为什么需要用MySQL连接池在客户端保护一个连接池? 这个问题相信每个人心里都有一些答案。原因很简略。两者都使用池化技术来重用资源,俭约开销,提高性能,但针对的方向不同。 MySQL的连接池次要是为了重用线程,因为每一个数据库连接都会被MySQL中的一个线程保护,而每一次连接对象调配给一个客户端,都需要经历创建线程、调配堆栈空间这样沉重的工作...这个过程需要工夫,资源开销也不小,所以MySQL通过使用池化技术来解决这些问题。客户端的连接池次要是为了重用数据库连接,因为每一个SQL操作都需要经历TCP三次握手/四波的过程,同样耗时耗力,占用资源。所以也采纳了池化技术来解决这个问题。 其实也可能这样理解,MySQL连接池保护的是工作线程,而客户端连接池保护的是网络连接。 2.2.在执行SQL之前会发生什么回到本文的主题,当生成完整的SQL时,咱们将首先尝试在连接池中获取一个连接对象。接下来会发生什么? 在尝试从连接池中获取连接时,如果此时连接池中有空闲的连接,可能间接获取重用。但如果不是,你首先要判断以后池中的连接数是否达到了最大数量。如果连接数已满,以后线程需要等待其余线程开释连接对象。如果没有,您可能间接创建一个新的数据库连接来使用。 假设此时连接池中没有空闲的连接,需要再次创建新的连接,那么首先会发动一个网络请求来建立连接。 ①首先,将考据客户端的用户名和明码是否正确: 如果用户名不存在或明码谬误,将抛出错误代码1045和谬误消息。如果用户名和明码通过考据,请转到步骤②。 ②必定MySQL连接池中是否有空闲线程: 存在:间接从连接池中调配一个空闲线程来保护以后客户端的连接。否:创建一个新的工作线程(映射内核线程,调配堆栈空间...). worker线程会先查问MySQL自己的用户权限表,获取以后登录用户的权限信息,并进行授权。 至此,执行SQL前的筹备工作已经实现,执行SQL的通道已经打开。下一步是筹备执行SQL语句,工作线程将等待客户端传送SQL。三。SQL语句是如何在数据库中执行的?通过连接层的一系列工作,客户端会通过连接发送要执行的SQL语句,而后由MySQL服务层进行处理。然而根据用户的操作不同,MySQL执行SQL语句时会有一些区别,SQL语句指的是读操作和写操作。这两条SQL语句的执行过程是不同的。咱们先来看看select语句的执行过程。3.1.一个查问SQL的执行过程在分析查问SQL的执行过程之前,咱们先模拟一个案例进行后续分析: SQL语句Select id from ZZ _ user 其中user sex =男性,user_name =竹四号";-表格数据 +|用户标识|用户名|用户性别|用户电话|+| 1 |竹① |男| 1888888888 || 2 |竹② |男| 1358888888 || 3 |竹③ |男| 1568888888 || 4 |熊猫① |女| 1348888888 || 5 |熊猫② |女| 1858888888 || 6 |竹④ |男| 17777777 || 7 |熊猫③ |女| 166666666 |+

September 19, 2022 · 1 min · jiezi

关于vue3:VUE2升级成VUE3的优化与区别

大家好,我是小编阿贤。欢送各位大神关注《全栈技术圈》公众号,让技术更加简略易懂。 1. vue2和vue3实例区别1.1 创立一个vue2实例在vue2外面的Vue是一个构造函数,通过该构造函数创立一个Vue实例,data选项能够是对象,也能够是办法返回一个对象。能够通过el选项指定一个挂载的容器,也能够通过$mount()办法指定挂载的容器。 new Vue({ el: '#app', data: { name: 'Vue2', age: '6' }}).$mount('#app') 1.2 创立一个vue3实例在vue3外面Vue是一个对象,通过该对象的createApp()办法,创立一个Vue实例。vue3中,勾销了el选项。vue3中,无论是组件和是vue实例,data选项都必须是一个办法,由办法返回对象。 Vue.createApp({ //el: '#app', data() { return { name: 'Vue3', age: '2' } }}).mount('#app')2.Vue2和Vue3的响应式区别2.1 vue2的响应式在addSex办法中后增加的属性是非响应式的。在delName办法中间接应用delete形式删除对象的属性后,不具备响应式。在addFood办法中操作数组后同时要具备响应式。举荐应用$set办法依据下标增加数组元素,确保新增加的元素同样具备响应式。在delFood办法中间接依据下标删除数组元素,不具备响应式。 new Vue({ el:'#app', data:{ student:{ name:'张三', age:20 }, foods:['鱼翅','松茸','鱼子酱','帝王蟹','熊掌'] }, methods: { addSex(){ //增加性别 // this.student.sex='男' //能够通过$forceUpdate()强制页面更新一次 // this.$forceUpdate() //举荐应用$set办法给对象增加新的属性,确保新增加的属性同样具备响应式 this.$set(this.student,'sex','男') }, delName(){ //删除姓名 // 不具备响应式 // delete this.student.name //应用$delete办法,删除对象的属性后,持续具备响应式 this.$delete(this.student,'name') }, addFood(){ //增加食物 // 具备响应式,必须要应用上面的办法: // push pop unshift shift sort reverse splice // this.foods.push('佛跳墙') // this.foods[5] = '佛跳墙' // this.$forceUpdate() this.$set(this.foods,5,'佛跳墙') }, //删除食物 delFood(){ // this.foods.splice(3,1) //不具备响应式 // this.foods[3] = null //应用$delete办法,删除数组中指定地位的元素,持续具备响应式 this.$delete(this.foods,3) } }})2.2 vue3修复了vue2中响应式的所有缺点vue3后续新增属性值具备响应式,delete本人删除属性也具备响应式。 ...

September 17, 2022 · 2 min · jiezi

关于vue3:vue3个人心得概论

Vue 的两个外围性能申明式渲染:Vue 基于规范 HTML 拓展了一套模板语法,使得咱们能够申明式地形容最终输入的 HTML 和 JavaScript 状态之间的关系。(import)响应性:Vue 会主动跟踪 JavaScript 状态变动并在扭转产生时响应式地更新 DOM Vue 的一大劣势——渐进式框架Vue 活性和“能够被逐渐集成”这个特点。依据需要场景,能够用不同的形式应用 Vue: 无需构建步骤,渐进式加强动态的 HTML (这个能够了解)在任何页面中作为 Web Components 嵌入(这个能够了解)单页利用 (SPA)全栈 / 服务端渲染 (SSR)Jamstack / 动态站点生成 (SSG)开发桌面端、挪动端、WebGL,甚至是命令行终端中的界面Vue 的单文件组件单文件组件会将一个组件的逻辑 (JavaScript),模板 (HTML) 和款式 (CSS) 封装在同一个文件里(在任何页面中作为 Web Components 嵌入) <script setup>import { ref } from 'vue' defineProps({ msg: String}) const count = ref(0) </script> <template><p class="greeting">{{ count }}</p><p class="greeting">{{ msg }}</p></template><style scoped>.greeting { color: red; }</style> Vue 的组件格调选项式 API (Options API)用选项词(例如 data、methods 和 mounted)来形容和分类组件的逻辑。组合式 API (Composition API)用导入的 API 函数(例如 import { ref, onMounted } )来形容组件逻辑,雷同的逻辑可随便分布“选项式 API”与“组合式 API”只是写法格调的不同,作用是一样的组合式 API组合式 API是一系列 API 的汇合,使咱们能够应用函数而不是申明选项的形式书写 Vue 组件。它涵盖了以下方面的 API: ...

September 16, 2022 · 1 min · jiezi

关于vue3:Vue3-从入门到实战-进阶式掌握完整知识体系含源码ppt无mi分xiang

download:[Vue3 从入门到实战 进阶式把握残缺常识体系含源码ppt无mi分xiang自学it666 java python go c](https://www.zxit666.com/2093/)教你如何用Java获取IP归属。解释次要步骤: 从Java获取申请IP解决Nginx转发问题通过IP地址获取属性 获取IP地址首先,应用基于Spring Boot的我的项目,在控制器中增加HttpServletRequest申请参数:@RestController公共类IpController {@GetMapping("/ip-address ")公共字符串ipAddress(HttpServletRequest申请){//接管申请}}复制代码通过HttpServletRequest获取IP地址:string IP = request . get header(" x-forward-for ");if (ip == null || ip.length() == 0 ||“未知”。equalsIgnoreCase(ip)) {ip = request.getHeader("代理-客户端-IP ");}if (ip == null || ip.length() == 0 ||“未知”。equalsIgnoreCase(ip)) {IP = request . get header(" WL-代理-客户端-IP ");}if (ip == null || ip.length() == 0 ||“未知”。equalsIgnoreCase(ip)) {IP = request . get header(" HTTP CLIENT IP ");}if (ip == null || ip.length() == 0 ||“未知”。equalsIgnoreCase(ip)) {IP = request . get header(" HTTP X FORWARDED _ FOR ");}if (ip == null || ip.length() == 0 ||“未知”。equalsIgnoreCase(ip)) {IP = request . getremoteaddr();}回归IP;复制代码调用以获取本地环境中的IP,0:0:0:0:0:0:0:1或LAN IP。 ...

September 13, 2022 · 2 min · jiezi

关于vue3:Vue3拖拽式低代码数据可视化平台

简介OpenDataV 是一个纯前端的拖拽式、可视化、低代码数据可视化开发平台,你能够用它自在的拼接成各种✨炫酷的大屏,同时反对用户不便的开发本人的组件并接入平台。 体验国外:http://datav.byteportrait.com/ 国内:http://small_bud_star.gitee.io/datav 源码地址:github:https://github.com/AnsGoo/openDataV gitee:https://gitee.com/small_bud_star/DataV gitee 仅做代码同步,issues或者RP请在github提交。 目前该我的项目在一直的欠缺中,欢送issuer,欢送start, 欢送commit, 欢送use...,欢送所有技术交流活动 ️预览️ 布局页 编辑页 性能 编辑器页面基本功能实现,包含编辑、预览、导入、导出、保留 图层的置顶、置底、高低挪动、显示、暗藏、复制、剪切、粘贴️ 组件的缩放、旋转、拖动、复制、粘贴、组合、拆分、移除、主动对齐 反对用户操作记录的复原、撤销性能 反对用户自定义组件 反对组件的用户自定组件配置项 反对明暗主题切换 应用Monorepo模式进行组件和依赖治理技术点本我的项目采纳Vue3 + vite + TypeScript开发,界面库应用NaiveUI,应用面向对象形式封装了路由、申请、存储,组件采纳主动扫描注册、异步加载,晋升渲染速度;应用IndexDB存储快照数据,缩小快照数据内存占用,放慢访问速度;组件独立依赖,解耦了组件和根底框架的依赖库,不便后续独立开发组件。 目前仅开发了局部组件,后续还会持续欠缺。 ⌛打算性能[ ] 组件动静、静态数据加载[ ] 数据动静解决(JS、Python)[ ] 我的项目公布[ ] 接口治理[ ] 算法治理[ ] HTTP、 WebScoket、MQTT、SocketIO多种数据接口适配[ ] 代码生成开发开发环境名称版本node16.14.xpnpm7.9.3vue3.2.20目前仅在Chrome和Microsoft Edge最新版浏览器测试过,其余浏览器未测试 启动我的项目# 装置依赖pnpm install -r# 运行我的项目pnpm dev# 打包我的项目pnpm build☎️联系方式技术交换,请加群 更新动静请关注公众号

September 6, 2022 · 1 min · jiezi

关于vue3:Vue3-reactive-源码分析

概要本文通过抽取Vue3 reactive源码中的次要局部,来了解其响应式object的实现形式。本文源码基于这个入口文件:github reactive.ts reactive()源码地位:github reactive.ts export function reactive(target) { return createReactiveObject( target, false, mutableHandlers, mutableCollectionHandlers )}reactive外部调用了createReactiveObject函数,并传入mutableHandlers作为Proxy的handler createReactiveObject()源码地位:github reactive.ts function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers) { const proxy = new Proxy( target, targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers ) return proxy}可见reactive的实质,是将一般的object转换成了Proxy。而Proxy只反对非空的object,所以reactive函数也只能用于object。 const handler = {}new Proxy({}, handler) // 失常运行new Proxy(1, handler) // Cannot create proxy with a non-object as target or handler如果用于原始类型的响应式,应该应用Vue3提供的ref函数。 mutableHandlers源码地位:github baseHandlers.ts mutableHandlers和mutableCollectionHandlers用于new Proxy的第二个参数,是reactive函数最外围的逻辑,重点关注其get和set属性。 export const mutableHandlers = { get: createGetter(), set: createSetter(), deleteProperty, has, ownKeys,}createGetter()源码地位:github baseHandlers.ts ...

September 6, 2022 · 3 min · jiezi

关于vue3:网易云Vue3实战商城后台管理系统开发无mi

download:Vue3实战商城后盾管理系统开发开篇RT,咱们为什么要上 Vue3?应用 Vue3 影响我开法拉利吗?最近在 Vue3 公布了3.2 大版本之后,掘金上对于 Vue3 的文章越来越多,原本想着让子弹再飞一会,但最近公司上了 Vue3 的我的项目,本人也跟着学了起来。昨天还是 Vue2 的 Options API 的忠诚信徒,后果明天搞了 Vue3 的 Composition API 之后,直呼 Vue3 真香!接下来,咱们从剖析 Vue2 优缺点动手,以及联合图片和用例来理解 Vue3 的劣势。Vue2 ⚔ Vue3Vue2长处不可否认 Vue2 在获得的胜利,在 Github 的 Front-End 分类的排行榜上也能看到 Vue 仓库的排名是第一,粉丝足够多,沉闷用户足够多 比 React 足足多了 12k+ star从我的角度来看,最大的功臣莫过于这三个: 响应式数据Options APISFC 除去这三位大将,不可或缺 Vuex/Vue-Router 这两位功臣,以及丰盛的周边插件和沉闷的社区。毛病在一个组件仅承当繁多逻辑的时候,应用 Options API 来书写组件是很清晰的。然而在咱们理论的业务场景中,一个父组件总是要蕴含多个子组件,父组件须要给子组件传值、解决子组件事件、间接操作子组件以及解决各种各样的调接口的逻辑,这时候咱们的父组件的逻辑就会变得复杂。咱们从代码维护者的角度登程,假如这个时候有 10 个函数办法,天然咱们要把他们放入到methods中,而这个 10 个函数办法又别离操作 10 个数据,这个 10 个数据又别离须要进行Watch操作。这时候,咱们依据Vue2的Options API的写法,就写完了 10 个method、10 个data、10 个watch,咱们就将原本 10 个的函数办法,宰割在 30 个不同的中央。这时候父组件的代码,对代码维护者来说是很不敌对的。 ...

September 3, 2022 · 1 min · jiezi

关于vue3:网易云Vue3实战商城后台管理系统开发

网易云Vue3实战商城后盾管理系统开发Spring5源码5-Bean生命周期后置处理器 次要阐明三种生命周期增强器: BeanFactoryPostProcessor:BeanFactory 后置处理器 BeanDefinitionRegistryPostProcessor:bean定义注册后置处理器BeanFactoryPostProcessorBeanPostProcessor:Bean后置处理器 BeanPostProcessorMergedBeanDefinitionPostProcessorSmartInstantiationAwareBeanPostProcessorInstantiationAwareBeanPostProcessorInitializingBean DisposableBean (销毁的计划咱们临时不做阐明) 1.1 什么是 BeanPostProcessorBeanPostProcessor 是 Spring提供给咱们的一个十分重要的扩大接口,并且Spring外部的很多性能也是通过 BeanPostProcessor 来实现的(目前看到最典型的就是 AnnotationAwareAspectJAutoProxyCreator 的 注入)。 1.2 BeanPostProcessor 的品种BeanPostProcessor 在Spring 中的子类十分多(idea 显是有46个),比方 InstantiationAwareBeanPostProcessorAdapter : 在Spring 的bean加载过程中起了十分重要的作用AnnotationAwareAspectJAutoProxyCreator : bean 创立过程中的 属性注入时起作用AspectJAwareAdvisorAutoProxyCreator : Aspect 的 AOP 性能实现也全凭仗BeanPostProcessor 的个性。1.3 创立机会BeanFactoryPostProcessor:在 Spring 启动时对BeanDefinition 的创立 进行干涉解决。 BeanPostProcessor:一是Bean对应的BeanDefinition 的创立。二是Bean 实例的创立。因为在 Spring容器中,Bean的创立并非仅仅通过反射创立就完结了,在创立过程中,须要思考到Bean针对Spring容器中的一些属性,所以BeanDefinition 中不仅仅蕴含了 Bean Class 文件信息,还蕴含了 以后Bean在Spring容器中的一些属性,比方在容器中的作用域、是否懒加载、别名等信息。当Bean 进行实例化创立时须要依赖于对应的BeanDefinition 提供对应的信息。。 而因为 BeanPostProcessor 是参加了 Bean 创立过程。所以其创立肯定在一般 Bean 之前。实际上 BeanPostProcessor 的创立时在 Spring 启动时容器刷新的时候。 BeanPostProcessor 的 BeanDefinition 创立机会和一般 Bean没有区别,都是在Spring 启动时的BeanFactoryPostProcessor 中实现(确切的说是 ConfigurationClassPostProcessor 中实现)。 ...

September 3, 2022 · 15 min · jiezi

关于vue3:vue3-ts-echarts封装一个基础echarts组件

话不多说,间接上代码吧新增一个MyCharts.vue文件,文件内容如下<!--/*** Author: 前端小高* Desc: MyCharts 图表组件*/--><template> <div :id="chartId" :style="getChartStyle"></div></template><script name="MyCharts" lang="ts" setup>import { ref, shallowRef, computed, watch, onMounted, onBeforeUnmount, getCurrentInstance, PropType} from 'vue'import { debounce } from 'lodash'const { proxy } = getCurrentInstance() as anyconst props = defineProps({ options: { type: Object, default: () => { return {} } }, height: { type: Number, default: 300 }, // 是否不跟之前的传入值合并 notMerge: { type: Boolean, default: true }})const getChartStyle = computed(() => { return { width: '100%', height: `${props.height}px` }})watch( () => props.options, () => { initChart() }, { deep: true })// 默认显示的图表配置数据const defaultOptions = { tooltip: { trigger: 'axis' }, legend: { data: ['Email', 'Union Ads'] }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis: { type: 'category', boundaryGap: false, data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [ { name: 'Email', type: 'line', smooth: true, stack: 'Total', data: [120, 132, 101, 134, 90, 230, 210] }, { name: 'Union Ads', type: 'line', smooth: true, stack: 'Total', data: [220, 182, 191, 234, 290, 330, 310] } ]}const getRandomStr = () => { const randomNumStr = String(Math.random()).split('.')[1] return randomNumStr}const chartId = ref('chart-id')const getChartId = () => { const str = 'chart-id-' + getRandomStr() chartId.value = str}getChartId()const resizeHandler = () => { eChartsRef.value.resize()}const resizeHandlerOrigin = debounce(resizeHandler, 500)const eCharts = proxy.$EChartsconst eChartsRef = shallowRef<any>()const initChart = () => { eChartsRef.value = eCharts.init(document.getElementById(chartId.value)) let options = {} if (isEmptyObj(props.options)) { options = defaultOptions } else { options = props.options } eChartsRef.value.setOption(options, props.notMerge) window.addEventListener('resize', resizeHandlerOrigin)}const isEmptyObj = (obj) => { return typeof obj === 'object' && JSON.stringify(obj) === '{}'}onMounted(() => { initChart()})onBeforeUnmount(() => { window.removeEventListener('resize', resizeHandlerOrigin) eChartsRef.value.dispose()})watch( () => props.options, () => { initChart() }, { deep: true })</script><style lang="scss" scoped></style>页面下援用组件及应用办法<template> <my-charts></my-charts></template><script name="TestPage" lang="ts" setup> import MyCharts from './MyCharts.vue'</script>预览成果如下 ...

September 1, 2022 · 2 min · jiezi

关于vue3:vue3源码九ref源码解析

【vue3源码】九、ref源码解析参考代码版本:vue 3.2.37 官网文档:https://vuejs.org/ ref承受一个外部值,返回一个响应式的、可更改的ref对象,此对象只有一个指向其外部值的property.value应用const count = ref(0)console.log(count.value) // 0count.value++console.log(count.value) // 1源码解析export function ref(value?: unknown) { return createRef(value, false)}ref返回createRef函数的返回值。 createRef接管两个参数:rawValue待转换的值、shallow浅层响应式。 function createRef(rawValue: unknown, shallow: boolean) { if (isRef(rawValue)) { return rawValue } return new RefImpl(rawValue, shallow)}如果rawValue本就是ref类型的会立刻返回rawValue,否则返回一个RefImpl实例。 RefImplclass RefImpl<T> { private _value: T private _rawValue: T // 以后ref的依赖 public dep?: Dep = undefined public readonly __v_isRef = true constructor(value: T, public readonly __v_isShallow: boolean) { this._rawValue = __v_isShallow ? value : toRaw(value) this._value = __v_isShallow ? value : toReactive(value) } get value() { trackRefValue(this) return this._value } set value(newVal) { newVal = this.__v_isShallow ? newVal : toRaw(newVal) if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal this._value = this.__v_isShallow ? newVal : toReactive(newVal) triggerRefValue(this, newVal) } }}RefImpl的结构器接管两个值:value、__v_isShallow是否浅层响应式。 ...

August 31, 2022 · 2 min · jiezi

关于vue3:elselect-的focus事件和ElMessageBox搭配出现的focus死循环问题的解决方法

问题因为业务须要,所以呈现了不停弹出ElMessageBox的这种状况,代码如下: <template> <el-select v-model="form.type" @focus="onFocus"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select></template><script>import ...export default defineComponent({ setup() { const form = ref({}) const options = ref([]) const onFocus = () => { if (!form.value.cate) { ElMessageBox.alert('请先抉择分类', '提醒', { confirmButtonText: '好的', }) } } return { form, options, onFocus, } }})</script>解决办法:起初想到应该是ElMessageBox组件让el-select不停地处在focus的状态上,所以才会不停地触发focus事件,陷入对话框死循环。所以我就在触发focus事件的结尾,增加让el-select失去焦点的办法,刚好官网文档里,el-select就有一个blur()办法。这个时候须要用到ref了,而在vue3的setup里调用$refs的形式,我先是用了 getCurrentInstance,然而不晓得为何返回的是null,所以最终用上面的办法解决了反复弹出的问题。 <template> <el-select v-model="form.type" @focus="onFocus" ref="selectRef"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select></template><script>import ...export default defineComponent({ setup() { const form = ref({}) const options = ref([]) const selectRef = ref(null) const onFocus = () => { if (!form.value.cate) { ElMessageBox.alert('请先抉择分类', '提醒', { confirmButtonText: '好的', callback: action => { //被动失去焦点的的办法加在这里是有效的。 } }) selectRef.value.blur() //就是这一句, } } return { form, options, onFocus, selectRef, } }})</script>

August 27, 2022 · 1 min · jiezi

关于vue3:解析Vue3patch核心算法patchKeyedChildren

解析Vue3patch外围算法patchKeyedChildrenlocate:runtime-core > renderer > baseCreateRenderer > patchKeyedChildrenpatchKeyedChildren是patch算法中较为简单的一段,更是vue技术栈面试的高频点,最后我是在vue3.0 beta版本时大抵看了源码,起初在《vue设计与剖析》中看了霍春阳大佬的解析,本篇就简要剖析一下做个记录首先patchKeyedChildren是在子列表比照并且有key的状况会进入,并且逻辑大抵分为5步,这个看源码官网正文就能够看出第一步,从前向后遍历这一步是从节点组头部向尾部遍历,如果遍历过程中遇到类似节点,就进行patch比照,否则就退出遍历,并记录以后遍历的最新下标 while (i <= e1 && i <= e2) { const n1 = c1[i] const n2 = (c2[i] = optimized ? cloneIfMounted(c2[i] as VNode) : normalizeVNode(c2[i])) if (isSameVNodeType(n1, n2)) { patch( n1, n2, container, null, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } else { break } i++}第二步,从后向前遍历从后向前遍历,如果遇到第一步记录的下标就进行,而后遍历过程中,如果遇到类似节点也是间接进行patch比照,如果不雷同就是间接退出遍历,并且记录旧节点组和新节点组的尾指针 while (i <= e1 && i <= e2) { const n1 = c1[e1] const n2 = (c2[e2] = optimized ? cloneIfMounted(c2[e2] as VNode) : normalizeVNode(c2[e2])) if (isSameVNodeType(n1, n2)) { patch( n1, n2, container, null, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } else { break } e1-- e2--}第三步,查看旧节点组这一步就是查看旧节点组在上两步的遍历后是否遍历完,如果遍历完,那么新节点组没有遍历完的就都是新的dom,能够全副当作新增节点进行挂载解决 ...

August 25, 2022 · 2 min · jiezi

关于vue3:vue3-分页如何渲染属性-ariacurrentpage

分页模块的时候,过后以后页面,如果是当前页,须要加一个属性 aria-current="page":vue3代码:aria-current="{'page':page === n}" 后果没有渲染进去,IDE也标黄。 代码<template> <nav aria-label="..."> <ul class="pagination"> <li class="page-item" :class="{'disabled':page === 1}"> <span class="page-link">Previous</span> </li> <li v-for="n in total_page" class="page-item" :class="{'active': page === n }" :aria-current="page === n ?'page':false"> <a v-if="page === n" class="page-link" href="#" @click="submit(n)">{{ n }}</a> <span v-else class="page-link" @click="submit(n)">{{ n }}</span> </li> <li class="page-item" :class="{'disabled': page === total_page}"> <a class="page-link" href="#" @click="submit(total_page)">Next</a> </li> </ul> </nav></template>模板<nav aria-label="..."> <ul class="pagination"> <li class="page-item disabled"> <a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a> </li> <li class="page-item"><a class="page-link" href="#">1</a></li> <li class="page-item active" aria-current="page"> <a class="page-link" href="#">2</a> </li> <li class="page-item"><a class="page-link" href="#">3</a></li> <li class="page-item"> <a class="page-link" href="#">Next</a> </li> </ul></nav>

August 19, 2022 · 1 min · jiezi