顺序断层机制按照报价从低到高排序，在遇到第一个 purchaseQty 为空（或为0）的断层之前，有值的项都是绿色；一旦遇到断层，之后即使 purchaseQty 有值，也只能给黄色。
过渡的类名在进入/离开的过渡中，会有 6 个 class 切换。1、v-enter：定义进入过渡的开始状态。在元素被插入之前生效，在元素被插入之后的下一帧移除。2、v-enter-active：定义进入过渡生效时的状态。在整个进入过渡的阶段中应用，在元素被插入之前生效，在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间，延迟和曲线函数。3、v-enter-to：2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除)，在过渡/动画完成之后移除。4、v-leave：定义离开过渡的开始状态。在离开过渡被触发时立刻生效，下一帧被移除。5、v-leave-active：定义离开过渡生效时的状态。在整个离开过渡的阶段中应用，在离开过渡被触发时立刻生效，在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间，延迟和曲线函数。6、v-leave-to：2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除)，在过渡/动画完成之后移除。自定义过渡的类名我们可以通过以下 attribute 来自定义过渡类名：enter-classenter-active-classenter-to-class (2.1.8+)leave-classleave-active-classleave-to-class (2.1.8+)纯class过渡deom<transition name="module-fade" mode="out-in"> <component ref="activeModule" :is="activeModule"></component> </transition> 在<transition>中切换的类名来说需要注意：如果你使用了 ，那么 v-enter 会替换为 my-transition-enter。对应css过度动画.module-fade-enter-active, .module-fade-leave-active { transition: all 1s; } .module-fade-enter, .module-fade-leave-to { opacity: 0; transform: translateY(30px); } JavaScript 钩子<transition name="module-fade" mode="out-in" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @enter-cancelled="enterCancelled" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave" @leave-cancelled="leaveCancelled" > <component ref="activeModule" :is="activeModule"></component> </transition> 对应钩子的方法：// -------- // 进入中 // -------- beforeEnter (el) { console.log('1 beforeEnter') }, // 回调函数 done 是可选的 enter (el, done) { console.log('2 enter') done() }, afterEnter (el) { console.log('3 afterEnter') }, enterCancelled: function (el) { // ... }, // -------- // 离开时 // -------- beforeLeave (el) { this.$refs['activeModule'].handleSave(); console.log('4 beforeLeave') }, // 当与 CSS 结合使用时 // 回调函数 done 是可选的 leave (el, done) { console.log('5 leave') done() }, afterLeave (el) { console.log('6 afterLeave') }, // leaveCancelled 只用于 v-show 中 leaveCancelled: function (el) { // ... } 这些钩子函数可以结合 CSS transitions/animations 使用，也可以单独使用。enter (el) { el.style.opacity = 0 el.style.transform = 'translateY(30px)' }, 当只用 JavaScript 过渡的时候，在 enter 和 leave 中必须使用 done 进行回调。否则，它们将被同步调用，过渡会立即完成。推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false"，Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
nodejs v24 Error: No such module: http_parser
最近跑了个老项目由于node版本太高启动的时候报如下错误对应报错的文件C:\code\siemens\bsceba\node_modules\http-deceiver\lib\deceiver.js主要问题 process.binding('http_parser') 是 Node已弃用。解决方法：HTTPParser = process.binding('http_parser').HTTPParser; 改成：HTTPParser = require('http-parser-js').HTTPParser; 兼容修改成如下：try { // 尝试使用原生绑定 HTTPParser = process.binding('http_parser').HTTPParser; } catch (e) { // 降级到 JavaScript 实现 HTTPParser = require('http-parser-js').HTTPParser; }
LogicFlow 配置项：LogicFlow 流程图上所有的节点实例操作以及事件new LogicFlow()初始化的详情 点击这里跳转官方说明 图片显示demo在文章底部用到的依赖包 "@logicflow/core": "^2.1.7", "@logicflow/extension": "^2.1.9", "@logicflow/layout": "^2.0.7", LogicFlow apinew LogicFlow 初始化基础DEMO CODEthis.lf = new LogicFlow({ container: this.$refs.container, grid: true, // 等同于默认属性如下 // grid: { // size: 20, // 设置网格大小 // visible: true, // 设置是否可见，若设置为false则不显示网格线但是仍然保留size栅格的效果 // type: "dot", // 设置网格类型，目前支持 dot 点状和 mesh 线状两种 // config: { // color: "#ababab", // 设置网格的颜色 // thickness: 1, // 设置网格线的宽度 // }, // }, keyboard: { enabled: true, }, // edgeTextDraggable: true, // adjustEdgeStartAndEnd: true, edgeType: 'bezier', // idGenerator(type) { // return type + '_' + Math.random(); // }, }); render渲染图数据的时候可以增加初始化数据renderData是在data中配置的默认初始化数据，可以不填this.lf.render(this.renderData); LogicFlow 事件文档接口 外部拖入节点添加时触发demothis.lf.on("node:dnd-add", (data) => { // 拖拽进入面板内执行 console.log("node:dnd-add", data) }); 基于node:click事件输出的API各个模块默认初始化方法LogicFlow 构造函数graphModel 画布数据属性nodeModel 节点数据属性graphModel 事件transformModel 控制画布的放大、缩小、平移editConfigModel 控制页面编辑状态this.lf.on("node:click", (data) => { console.log("node:click", data) const {lf} = this; let {id} = data.data; // 获取节点的model console.log("getNodeModelById", lf.getNodeModelById(id)) // 获取节点的model数据 console.log("getNodeDataById", lf.getNodeDataById(id)) // 获取流程绘图数据 console.log("getGraphData", lf.getGraphData()) // 获取流程绘图原始数据 console.log("getGraphRawData", lf.getGraphRawData()) // 获取指定区域内的所有元素，此区域必须是 DOM 层。 console.log("getAreaElement", lf.getAreaElement([100, 100], [200, 200])) console.log('========LogicFlow==================') console.log("lf", lf) console.log('========画布数据属性=================') const graphModel = lf.graphModel; console.log("graphModel", graphModel) console.log("graphModel", graphModel.height) console.log('========节点数据属性=================') const nodeModel = lf.getNodeModelById(id); console.log("nodeModel", nodeModel) nodeModel.updateText("hello world"); console.log('========事件====================') const {eventCenter} = lf.graphModel; console.log("eventCenter", eventCenter) console.log('========transformModel====================') const {transformModel} = lf.graphModel; console.log("transformModel", transformModel) console.log('========editConfigModel====================') const {editConfigModel} = lf.graphModel; console.log("editConfigModel", editConfigModel) }); edgeModel 边数据属性，边只能点击线才可以捕获所以需要监听edge:click事件// 点击边线体 this.lf.on("edge:click", (data) => { console.log("edge:click", data) console.log('========边数据属性====================') const {lf} = this; let {id} = data.data; const edgeModel = lf.getEdgeModelById(id); const edgeData = edgeModel.getData(); console.log("edgeModel", edgeModel) console.log("edgeData", edgeData) }); demo文件链接点击下载
element的tree树形菜单回显、父级设置半选状态
主要代码： keyList.forEach(key => { const node = this.$refs.weiTree.getNode(key); console.log(node.isLeaf) if (node.isLeaf) { this.$refs.weiTree.setChecked(node, true); } }); 完整demo <el-dialog title="tree" class="bp-dialog" :visible.sync="treeVisible" width="850px" append-to-body :close-on-click-modal="false"> {{ item.title }} <el-tree ref="weiTree" :data="treeData" :props="defaultProps" show-checkbox node-key="code" default-expand-all :expand-on-click-node="false"> <span v-if="node.label.length<28">{{ node.label }} <el-tooltip v-else placement="top" effect="light"> {{ node.label }} {{ node.label }} </el-tooltip> <el-image v-if="/.(png|jpg|jpeg)$/.test(item.dfsPath)" :src="item.dfsPath" :preview-src-list="[item.dfsPath]"> </el-image> 文件 <el-tag v-if="!data.notCheck">检查</el-tag> <el-tag v-else type="success">只读</el-tag> <el-tag v-if="[1,2].includes(data.checkResultType)"> {{ checkResultTypeObj[data.checkResultType] }} </el-tag> <el-tag v-else type="succcess"> {{ checkResultTypeObj[data.checkResultType] }} </el-tag> {{ data.sort }} </el-tree> <el-button type="primary" @click="handleInit">初始化</el-button> <el-button type="primary" @click="handleSubmit">确定</el-button> <el-button @click="handleCancel">取消</el-button> </el-dialog>
ElementUI 中 Table expend嵌套另一个子Table，fixed+嵌套多选实现
比较忙，直接贴代码 <el-button size="mini" @click="handleExpand" class="bp-primary-plain" type="primary" plain>一键展开 </el-button> <el-button size="mini" @click="handlePutAway" class="bp-primary-plain" type="primary" plain>一键收起 </el-button> <el-table ref="tableItemRef" class="bp-table" border :data="tableData"> <el-table-column width="50" fixed="left" align="center"> <el-checkbox v-model="globelCheckedAll" @change="clickCheckAll(scope)" :indeterminate="isIndeterminateAll"></el-checkbox> <el-checkbox v-model="scope.row.isChecked" :indeterminate="scope.row.isIndeterminate" @change="handleSelectionChange(scope.row)"></el-checkbox> </el-table-column> <el-table-column align="center" fixed="left" type="expand"> <el-table class="bp-table" :data="props.row.children" row-key="id"> <el-table-column width="97" align="center"> <el-checkbox v-model="props.row.isChecked" :indeterminate="props.row.isIndeterminate" @change="handleSelectionChange(props.row)"></el-checkbox> <el-checkbox v-model="scope.row.isChecked" @change="clickCheckItemFn(props.row, scope.row)"></el-checkbox> </el-table-column> <el-table-column align="center" prop="" min-width="150" label="" show-overflow-tooltip/> <el-table-column align="center" prop="itemFunction" width="150" label="工步" show-overflow-tooltip/> <el-table-column align="center" prop="potentialFailureMode" min-width="150" label="潜在失效模式" show-overflow-tooltip/> <el-table-column align="center" prop="potentialEffectOfFailure" min-width="150" label="潜在失效影响" show-overflow-tooltip/> <el-table-column align="center" prop="sev" label="严重度" min-width="70" show-overflow-tooltip/> <el-table-column align="center" prop="potentialCauseMechanismOfFailure" min-width="120" label="失效起因/机理" show-overflow-tooltip/> <el-table-column align="center" prop="occur" label="频度" min-width="60" show-overflow-tooltip/> <el-table-column align="center" prop="currentDesignControls" min-width="180" label="现行过程控制" show-overflow-tooltip/> <el-table-column align="center" prop="det" label="探测度" min-width="70" show-overflow-tooltip/> <el-table-column align="center" prop="rpn" label="风险度" min-width="70" show-overflow-tooltip/> <el-table-column align="center" label="操作" fixed="right" min-width="129"> <el-button type="text" size="small" @click="clickDelFn(props.row,props.$index,scope.row,scope.$index)"> 删除 </el-button> </el-table-column> </el-table> </el-table-column> <el-table-column prop="flowChart" fixed="left" label="工序" min-width="150" show-overflow-tooltip/> <el-table-column align="center" prop="itemFunction" width="150" label="工步" show-overflow-tooltip/> <el-table-column align="center" prop="potentialFailureMode" min-width="150" label="潜在失效模式" show-overflow-tooltip/> <el-table-column align="center" prop="potentialEffectOfFailure" min-width="150" label="潜在失效影响" show-overflow-tooltip/> <el-table-column align="center" prop="sev" label="严重度" min-width="70" show-overflow-tooltip/> <el-table-column align="center" prop="potentialCauseMechanismOfFailure" min-width="120" label="失效起因/机理" show-overflow-tooltip/> <el-table-column align="center" prop="occur" label="频度" min-width="60" show-overflow-tooltip/> <el-table-column align="center" prop="currentDesignControls" min-width="180" label="现行过程控制" show-overflow-tooltip/> <el-table-column align="center" prop="det" label="探测度" min-width="70" show-overflow-tooltip/> <el-table-column align="center" prop="rpn" label="风险度" min-width="70" show-overflow-tooltip/> <el-table-column align="center" label="操作" fixed="right" min-width="130"> <el-button type="text" size="small" @click="clickDelFn(props.row,props.$index,scope.row,scope.$index)"> 删除 </el-button> </el-table-column> </el-table>
解决elementui中el-radio或el-cascader报错：Blocked aria-hidden on an element because its descendant retained focus.
在使用elment中el-radio的时候发现控制台报错，Blocked aria-hidden on an element because its descendant retained focus. The focus must not be hidden from assistive technology users. Avoid using aria-hidden on a focused element or its ancestor. Consider using the inert attribute instead, which will also prevent focus. For more details, see the aria-hidden section of the WAI-ARIA specification at https://w3c.github.io/aria/#aria-hidden. Element with focus: input Ancestor with aria-hidden: ​ 解决方案一：::v-deep input[aria-hidden="true"] { display: none !important; } ::v-deep .el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner { box-shadow: none !important; } 解决方案二：自定义指令 Vue.directive('removeAriaHidden', { bind(el, binding) { const ariaEls = el.querySelectorAll('.el-radio__original') ariaEls.forEach((item) => { item.removeAttribute('aria-hidden') }) } }) 页面使用<el-radio-group v-model="tableRadio" class="new_radio" @change="changeRadio" v-removeAriaHidden></el-radio-group>
最近在把vue2升级vue3过程中遇到了各种bug，这次遇到了在vue2中父子传参的过程中发现showSearch数据不更新问题父组件引用 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> 子组件 this.$emit("update:showSearch", !this.showSearch); 我们需要吧父组件改成v-model:value="value" 模式<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
svg渲染use占位符宽高都是0，页面显示空白问题
<svg-icon icon-class="clipboard" class-name="disabled" /> 经过分析是少了个解析插件 svg-sprite-loader ，用npm安装一下，然后需要在vue.config.js中添加配置'use strict' const path = require('path') function resolve(dir) { return path.join(__dirname, dir) } chainWebpack: config => { config.plugins.delete('preload') // TODO: need test config.plugins.delete('prefetch') // TODO: need test // set svg-sprite-loader config.module .rule('svg') .exclude.add(resolve('src/assets/icons')) .end() config.module .rule('icons') .test(/\.svg$/) .include.add(resolve('src/assets/icons')) .end() .use('svg-sprite-loader') .loader('svg-sprite-loader') .options({ symbolId: 'icon-[name]' }) .end() }
pc端屏幕显示设置缩放比例对页面布局的适配
利用device-pixel-ratio单独适配像素比@media all and (-moz-min-device-pixel-ratio: 1.09) and (-moz-max-device-pixel-ratio: 1.18), (-webkit-min-device-pixel-ratio: 1.09) and (-webkit-max-device-pixel-ratio: 1.18), (min-resolution: 1.09dppx) and (max-resolution: 1.18dppx) { :root { font-size: 14px; } } @media all and (-moz-min-device-pixel-ratio: 1.19) and (-moz-max-device-pixel-ratio: 1.28), (-webkit-min-device-pixel-ratio: 1.19) and (-webkit-max-device-pixel-ratio: 1.28), (min-resolution: 1.19dppx) and (max-resolution: 1.28dppx) { :root { font-size: 13px; } } @media all and (-moz-min-device-pixel-ratio: 1.29) and (-moz-max-device-pixel-ratio: 1.4), (-webkit-min-device-pixel-ratio: 1.29) and (-webkit-max-device-pixel-ratio: 1.4), (min-resolution: 1.29dppx) and (max-resolution: 1.4dppx) { :root { font-size: 12px; } } @media all and (-moz-min-device-pixel-ratio: 1.41) and (-moz-max-device-pixel-ratio: 1.6), (-webkit-min-device-pixel-ratio: 1.41) and (-webkit-max-device-pixel-ratio: 1.6), (min-resolution: 1.41dppx) and (max-resolution: 1.6dppx) { :root { font-size: 10px; } } @media all and (-moz-min-device-pixel-ratio: 1.61) and (-moz-max-device-pixel-ratio: 1.8), (-webkit-min-device-pixel-ratio: 1.61) and (-webkit-max-device-pixel-ratio: 1.8), (min-resolution: 1.61dppx) and (max-resolution: 1.8dppx) { :root { font-size: 9px; } } @media all and (-moz-min-device-pixel-ratio: 1.81) and (-moz-max-device-pixel-ratio: 2.1), (-webkit-min-device-pixel-ratio: 1.81) and (-webkit-max-device-pixel-ratio: 2.1), (min-resolution: 1.81dppx) and (max-resolution: 2.1dppx) { :root { font-size: 8px; } } vue解决办法mounted () { this.handleScreen() window.onresize = () => { this.handleScreen() } }, methods: { handleScreen(){ const zoom = this.detectZoom(); console.log(zoom, 'MMMMMMMMMMMMMMM') const scale = 100 / Number(zoom); console.log('scale', scale, typeof scale) }, detectZoom () { let ratio = 0, screen = window.screen, ua = navigator.userAgent.toLowerCase(); if (window.devicePixelRatio !== undefined) { ratio = window.devicePixelRatio; } else if (~ua.indexOf('msie')) { if (screen.deviceXDPI && screen.logicalXDPI) { ratio = screen.deviceXDPI / screen.logicalXDPI; } } else if (window.outerWidth !== undefined && window.innerWidth !== undefined) { ratio = window.outerWidth / window.innerWidth; } if (ratio) { ratio = Math.round(ratio * 100); } return ratio; }, }
首先安装vue-i18n包新建locales/i18n.js文件/** * Created by liweiliang 406320591@QQ.com on 2022/10/14 15:16. */ import Vue from "vue"; import VueI18n from "vue-i18n"; import elementZhLocale from "element-ui/lib/locale/lang/zh-CN"; // element-ui lang import elementEnLocale from "element-ui/lib/locale/lang/en"; // element-ui lang import enLocale from "./lang/enLocale"; import zhLocale from "./lang/zhLocale"; const messages = { en: { ...enLocale, ...elementEnLocale, }, zh: { ...zhLocale, ...elementZhLocale, }, }; /** * i18n 配置 * @param locale 本地化语言 * @param fallback 回退语言 * @returns {VueI18n} */ function initI18n(locale, fallback) { Vue.use(VueI18n); let i18nOptions = { locale, fallbackLocale: fallback, silentFallbackWarn: true, messages, }; return new VueI18n(i18nOptions); } export { initI18n }; locales/lang/zhLocale.js文件/** * Created by liweiliang 406320591@QQ.com on 2022/10/17 14:11. */ const zhModulesFiles = require.context("./zh", true, /\.js$/); const zhLang = zhModulesFiles.keys().reduce((modules, modulePath) => { const value = zhModulesFiles(modulePath); modules = { ...modules, ...value.default }; return modules; }, {}); export default zhLang; locales/lang/enLocale.js文件main.js引入import { initI18n } from "@/locales/i18n"; const i18n = initI18n(Cookies.get('language') || 'en', "en"); new Vue({ el: '#app', router, store, i18n, render: h => h(App) })
vue 项目启动报错：Syntax Error: Unexpected token 的解决方法
vue项目根目录新增配置文件 .babelrc{ "presets": [ "stage-2" ] } 修复好 Syntax Error: Unexpected token 启动发现又报如下问题Failed to compile with 9 errors Module build failed: Error: No PostCSS Config found in: D:\project\ 根目录新建postcss.config.js/** * Created by liweiliang 406320591@QQ.com on 2022/11/1 14:10. */ module.exports = { plugins: { autoprefixer: {browsers: 'last 5 version'} } }
<el-button-group> <el-button type="primary" icon="el-icon-arrow-left" size="small" @click="prePage">上一页</el-button> <el-button type="primary" size="small" @click="nextPage">下一页</el-button> </el-button-group> {{ currentPage }} / {{ pageCountNum }} <pdf :page="currentPage" :src="pdfUrl" @progress="loadedRatio = $event" @num-pages="pageCountNum = $event" ></pdf>
安装包 jszip和file-saver代码 downloadZip
项目main.js文件引入import VueQuillEditor from 'vue-quill-editor' // require styles import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css' Vue.use(VueQuillEditor, /* { default global options } */) /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App,VueQuillEditor }, //组件中注册 template: '<App/>' }) 新建一个editor-demo.vue文件，下面注释部分是局部引入方法 <quill-editor v-model="content" ref="myQuillEditor" :options="editorOption" @blur="onEditorBlur($event)"> </quill-editor> 保存 {{storageCont}}
[Vue warn]: Failed to resolve directive: ant-portal (found in <Anonymous>)
最近在各种魔改一个老项目，遇到了一个这样的错误Ant Design Vue 局部引入 Modal 组件方式import {Row, Col, Button, Collapse, Icon, Modal, Input} from "ant-design-vue"; components: { AButton: Button, AInput: Input, ACollapse: Collapse, ACollapsePanel: Collapse.Panel, AIcon: Icon, AModal: Modal }, 开始看到 directive 以为写的自定义指令有问题，后来查了下是由于modal局部引用导致的，所有要把Modal已use的方式来注册就好了，代码如下import Vue from 'vue' import {Modal} from "ant-design-vue"; Vue.use(Modal)
最近老搞移动端开发，赶脚调试起来很不方便，然后就发现了腾讯开源的vConsolevConsole是一个轻量、可拓展、针对手机网页的前端开发者调试面板。特性查看 console 日志查看网络请求查看页面 element 结构查看 Cookies、localStorage 和 SessionStorage手动执行 JS 命令行自定义插件上手方法一：使用 npm（推荐）$ npm install vconsole Import 并初始化后，即可使用 console.log 功能，如 Chrome devtools 上一样。import VConsole from 'vconsole'; const vConsole = new VConsole(); // 或者使用 options 选项初始化 const vConsole = new VConsole({ maxLogNumber: 1000 }); // 接下来即可照常使用 `console` 等方法 console.log('Hello world'); // 结束调试后，可移除掉 vConsole.destroy(); 方法二：使用 unpkg 的 CDN 直接插入到 HTML 详细使用方法请参阅使用教程。http://wechatfe.github.io/vconsole/demo.html文档vConsole 本体：使用教程公共属性及方法辅助函数插件：插件：入门插件：编写插件插件：Event 事件列表第三方插件列表vConsole-sourcesvconsole-webpack-pluginvconsole-stats-pluginvconsole-vue-devtools-pluginvconsole-outputlog-pluginvite-plugin-vconsole
Vue style scoped 使用@import引入css, 作用域是全局的解决方案
这两天有开始搞华为VOLTE第二版了，偷懒样式直接@import，这时发现第一版样式全服错乱，查看了下是在使用@import引入css的时候，css-loader对import的文件会当做外部资源来编译造成它变为全局样式案例 修改成 注意：如果想要额外增加样式需要单独写个style，如果在 中增加样式将不生效所以最后改成下面效果，当然你也可以直接写到mian.css里面
最近开发项目在和华为Volte做对接，结果华为volte第一版还是原生加jquery来实现的，由于里面有不少需要引入外部js文件的，就给了一天的时间做对接，没办法只能剑走偏锋了首先定义一个 utils/loadScript.js 封装一个动态加载js文件的方法export function loadScript (url) { return new Promise((resolve, reject) => { const script = document.createElement('script') script.onload = () => resolve() script.onerror = () => reject(new Error(`Load script from ${url} failed`)) script.src = url const head = document.head || document.getElementsByTagName('head')[0] ;(document.body || head).appendChild(script) }) } 然后定义一个 callVoLte.js文件供vue文件引入调用的/** * Created by liweiliang 406320591@QQ.com on 2022-01-12 10:59. */ import { loadScript } from '@/utils/loadScript' const RESOURCE_LIST = [ "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/tools/jquery/jquery-3.1.1.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/tools/jquery/jquery-query.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/tools/jquery/jquery.cookie.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/tools/jquery/jquery.json-2.3.min.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/tools/jquery/jquery.utils.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/tools/jquery/jquery.md5.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/tools/pop/jquery-translucent.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/ams/reconnecting-websocket.min.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/ams/websocket.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/ams/ams-utils.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/ams/xnams-websocket.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/rtcjs/rest-api.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/rtcjs/socket.io.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/rtcjs/adapter-7.0.0.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/rtcjs/rtc.min.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/sdk_lib/tools/common.js", "https://huawei-volte-v2.oss-cn-beijing.aliyuncs.com/static/demo.js" ] export function loadVoLteResourceList () { return RESOURCE_LIST.reduce((res, el) => res.then(() => loadScript(el)), Promise.resolve()).then(() => { console.log('success') }).catch((error) => { console.error('外呼VoLTE sdk 前置 js 资源加载失败:', error.name, error.message) return Promise.reject(error) }) } 最后在.vue文件中引用定义好的callVoLte.js中的方法及在生命周期函数中调用下就好了import { loadVoLteResourceList } from './callVoLte' //引用 export default { name: 'index', created() { loadVoLteResourceList() //调用运行 }, data(){ return { } }, methods: { screen_capture() { let user_id = $('#showPhone').text() let img_str = screenCapture(user_id) if (img_str == '') { console.log('截屏失败') return } console.log('xxxxxxxx 截屏成功，图片base64字符串：', img_str) this.$bus.$emit('upload-photos', img_str) }, closeVoLte(){ this.$store.commit('setVoLteState',false) } } }
never reassigned. Use 'const' instead prefer-const
最近在搞vue3+Typescript脚手架然后在定义变量的时候报错 'name' is never reassigned. Use 'const' instead prefer-const 大概意思就是 标识符'errMsg'永远不会被重新分配;使用'const'而不是'let'。(prefer-const)解决方法就是在eslint配置文件或者tslintt配置文件增加{ "rules":{ "prefer-const": "off" } }
Pinia 是什么?Pinia 是一个用于 Vue 的状态管理库，类似 Vuex, 是 Vue 的另一种状态管理方案Pinia 支持 Vue2 和 Vue3常见问题关于该项目和可能问题的几点说明：问：这是否取代了Vuex，是它的继任者吗？答：不，或者至少这不是主要意图问：动态模块呢？答：动态模块不是安全的类型，因此我们允许创建不同的商店，可以在任何地方导入Pinia 优势符合直觉，易于学习极轻， 仅有 1 KB模块化设计，便于拆分状态安装 Piniayarn add pinia@next # or with npm npm install pinia@next 用法创建一个 pinia（根存储）并将其传递给应用程序：import { createPinia } from 'pinia'; app.use(createPinia()); 核心概念与基本使用StoreStore 是一个保存状态和业务逻辑的实体，可以自由读取和写入，并通过导入后在 setup 中使用创建一个 store// store.js import { defineStore } from "pinia"; interface MainState { counter: number name: string } export const useMainStore = defineStore({ // id: 必须的，在所有 Store 中唯一 id: "main", // a function that returns a fresh state state: () => MainState ({ counter: 0, name: 'Eduardo', }), // optional getters getters: { doubleCount() { return this.counter * 2 }, // use getters in other getters doubleCountPlusOne() { return this.doubleCount * 2 + 1 }, }, // optional actions actions: { reset() { // `this` is the store instance this.counter = 0 }, }, }) 使用 Store// xxx.vue {{store.count}}
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in D:\project\saas-platform-pc\node_modules\@babel\helper-compilation-targets\package.json
原因：可能是node版本导致引入依赖时bable配置问题。解决办法修改对应文件 node_modules\@babel\helper-compilation-targets\package.json 48行的 “exports”：false 为{ ".": "./lib/index.js" },
vue for循环中按顺序axios请求拿到每条数据对应的状态
在循环数组的时候基于每个对象中的某个参数来进行数据请求，获取当前对象对应的数据状态实现方法基于最新的es6中的async await 来实现首先要把对应的Promise方法进行一个封装_getReportStatus(item){ return new Promise((resolve, reject) => { getReportStatus({reportCode:item.reportNo}).then(data => { if(data.data.code == '0000'){ resolve(data.data.result.taskState); } }) }); }, 然后利用async 来调取async getReportStatus(result){ for (let item of result){ item.taskState = await this._getReportStatus(item); } app.globalData.caseList = result wx.navigateTo({ url: "../progressQuery/progressQuery", }); }, 如果循环中需要用到多个请求的话最后可以加一个 Promise.all 来进行数据解析，还有需要注意的async 中使用 await定义的方法，只能用for，那么为什么不能用forEach,map等方法呢，原因很简单那就是 forEach,map等是一个同步方法，真正要实现异步返回就需要用for of .
使用自定义指令directive如何修改v-model绑定的键值对
主要语句 vnode.elm.dispatchEvent(new CustomEvent('input'));/** * Created by liweiliang 406320591@QQ.com on 2021/01/26 23:04. */ import pattern from '@/utils/pattern' let amountCheck = function (vnode, binding, el) { // console.log(el, vnode, binding) let reopenState = binding.modifiers.reopen; if (!reopenState && !pattern.twoDecimal.test(el.target.value)) { vnode.context.$message.error('输入错误,已重置成最后一次输入正确的值') el.target.value = el.target.oldValue; vnode.elm.dispatchEvent(new CustomEvent('input')); } else if (reopenState && !pattern.twoDecimalReopen.test(el.target.value)) { vnode.context.$message.error('输入错误,已重置成最后一次输入正确的值') el.target.value = el.target.oldValue; vnode.elm.dispatchEvent(new CustomEvent('input')); } } export default { directiveName: 'amounts', bind (el, binding, vnode, oldVnode) { // console.log(el, binding, vnode, oldVnode) if (el.nodeName != 'INPUT') return el.addEventListener('blur', amountCheck.bind(this, vnode, binding)) }, componentUpdated (el, binding, vnode, oldVnode) { console.log(binding.name, 'value', binding.value, 'oldValue', binding.oldValue) console.log(pattern) if (binding.modifiers.reopen) { if (pattern.twoDecimalReopen.test(binding.value)) { el.oldValue = binding.value } else if (pattern.twoDecimalReopen.test(binding.oldValue)) { el.oldValue = binding.oldValue } } else if (pattern.twoDecimal.test(binding.value)) { el.oldValue = binding.value } else if (pattern.twoDecimal.test(binding.oldValue)) { el.oldValue = binding.oldValue } }, unbind (el, binding, vnode, oldVnode) { el.removeEventListener('blur', amountCheck.bind(this, vnode)) } };
Ant Design of Vue —— Table表格组件 —— 设置动态表头
Column配置比如：操作列{ key: 'action', scopedSlots: { customRender: 'action', title: '变量名' }, align: 'center' } 代码段 {{动态表头名称}} demo: 注意不要在括号 dataIndex同级节点加title属性名，否则的话scopedSlots设置的title会失效//Column { dataIndex: 'belong', key: 'belong', width:'8.33333333%', scopedSlots: {customRender: 'belong',title:'belongTitle'} } //template {{belongTitle}}
vue-baidu-map or 百度地图API 禁止点击时弹出地址详情的方法
首先来说 百度地图默认的api，通过查看接口文当 中 MapOptions -> enableMapClick:是否开启底图可点功能，默认启用new BMap.Map(mapid,{enableMapClick:false});在vue-baidu-map中，上面这个方法是无效的通过查看源码发现需要在baidu-map上添加个:mapClick="false" 就可以了官方文档：https://dafrok.github.io/vue-baidu-map/#/zh/index
antdv Modal this.$confirm对话框 使用vnode修改标题icon问题
icon 自定义图标（1.14.0 新增） string|()=>VNode 一、利用自带的icon赋值个默认的icon名字就可以了，但是有时候我们需要用到实底风格的icon，所以只能用()=>VNodethis.$confirm({ title: '确认设置当前位置为出险地点?', content: this.infoWindow.contents, icon: 'exclamation-circle', onOk: () => { this.onMapClose(); console.log('点击确认') }, onCancel() { }, }); 二、通过()=>VNode修改this.$confirm({ title: '确认设置当前位置为出险地点?', content: this.infoWindow.contents, icon: () => this.$createElement('a-icon', { props: { type: 'exclamation-circle', theme: 'filled' }, }), onOk: () => { this.onMapClose(); console.log('点击确认') }, onCancel() { }, });
Warning: [antdv: Each record in table should have a unique `key` prop,or set `rowKey` to an unique primary key.]
Warning: [antdv: Each record in table should have a unique key prop,or set rowKey to an unique primary key.] 使用 Ant Design的时候报key警告，这由于columns中定义的默认key值在返回的数据中没有当前的这个字段造成的，一个是使用rowKey默认指定一个对应的键值对，或者使用类似v-for循环中的下标index来代替:rowKey="(record,index)=>{return index}"
vue 报错 You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
最近试了下 Vue.extend 方法，写好后发现访问会报如下错误vue.runtime.esm.js?2b0e:619 [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.接下来我们分析下报错的原因在哪里和解决办法原因vue有两种形式的代码 compiler（模板）模式和runtime模式（运行时），vue模块的package.json的main字段默认为runtime模式， 指向了"dist/vue.runtime.common.js"位置。这是vue升级到2.0之后就有的特点。解决方法在vue.config中增加个配置就可以了runtimeCompiler: true
Vue父子组件生命周期执行顺序及钩子函数的个人理解（转载）
先附一张官网上的vue实例的生命周期图，每个Vue实例在被创建的时候都需要经过一系列的初始化过程，例如需要设置数据监听，编译模板，将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数(回调函数)，这给了用户在不同阶段添加自己代码的机会。1、vue的生命周期图在vue实例的整个生命周期的各个阶段，会提供不同的钩子函数以供我们进行不同的操作。先列出vue官网上对各个钩子函数的详细解析。生命周期钩子详细beforeCreate在实例初始化之后，数据观测(data observer) 和 event/watcher 事件配置之前被调用。created实例已经创建完成之后被调用。在这一步，实例已完成以下的配置：数据观测(data observer)，属性和方法的运算， watch/event 事件回调。 在执行data()方法前props属性有数据已经可以访问，watch和computed监听函数此时为null，此时this.computed里的计算属性值为undefined。 data函数执行完后，watch和computed监听函数才可用，因为data函数执行完后，data函数return的属性这时才可用。然而，挂载阶段还没开始，$el 属性目前不可见。beforeMount在挂载开始之前被调用：相关的 render 函数首次被调用。mountedel 被新创建的 vm.$el 替换，并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素，当 mounted 被调用时 vm.$el 也在文档内。beforeUpdate数据更新时调用，发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态，这不会触发附加的重渲染过程。updated由于数据更改导致的虚拟 DOM 重新渲染和打补丁，在这之后会调用该钩子。当这个钩子被调用时，组件 DOM 已经更新，所以你现在可以执行依赖于 DOM 的操作。activatedkeep-alive 组件激活时调用。deactivatedkeep-alive 组件停用时调用。beforeDestroy实例销毁之前调用。在这一步，实例仍然完全可用。destroyedVue 实例销毁后调用。调用后，Vue 实例指示的所有东西都会解绑定，所有的事件监听器会被移除，所有的子实例也会被销毁。2、实际操作下面我们在实际的代码执行过程中理解父子组件生命周期创建过程以及钩子函数执行的实时状态变化。测试基于下面的代码，引入vue.js文件后即可执行。（打开页面后，再按一次刷新会自动进入debugger状态） Document {{message}} <keep-alive> <my-components :msg="msg1" v-if="show"></my-components> </keep-alive> 3.1、生命周期调试首先我们创建了一个Vue实例vm，将其挂载到页面中id为“app”的元素上。3.1.1、根组件的beforeCreate阶段可以看出，在调用beforeCreate()函数时，只进行了一些必要的初始化操作（例如一些全局的配置和根实例的一些属性初始化），此时data属性为undefined，没有可供操作的数据。3.1.2、根组件的Created阶段调用Created()函数，在这一步，实例已完成以下的配置：数据代理和动态数据绑定(data observer)，属性和方法的运算， watch/event 事件回调。然而，挂载阶段还没开始，$el 属性目前不可见。3.1.3、根组件的beforeMount阶段在调用boforeMount()函数前首先会判断对象是否有el选项。如果有的话就继续向下编译，如果没有el选项，则停止编译，也就意味着停止了生命周期，直到在该vue实例上调用vm.$mount(el)在这个例子中，我们有el元素，因此会调用boforeMount()函数,此时已经开始执行模板解析函数，但还没有将$el元素挂载页面，页面视图因此也未更新。在标红处，还是 {{message}}，这里就是应用的 Virtual DOM（虚拟Dom）技术，先把坑占住了。到后面mounted挂载的时候再把值渲染进去。3.1.4、子组件的beforeCreate、Created、beforeMount、Mounted阶段在父组件执行beforeMount阶段后，进入子组件的beforeCreate、Created、beforeMount阶段，这些阶段和父组件类似，按下不表。beforeMount阶段后，执行的是Mounted阶段，该阶段时子组件已经挂载到父组件上，并且父组件随之挂载到页面中。由下图可以知道，在beforeMount阶段之后、Mounted阶段之前，数据已经被加载到视图上了，即$el元素被挂载到页面时触发了视图的更新。3.1.5、子组件的activated阶段我们发现在子父组件全部挂载到页面之后被触发。这是因为子组件my-components被 包裹，随$el的挂载被触发。如果子组件没有被包裹，那么该阶段将不会被触发。3.1.6、父组件的mounted阶段mounted执行时：此时el已经渲染完成并挂载到实例上。至此，从Vue实例的初始化到将新的模板挂载到页面上的阶段已经完成，退出debugger。下面我们来看一下deactivated、beforeUpdate、updated、beforeDestroy、destroyed钩子函数。3.2、deactivated、beforeUpdate、updated阶段由生命周期函数可知：当数据变化后、虚拟DOM渲染重新渲染页面前会触发beforeUpdate()函数，此时视图还未改变。当虚拟DOM渲染页面视图更新后会触发updated()函数。我们不妨改变vm.show = false，当修改这个属性时，不仅会触发beforeUpdate、updated函数，还会触发deactivated函数（因为keep-alive 组件停用时调用）。我们不妨想一下deactivated函数会在beforeUpdate后还是updated后调用。我们在控制台输入vm.show = false。得到三者的调用顺序分别为beforeUpdate、deactivated、updated。我们可以知道的是deactivated函数的触发时间是在视图更新时触发。因为当视图更新时才能知道keep-alive组件被停用了。3.3、beforeDestroy和destroyed钩子函数间的生命周期现在我们对Vue实例进行销毁，调用app.$destroy()方法即可将其销毁，控制台测试如下：我们发现实例依然存在，但是此时变化已经发生在了其他地方。beforeDestroy钩子函数在实例销毁之前调用。在这一步，实例仍然完全可用。destroyed钩子函数在Vue 实例销毁后调用。调用后，Vue 实例指示的所有东西都会解绑定，所有的事件监听器会被移除，所有的子实例也会被销毁（也就是说子组件也会触发相应的函数）。这里的销毁并不指代'抹去'，而是表示'解绑'。销毁时beforeDestory函数的传递顺序为由父到子，destory的传递顺序为由子到父。4、一些应用钩子函数的想法在created钩子中可以对data数据进行操作，这个时候可以进行ajax请求将返回的数据赋给data。虽然updated函数会在数据变化时被触发，但却不能准确的判断是那个属性值被改变，所以在实际情况中用computed或match函数来监听属性的变化，并做一些其他的操作。在mounted钩子对挂载的dom进行操作，此时，DOM已经被渲染到页面上。在使用vue-router时有时需要使用来缓存组件状态，这个时候created钩子就不会被重复调用了，如果我们的子组件需要在每次加载或切换状态的时候进行某些操作，可以使用activated钩子触发。所有的生命周期钩子自动绑定 this 上下文到实例中，所以不能使用箭头函数来定义一个生命周期方法 (例如 created: () => this.fetchTodos())。这是导致this指向父级。5、 小结加载渲染过程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted子组件更新过程 父beforeUpdate->子beforeUpdate->子updated->父updated父组件更新过程 父beforeUpdate->父updated销毁过程 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed6、参考文章关于Vue.js2.0生命周期的研究与理解Vue2.0 探索之路——生命周期和钩子函数的一些理解