在vscode编辑器需要安装EditorConfig for VS Code插件
# https://editorconfig.org
# 代码风格设置
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格 tabs | space
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
insert_final_newline = true # 去除行首的任意空白字符
trim_trailing_whitespace = true # 始终在文件末尾插入一个新行
[*.md] # 表示仅md文件适用以下规则
insert_final_newline = false
trim_trailing_whitespace = false
yarn add prettier -D
{
"useTabs":false, # 适用tab缩进还是空格缩进
"tabWidth":2, # tab是空格的情况下,是几个空格,选择2个
"printWidth":80, # 当行字符长度,推荐80
"singleQuote":true, # 使用单引号还是双引号,true是单引号
"trailingComma":"none", # 在多行输入的尾逗号是否添加,设置为none
"semi":false # 语句末尾是否要教分号,默认为ture添加分号
}
/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*
.eslintrc.js文件中extend属性加入"plugin:prettier/recommended"
"plugin:prettier/recommended"
npx husky-init && npm install
// 如果报错标记“&&”不是此版本中的有效语句分隔符,原因是执行命令时使用的PowerShell版本低了
// 可以尝试这行命令
npx husky-init '&&' npm install
或者用其他办法
yarn add husky -D
npx husky-init
在.husky下的pre-commit文件修改配置
npm run lint
参考:https://cli.vuejs.org/zh/config/
const Version = new Date().getTime()
module.exports = {
// 这是因为项目打包后,index会白屏,所以把路径改了
publicPath: './',
assetsDir: "static",
css: {
loaderOptions: {
less: {
javascriptEnabled: true
},
postcss: {
plugins: [
require('postcss-pxtorem')({
rootValue: 75,
propList: ['*'],
selectorBlackList: ['el-','y-'], // 跳过类名开头转换
exclue: ['node_modules'], // 跳过文件夹转换
unitPrecision: 2
})
]
}
}
},
devServer: {
open: true,
hot: true,
compress: true,
disableHostCheck: true,
port: 8080,
proxy: {
'/admin': {
target: process.env.VUE_APP_BASEURL,
changeOrigin: true,
cookieDomainRewrite: 'localhost',
secure: false,
ws: true
}
}
},
// lintOnSave: false, // 取消elsin校验
outputDir: 'admin-ui',
configureWebpack: {
output: {
// 输出重构 打包编译后的 文件名称 【模块名称.版本号.时间戳】
filename: `js/[name].${Version}.js`,
chunkFilename: `js/[name].${Version}.js`
}
}
/*
chainWebpack: config => {
config.plugin('provide').use(webpack.ProvidePlugin, [
{
'window.Quill': 'quill/dist/quill.js',
Quill: 'quill/dist/quill.js',
},
]);
config.when(process.env.NODE_ENV === 'production', config => {
config.optimization.minimizer('terser').tap(args => {
// 注释console.*
args[0].terserOptions.compress.drop_console = true;
// remove debugger
args[0].terserOptions.compress.drop_debugger = true;
// 移除 console.log
args[0].terserOptions.compress.pure_funcs = ['console.log'];
// 去掉注释 如果需要看chunk-vendors公共部分插件,可以注释掉就可以看到注释了
args[0].terserOptions.output = {
comments: false,
};
return args;
});
});
config.resolve.alias.set('components', resolve('src/components')).set('assets', resolve('src/assets')).set('@/', resolve('src')).end();
},
*/
}
安装
yarn add element-plus
// 在main.ts中
import elementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(elementPlus)
// 添加插件
yarn add unplugin-vue-components
// 在vue.config.js
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = {
// ...
configureWebpack: {
plugins: [
Components({
resolvers: [ElementPlusResolver()]
})
]
}
}
yarn add ant-design-vue@next
yarn add babel-plugin-import
yarn add antd-iconfont
/**在babel.config.js添加*/
plugins: [
[
'import',
{ libraryName: 'ant-design-vue', libraryDirectory: 'es', style: 'css' } // 注意如果没有less-loader得自己装一下
]
]
/**某个js文件*/
// 组件
import {
Button
} from 'ant-design-vue'
const components = [
Button
]
// 图标
import {
UserOutlined
} from '@ant-design/icons-vue'
const icons = {
UserOutlined
}
export function setupAnt (app) {
components.forEach(item => {
app.use(item)
})
for (const key in icons) {
app.component(key, icons[key])
}
}
/**在main引入某个js文件并调用*/
import { setupAnt } from './utils/antDesign'
const app = createApp(App)
setupAnt(app)
/**针对web网页,没有对移动端进行适配*/
yarn add postcss-pxtorem@5.1.1
/**vue.config.js添加*/
module.exports = {
css: {
loaderOptions: {
less: {
javascriptEnabled: true
},
postcss: {
plugins: [
require('postcss-pxtorem')({
rootValue: 75,
propList: ['*'],
exclue: ['node_modules'],
unitPrecision: 2
})
]
}
}
},
...
}
/**某个js文件定义函数*/
export const fun = function (doc: Document, win: Window) {
const docEl = doc.documentElement
const resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'
const recalc = function () {
const clientWidth = docEl.clientWidth
if (!clientWidth) return
// 这里是假设在1920px宽度设计稿的情况下,1rem = 20px
// 可以根据实际需要修改
docEl.style.fontSize = 100 * (clientWidth / 1920) + 'px'
// docEl.style.fontSize = 100 * (clientWidth / 1440) + 'px'
}
if (!doc.addEventListener) return
win.addEventListener(resizeEvt, recalc, false)
doc.addEventListener('DOMContentLoaded', recalc, false)
}
/**main.js调用*/
import { fun } from '@/utils/public'
const app = createApp(App)
fun(document, window)
/**TS*/
import { JSEncrypt } from 'jsencrypt'
// rsa加密
export const rsaEncryption = function (data: any) {
const Je = new JSEncrypt({ default_key_size: '1024' })
Je.setPublicKey('密钥')
if (data instanceof Object) {
data = JSON.stringify(data)
}
return Je.encrypt(data)
}
// rsa解密
export const rsaDecrypt = function (data: string) {
const Je = new JSEncrypt({ default_key_size: '1024' })
Je.setPublicKey('密钥')
return Je.decrypt(data)
}
/**JS*/
import jsencrypt from 'jsencrypt';
function rsaUtil(data) {
let Je = new jsencrypt({
default_key_size: 1024
})
Je.setPublicKey('密钥')
if (data instanceof Object) {
data = JSON.stringify(data);
}
return Je.encrypt(data);
}
export default rsaUtil;
/**canvas.js*/
export default class Ball {
constructor(x, y, r,ctx) {
this.x = x;
this.y = y;
this.r = r;
this.ctx = ctx;
this.color = this.getRandomColor();
this.dx = parseInt(Math.random() * 10) - 5;
this.dy = parseInt(Math.random() * 10) - 5;
}
render(){
this.ctx.beginPath();
this.ctx.fillStyle = this.color;
this.ctx.arc(this.x,this.y,this.r,0,2*Math.PI,false);
this.ctx.fill();
}
getRandomColor() {
const colorStr = '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f';
const colorArr = colorStr.split(',');
const length = colorArr.length;
let color = "#";
for (let i = 0; i < 6; i++) {
const random = parseInt(Math.random() * length);
color += colorArr[random];
}
// console.log(color);
return color;
}
update(arr){
this.x -= this.dx;
this.y -= this.dy;
this.r -= 0.4;
if(this.r<=0){
for(let i = 0;i<arr.length;i++){
if(arr[i]===this){
arr.splice(i,1);
}
}
}
}
}
/**waterMark.js*/
export default function __canvasWM({
// 使用 ES6 的函数默认值方式设置参数的默认取值
container = document.body,
width = '100vw',
height = '120%',
textAlign = 'center',
textBaseline = 'middle',
font = "800 15px Microsoft Yahei",
fillStyle = 'rgba(184, 184, 184, 0.5)',
content = '请勿外传',
rotate = '60',
zIndex = 1000
} = {}) {
const args = arguments[0];
console.log(args);
const canvas = document.createElement('canvas');
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
const ctx = canvas.getContext("2d");
ctx.textAlign = textAlign;
// ctx.textBaseline = textBaseline;
ctx.font = font;
ctx.fillStyle = fillStyle;
ctx.rotate(Math.PI / 360 * rotate);
ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 15,80);
const base64Url = canvas.toDataURL();
const __wm = document.querySelector('.__wm');
const watermarkDiv = __wm || document.createElement("div");
const styleStr = `
position:absolute;
top:1rem;
left:200px;
width:calc(100% - 200px);
height:calc(100% - 1rem);
z-index:${zIndex};
pointer-events:none;
background-image:url('${base64Url}')`;
watermarkDiv.setAttribute('style', styleStr);
watermarkDiv.classList.add('__wm');
if (!__wm) {
container.style.position = 'relative';
container.insertBefore(watermarkDiv, container.firstChild);
}
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
if (MutationObserver) {
let mo = new MutationObserver(function () {
const __wm = document.querySelector('.__wm');
// 只在__wm元素变动才重新调用 __canvasWM
if ((__wm && __wm.getAttribute('style') !== styleStr) || !__wm) {
// 避免一直触发
mo.disconnect();
mo = null;
__canvasWM(JSON.parse(JSON.stringify(args)));
}
});
mo.observe(container, {
attributes: true,
subtree: true,
childList: true
})
}
}
/**main.js自调用*/
if (typeof module != 'undefined' && module.exports) { //CMD
module.exports = __canvasWM;
} else if (typeof define == 'function' && define.amd) { // AMD
define(function () {
return __canvasWM;
});
} else {
window.__canvasWM = __canvasWM;
}
yarn add vuex-persistedstate
// 引入
import createPersistedState from "vuex-persistedstate"
export default new Vuex.Store({
plugins: [createPersistedState({
storage: window.sessionStorage,
reducer(val) {
const {
value
}
}
})],
state,
mutations,
actions,
getters,
modules: {}
})
/**在无需编译的文件中定义接口变量,一般在public下建一个public.js*/
BASE_URL = 'api'
/**在接口文件使用*/
const baseUrl = process.env.NODE_ENV === 'development'?'api':window.BASE_URL
export default class {
constructor(option: any) {
const that: any = this;
that.standards = {
strict: 'strict',
loose: 'loose',
html5: 'html5'
};
that.selectArray = []; // 存储select的
that.counter = 0;
that.settings = {
standard: that.standards.html5,
extraHead: '', // 附加在head标签上的额外元素,使用逗号分隔
extraCss: '', // 额外的css逗号分隔
popTitle: '', // 标题
endCallback: null, // 成功打开后的回调函数
ids: '' // 局部打印的id
};
Object.assign(that.settings, option);
that.init();
}
init() {
const that: any = this;
that.counter++;
that.settings.id = `printArea_${that.counter}`;
const PrintAreaWindow = that.getPrintWindow(); // 创建iframe
that.write(PrintAreaWindow.doc); // 写入内容
that.print(PrintAreaWindow);
that.settings.endCallback();
}
print(PAWindow: any) {
const that: any = this;
const paWindow = PAWindow.win;
const _loaded = () => {
paWindow.focus();
paWindow.print();
try {
const box: any = document.getElementById(that.settings.id);
const canvasList: any = that.elsdom.querySelectorAll('.canvasImg')
console.log(that.elsdom)
for (let i = 0; i < canvasList.length; i++) {
const _parent = canvasList[i].parentNode
_parent.removeChild(canvasList[i])
}
box.parentNode.removeChild(box);
} catch (e) {
console.log(e);
}
};
if (window.ActiveXObject) {
paWindow.onload = _loaded();
return false;
}
paWindow.onload = () => {
_loaded();
};
}
write(PADocument: any, $ele: any) {
const that: any = this;
PADocument.open();
PADocument.write(`${that.docType()}${that.getHead()}${that.getBody()}`);
PADocument.close();
}
docType() {
const that: any = this;
if (that.settings.standard === that.standards.html5) {
return '';
}
const transitional = that.settings.standard === that.standards.loose ? ' Transitional' : '';
const dtd = that.settings.standard === that.standards.loose ? 'loose' : 'strict';
return `${transitional}//EN" "http://www.w3.org/TR/html4/${dtd}.dtd">`;
}
getHead() {
const that: any = this;
let extraHead = '';
let links = '';
let style = '';
if (that.settings.extraHead) {
that.settings.extraHead.replace(/([^,]+)/g, (m: any) => {
extraHead += m;
});
}
// 复制所有link标签
[].forEach.call(document.querySelectorAll('link'), function (item: any) {
if (item.href.indexOf('.css') >= 0) {
links += `${item.href}" >`;
}
});
// 循环获取style标签的样式
const domStyle = document.styleSheets;
if (domStyle && domStyle.length > 0) {
for (let i = 0; i < domStyle.length; i++) {
try {
if (domStyle[i].cssRules || domStyle[i].rules) {
const rules = domStyle[i].cssRules || domStyle[i].rules;
for (let b = 0; b < rules.length; b++) {
style += rules[b].cssText;
}
}
} catch (e) {
// console.log(domStyle[i].href + e);
}
}
}
if (that.settings.extraCss) {
that.settings.extraCss.replace(/([^,\s]+)/g, (m: any) => {
links += `${m}">`;
});
}
return ` ${that.settings.popTitle}${extraHead}${links}${style}`;
}
getBody() {
const that: any = this;
let ids = that.settings.ids;
ids = ids.replace(new RegExp("#", "g"), '');
that.elsdom = that.beforeHanler(document.getElementById(ids));
const ele = that.getFormData(that.elsdom);
const htm = ele.outerHTML;
return '' + htm + '';
}
// 克隆节点之前做的操作
beforeHanler(elsdom: any) {
const canvasList = elsdom.querySelectorAll('canvas');
// canvas转换png图片
for (let i = 0; i < canvasList.length; i++) {
if (!canvasList[i].style.display) {
const _parent = canvasList[i].parentNode
const _canvasUrl = canvasList[i].toDataURL('image/png')
const _img = new Image()
_img.className = 'canvasImg'
_img.style.display = 'none'
_img.src = _canvasUrl
// _parent.replaceChild(_img, canvasList[i])
_parent.appendChild(_img)
}
}
return elsdom
}
// 根据type去处理form表单
getFormData(ele: any):any {
const copy = ele.cloneNode(true);
const copiedInputs = copy.querySelectorAll('input,select,textarea');
const canvasImgList = copy.querySelectorAll('.canvasImg,canvas');
let selectCount = -1;
// 处理所有canvas
for (let i = 0; i < canvasImgList.length; i++) {
const _parent = canvasImgList[i].parentNode
const item = canvasImgList[i]
// 删除克隆后的canvas节点
if (item.tagName.toLowerCase() === 'canvas') {
_parent.removeChild(item)
} else {
item.style.display = 'block'
}
}
// 处理所有输入框
for (let i = 0; i < copiedInputs.length; i++) {
const item = copiedInputs[i];
let typeInput = item.getAttribute('type');
const copiedInput = copiedInputs[i];
// 获取select标签
if (!typeInput) {
typeInput = item.tagName === 'SELECT' ? 'select' : item.tagName === 'TEXTAREA' ? 'textarea' : '';
}
// 处理input框
if (item.tagName === 'INPUT') {
// 除了单选框 多选框比较特别
if (typeInput === 'radio' || typeInput === 'checkbox') {
copiedInput.setAttribute('checked', item.checked);
//
} else {
copiedInput.value = item.value;
copiedInput.setAttribute('value', item.value);
}
// 处理select
} else if (typeInput === 'select') {
selectCount++;
for (let b = 0; b < ele.querySelectorAll('select').length; b++) {
const select = ele.querySelectorAll('select')[b]; // 获取原始层每一个select
!select.getAttribute('newbs') && select.setAttribute('newbs', b) // 添加标识
if (select.getAttribute('newbs') == selectCount) {
const opSelectedIndex = ele.querySelectorAll('select')[selectCount].selectedIndex;
item.options[opSelectedIndex].setAttribute('selected', true);
}
}
// 处理textarea
} else {
copiedInput.innerHTML = item.value;
copiedInput.setAttribute('html', item.value);
}
}
return copy;
}
getPrintWindow() {
const that: any = this;
const f = that.Iframe();
return {
f: f,
win: f.contentWindow || f,
doc: f.doc
};
}
Iframe() {
const that: any = this;
const frameId = that.settings.id;
let iframe: any;
try {
iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.style.border = '0px';
iframe.style.position = 'absolute';
iframe.style.width = '0px';
iframe.style.height = '0px';
iframe.style.right = '0px';
iframe.style.top = '0px';
iframe.setAttribute('id', frameId);
iframe.setAttribute('src', new Date().getTime());
iframe.doc = null;
iframe.doc = iframe.contentDocument ? iframe.contentDocument : (iframe.contentWindow ? iframe.contentWindow.document : iframe.document);
iframe.onload = function () {
const win = iframe.contentWindow || iframe;
that.print(win);
}
} catch (e) {
throw new Error(e + '. iframes may not be supported in that browser.');
}
if (iframe.doc == null) {
throw new Error('Cannot find document.');
}
return iframe;
}
}
# 使用
new Print({
ids: id, // * 局部打印必传入id
standard: "", // 文档类型,默认是html5,可选 html5,loose,strict
extraHead: binding.value.extraHead, // 附加在head标签上的额外标签,使用逗号分隔
extraCss: binding.value.extraCss, // 额外的css连接,多个逗号分开
popTitle: "数据源列表", // title的标题 binding.value.popTitle
endCallback() {
// 调用打印之后的回调事件
closeBtn = true;
},
});
# 默认
NODE_ENV = 'development'
BASE_URL = ""
# 自定义变量名必须VUE_APP_开头
VUE_APP_DEMO = "demo"
![目录](https://img-blog.csdnimg.cn/08759e73173a4dd89aee5dda18b2266d.png#pic_center)
# main.ts引用
import '@/assets/iconfont/iconfont.css'
# 使用