元素拖拽onmouseup失效
这种情况可能是接收元素禁止拖拽元素的放置,此时给放置元素添加event.preventDefault(); 语句就可以处理响应问题
const atrrMouseMove = (listenId: string, movId: string) => {
if (!barCodeId.includes("#")) {
movId = "#" + movId;
}
if (!listenId.includes("#")) {
listenId = "#" + listenId;
}
let tag = document.querySelector(movId) as HTMLElement;
let listenEle = document.querySelector(listenId) as HTMLElement;
let page = document.querySelector("#page") as HTMLElement;
let tag_x = tag.offsetLeft;
let tag_y = tag.offsetTop;
listenEle.onmousedown = (event: any) => {
let ev = (event as MouseEvent) || (window.event as MouseEvent);
let mouse_x = ev.clientX;
let mouse_y = ev.clientY;
let betweenX = mouse_x - tag_x;
let betweenY = mouse_y - tag_y;
console.log("按下鼠标", event);
document.onmousemove = (event) => {
event.preventDefault();
let ev = (event as MouseEvent) || (window.event as MouseEvent);
mouse_x = ev.clientX;
mouse_y = ev.clientY;
tag_x = tag.offsetLeft;
tag_y = tag.offsetTop;
let left = mouse_x - betweenX;
let top = mouse_y - betweenY;
let wrapW = page.clientWidth;
let wrapH = page.clientHeight;
if (wrapW - left < tag.clientWidth) {
left = wrapW - tag.clientWidth;
} else if (left < 0) {
left = 0;
}
if (wrapH - top < tag.clientHeight) {
top = wrapH - tag.clientHeight;
} else if (top < 0) {
top = 0;
}
tag.style.top = top + "px";
tag.style.left = left + "px";
console.log("移动", event);
};
};
document.onmouseup = function () {
console.log("document -> 鼠标抬起解除监听");
document.onmousemove = null;
document.onmouseup = null;
};
};
设置npm命令链接到淘宝镜像(npm缓存)
npm config get registry 获取当前npm的地址
npm config set registry http://registry.npm.taobao.org/
npm cache clear --force 清除npm缓存
<embed>标签实现pdf预览
<embed
v-if="dataSource !== ''"
:src="dataSource"
frameborder="0"
class="pdfRender"
type="application/pdf"
:style="{
height: height + 70 + 'px',
maxHeight: '70vh'
}"
/>
<div
v-if="dataSource === ''"
:style="{
height: height + 70 + 'px'
}"
class="pdfEmpty"
>
加载中, 请稍后...
</div>
// 点击打印预览按钮逻辑
function printPreview() {
if(rectsList.value.length <= 0) {
proxy.$ElMessage.warning('没有预览内容');
return;
}
printDialog.value.dataSource = '';
state.visible = true;
printDialog.value.dialogVisible = true;
printDialog.value.width = canvas.configForm.width;
printDialog.value.height = canvas.configForm.height;
// 通过接口获取预览数据
previewLabel({ config: canvas.configForm, rects: canvas.rects })
.then((res: any) => {
printDialog.value.dataSource = window.URL.createObjectURL(res.data);
})
}
/**
* 打印预览接口
* @param data
*/
export function previewLabel(data?:any): AxiosPromise {
return request({
url: '/xxx/xxxx/xxxx',
method: 'post',
data: data,
responseType: 'blob' // 类型必须处理成流
});
}
去掉ElementPlus table组件表头复选框
<el-table
:border="true"
:data="tableData"
style="width: 100%"
height="100%"
ref="tableRef"
:header-cell-class-name="cellClass"
>
// 为表头复选框添加一个特殊的类
function cellClass(row: any) {
if (row.columnIndex === 0) {
return 'disabledCheck'
}
}
/* 去掉表头全选按钮 */
:deep(.el-table) {
.disabledCheck .cell .el-checkbox__inner{
display: none !important;
}
.disabledCheck .cell::before{
content: 'Choose'; // 用Choose代替表头复选框
text-align: center;
}
}
在ElementPlus table组件表头中画斜线
参考文章: https://blog.csdn.net/qq_42068550/article/details/112799837
.formTo {
height:24px;
width: 100%;
position: relative;
background: #DAE6F4 url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiPjxsaW5lIHgxPSIwIiB5MT0iMCIgeDI9IjEwMCUiIHkyPSIxMDAlIiBzdHJva2U9IiNDM0NFREIiIHN0cm9rZS13aWR0aD0iMSIvPjwvc3ZnPg==) no-repeat 100% center;
min-width: 70px;
}
在线加密地址
关闭浏览器的复制功能
(document.onselectstart as any) = new Function('event.returnValue=false');
通过样式来控制选中
// 禁止选中
-moz-user-select: none; /*火狐*/
-webkit-user-select: none; /*webkit浏览器*/
-ms-user-select: none; /*IE10*/
-khtml-user-select: none; /*早期浏览器*/
-o-user-select:none;
user-select: none;
Vite.config.ts配置
import { defineConfig,UserConfig, ConfigEnv, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import path from "path";
export default ({ mode }: ConfigEnv): UserConfig =>{
// 获取.env环境配置
// 根据当前工作目录中的 `mode` 加载 .env 文件
// process.cwd()返回运行脚本当前工作目录
const env = loadEnv(mode, process.cwd());
return {
// 开发或生产环境服务的公共基础路径。合法的值包括以下几种:
// 绝对 URL 路径名,例如 /foo/
// 完整的 URL,例如 https://foo.com/
// 空字符串或 ./(用于嵌入形式的开发)
base: "/my-base/",
// 需要用到的插件数组
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]'
})
],
// 服务器选项
server: {
host: '0.0.0.0', // 监听所有地址,包括局域网和公网地址。
port: Number(env.VITE_APP_PORT), // 指定开发服务器端口
open: true, // 运行自动打开浏览器
// 为开发服务器配置自定义代理规则
// 任何请求路径以 key 值开头的请求将被代理到对应的目标。如果 key 值以 ^ 开头,将被识别为 RegExp。
proxy: {
'/api': {
// API地址
target: 'http://10.222.333.66:8080',
changeOrigin: true, // 表示修改 Host 头部的 Origin(原始值)
rewrite: path =>
path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
},
'/my-base-api': {
// API地址
target: 'http://xxx.xxx.com.cn',
changeOrigin: true,
rewrite: path =>
path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
}
}
},
resolve: {
// Vite路径别名配置
alias: {
'@': path.resolve('./src')
}
}
}
};
Label标签上浮
<div class="search-item float-Label-input">
<label :class="{'float-Label': factory.value && factory.value != ''}">标签名称</label>
<el-select
filterable
v-model="factory.value"
class="search-content"
@change="selectChange('FactoryName')"
:title="factory.value"
placeholder=" "
>
<el-option
v-for="item in factory.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
.float-Label-input{
position: relative;
label {
color: #333;
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 11px;
z-index: 1;
pointer-events: none;
transition-property: all;
}
.float-Label {
background: white;
top: -4px;
font-size: 12px; //字体大小最小设置为12px
-webkit-transform-origin-x: 0; //缩放基于的位置
-webkit-transform: scale(0.8); //字体缩放
transform: scale(0.8);
transition-property: all;
}
}
// :has()表示满足一定条件后,就会匹配该元素。
:has(>.el-select>.select-trigger> .is-focus) label {
background: white;
top: -4px;
font-size: 12px;
-webkit-transform-origin-x: 0; //字体大小最小设置为12px
-webkit-transform: scale(0.8); //字体缩放
transform: scale(0.8);
transition-property: all;
}
Vue3编程式路由导航中的path不能与params同时使用
注意:如果提供了 path,params 会被忽略。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path :
const username = 'eduardo'
// 我们可以手动建立 url,但我们必须自己处理编码
router.push(`/user/${username}`) // -> /user/eduardo
// 同样
router.push({ path: `/user/${username}` }) // -> /user/eduardo
// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: 'user', params: { username } }) // -> /user/eduardo
// `params` 不能与 `path` 一起使用
router.push({ path: '/user', params: { username } }) // -> /user
Vue3的router-view 设置名字(同时 (同级) 展示多个视图)
例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s)
<router-view class="view left-sidebar" name="LeftSidebar"></router-view>
<router-view class="view main-content"></router-view>
<router-view class="view right-sidebar" name="RightSidebar"></router-view>
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
components: {
default: Home,
// LeftSidebar: LeftSidebar 的缩写
LeftSidebar,
// 它们与 `<router-view>` 上的 `name` 属性匹配
RightSidebar,
},
},
],
})
Vue3路由给组件传递参数(props)
路由向组件传参时可以解决这种行为(与路由的紧密耦合)
我们可以将下面的代码
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const routes = [{ path: '/user/:id', component: User }]
修改为
const User = {
// 请确保添加一个与路由参数完全相同的 prop 名
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const routes = [{ path: '/user/:id', component: User, props: true }]
- 当 props 设置为 true 时,route.params 将被设置为组件的 props。
- 对于命名视图,须为每个命名视图定义 props 配置
const routes = [
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
- 当 props 是一个对象时,它将原样设置为组件 props。当 props 是静态(即不变)的时候很有用。
const routes = [
{
path: '/promotion/from-newsletter',
component: Promotion,
props: { newsletterPopup: false }
}
]
- 创建一个返回 props 的函数。这允许你将参数转换为其他类型,将静态值与基于路由的值相结合等等。
const routes = [
{
path: '/search',
component: SearchUser,
props: route => ({ query: route.query.q })
}
]
URL /search?q=vue 将传递 {query: 'vue'} 作为 props 传给 SearchUser 组件
Vue3路由附加信息(meta路由元信息)
有关路由的相关信息可以存储在路由测meta中
export const constantRoutes: Array<any> = [
{
path: '/',
redirect: '/system',
meta: { hidden: true }
}
]
可以这样获取
// 方式1
router.beforeEach((to, from) => {
// 而不是去检查每条路由记录
// to.matched.some(record => record.meta.requiresAuth)
if (to.meta.requiresAuth && !auth.isLoggedIn()) {
// 此路由需要授权,请检查是否已登录
// 如果没有,则重定向到登录页面
return {
path: '/login',
// 保存我们所在的位置,以便以后再来
query: { redirect: to.fullPath },
}
}
})
// 方式2
import { useRoute } from 'vue-router';
const route = useRoute();
const { meta, path } = route;
Vue3路由的懒加载(更改导入方式)
可以用动态导入代替静态导入,这使得当路由被访问的时候才加载对应组件,这样就会更加高效。
// 将 import UserDetails from './views/UserDetails.vue'
// 替换成 const UserDetails = () => import('./views/UserDetails.vue')
{
path: '/login',
component: () => import('@/views/login/index.vue'),
meta: { hidden: true }
},