-
正则去除中括号(符号)及里面包含的内容例子:颜色:粉色[10] 尺码:S[5]去掉[ ]及内容:preg_replace("/\[.*\]/", '', $str)处理后效果:颜色:粉色 尺码:S小技巧:可把[ ]改为其他符号应用在需要的地方正则表达式匹配括号里的内容,^和&用法正则表达式匹配括号里的内容包括括号[\(|(].*[\)|)]$1、符号解释.匹配除\n外的字符*匹配多个\转义字符[ ]匹配里面的任意字符,[\(|(] 表示匹配 "(" 或者 "("2、简化,可以不用| 来判断 "(" 还是 "(" 。[\((].*[\))]坑1:注意 ^ 或者 $ 的使用(^:匹配输入字符串开始的位置;$:匹配输入字符串结束的位置),不要轻易写在最开始或者结尾,加了后匹配不了包含的字符,^[\((].*[\))]$ 表示以左括号开头并且以右括号结尾的字符串,所以匹配不了。要用^或者$ 的表示包含括号内容的字符串写法为[\((^].*[\))$]或者[\((^].*[\))]js使用console.log("验证结果",/[\((].*[\))]/.test("fgrgreregr((sdi啥@#@!!#!的s)dd))sdsnhyh"))
-
在WEB开发中,时常会用到javascript来获取当前页面的url网址信息,在这里是我的一些获取url信息的小总结。 下面我们举例一个URL,然后获得它的各个组成部分:http://i.jb51.net/EditPosts.aspx?opt=1 1、window.location.href(设置或获取整个 URL 为字符串) var test = window.location.href; alert(test); 返回:http://i.jb51.net/EditPosts.aspx?opt=1 2、window.location.protocol(设置或获取 URL 的协议部分) var test = window.location.protocol; alert(test); 返回:http: 3、window.location.host(设置或获取 URL 的主机部分) var test = window.location.host; alert(test); 返回:i.jb51.net 4、window.location.port(设置或获取与 URL 关联的端口号码) var test = window.location.port; alert(test); 返回:空字符(如果采用默认的80端口(update:即使添加了:80),那么返回值并不是默认的80而是空字符) 5、window.location.pathname(设置或获取与 URL 的路径部分(就是文件地址)) var test = window.location.pathname; alert(test); 返回:/EditPosts.aspx 6、window.location.search(设置或获取 href 属性中跟在问号后面的部分) var test = window.location.search; alert(test); 返回:?opt=1 PS:获得查询(参数)部分,除了给动态语言赋值以外,我们同样可以给静态页面,并使用javascript来获得相信应的参数值。 7、window.location.hash(设置或获取 href 属性中在井号“#”后面的分段) var test = window.location.hash; alert(test); 返回:空字符(因为url中没有) 8、js获取url中的参数值 一、正则法 function getQueryString(name) { var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); var r = window.location.search.substr(1).match(reg); if (r != null) { return unescape(r[2]); } return null; } // 这样调用: alert(GetQueryString("参数名1")); alert(GetQueryString("参数名2")); alert(GetQueryString("参数名3")); 二、split拆分法 function GetRequest() { var url = location.search; //获取url中"?"符后的字串 var theRequest = new Object(); if (url.indexOf("?") != -1) { var str = url.substr(1); strs = str.split("&"); for(var i = 0; i < strs.length; i ++) { theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]); } } return theRequest; } var Request = new Object(); Request = GetRequest();<br>// var id=Request["id"]; // var 参数1,参数2,参数3,参数N; // 参数1 = Request['参数1']; // 参数2 = Request['参数2']; // 参数3 = Request['参数3']; // 参数N = Request['参数N']; 三、指定取 比如说一个url:http://i.jb51.net/?j=js,我们想得到参数j的值,可以通过以下函数调用。 function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配 var context = ""; if (r != null) context = r[2]; reg = null; r = null; return context == null || context == "" || context == "undefined" ? "" : context; } alert(GetQueryString("j")); 四、单个参数的获取方法 function GetRequest() { var url = location.search; //获取url中"?"符后的字串 if (url.indexOf("?") != -1) { //判断是否有参数 var str = url.substr(1); //从第一个字符开始 因为第0个是?号 获取所有除问号的所有符串 strs = str.split("="); //用等号进行分隔 (因为知道只有一个参数 所以直接用等号进分隔 如果有多个参数 要用&号分隔 再用等号进行分隔) alert(strs[1]); //直接弹出第一个参数 (如果有多个参数 还要进行循环的) } } javascript 获取当前 URL 参数的两种方法 //返回的是字符串形式的参数,例如:class_id=3&id=2& function getUrlArgStr(){ var q=location.search.substr(1); var qs=q.split('&'); var argStr=''; if(qs){ for(var i=0;i<qs.length;i++){ argStr+=qs[i].substring(0,qs[i].indexOf('='))+'='+qs[i].substring(qs[i].indexOf('=')+1)+'&'; } } return argStr; } //返回的是对象形式的参数 function getUrlArgObject(){ var args=new Object(); var query=location.search.substring(1);//获取查询串 var pairs=query.split(",");//在逗号处断开 for(var i=0;i<pairs.length;i++){ var pos=pairs[i].indexOf('=');//查找name=value if(pos==-1){//如果没有找到就跳过 continue; } var argname=pairs[i].substring(0,pos);//提取name var value=pairs[i].substring(pos+1);//提取value args[argname]=unescape(value);//存为属性 } return args;//返回对象 } 另外列出一些 javascript 获取url中各个部分的功能方法: window.location.host; //返回url 的主机部分,例如:www.xxx.com window.location.hostname; //返回www.xxx.com window.location.href; //返回整个url字符串(在浏览器中就是完整的地址栏),例如:www.xxx.com/index.php?class_id=3&id=2 window.location.pathname; //返回/a/index.php或者/index.php window.location.protocol; //返回url 的协议部分,例如: http:,ftp:,maito:等等。 window.location.port //url 的端口部分,如果采用默认的80端口,那么返回值并不是默认的80而是空字符 以上就是本文的全部内容,希望对大家理解如何获取当前页面url网址信息有所帮助。 原文链接:https://www.jb51.net/article/82519.htm
-
最近接手了一个后台管理项目,项目使用了Element-ui组件, 使用了Select 下拉菜单展示并选择内容,使用了cascader做级联城市选择器 看了官方文档我们知道可以使用v-model绑定数据,设置初始值/默认值 <el-form-item label="班级" prop="classId"> <el-select v-model="form.classId" placeholder="请选择班级"> <el-option v-for="(value) of classList" :key="value.classId" :label="value.className" :value="value.classId"></el-option> </el-select> </el-form-item> <el-form-item label="机构地址" prop="district"> <el-cascader style="width: 216px;" v-model="form.district" :options="dataDistrict" @change="handleChange" > </el-cascader> </el-form-item> 问题来了,明明已经设置了v-model但是没有显示,百度发现问题在于数据类型,form.classId的值为 String ,而 el-select列表的 value 为 Number,el-cascader的value是Array,form.district却是JSON字符串,并不全等,导致无法找到对应的项,把数据类型进行转换后就能正常显示啦 ———————————————— 原文链接:https://blog.csdn.net/weixin_43144209/article/details/120891475
-
一、背景 在写项目的过程中,突然发现el-select这个组件,绑定的值没办法显示name,而是直接显示value。在编辑项目的弹框中,要显示项目绑定了哪个数据库(项目外连数据库表主键ID),结果发现直接把关联数据库的ID显示了出来,这与我的设想不一致,因此来找找是什么问题 二、解决 有问题的,有文档的当然第一时间去看文档,一看数据类型是string。 value-key 作为 value 唯一标识的键名,绑定值为对象类型时必填 数据类型string 再去检查项目传值,发现el-option绑定的list中key的类型是string,但v-model绑定的值是int,所以就导致了无法显示正确的名字,而显示主键ID 知道问题解决起来就很简单了,直接parseInt()转一下数据类型 <el-form-item label="归属数据库:" prop="databaseId"> <el-select v-model="projectForm.databaseId" placeholder="归属项目" style="width: 400px"> <el-option v-for="item in databaseList" :key="item.id" :value="parseInt(item.id)" :label="item.name" /> </el-select> </el-form-item> 但是可以的话,还是尽量数据格式一致,如果都是int的话,也是能可以正确显示的,那就无须做额外的处理了 ———————————————— 原文链接:https://blog.csdn.net/weixin_40295575/article/details/124250581
-
前言 最近在开发任务中碰到需要在新增和修改时使用动态加载级联选择器,但是当在修改时设置默认选中项,出现了后端数据返回较慢,导致无法选中和级联框选中了但input框不显示的问题,网上找到的方法也不是很有效,还得使用ref查看组件实例和element-ui cascader源码来寻找解决方法。 完整的实现代码在最后 1. 解决方法 我们知道使用动态加载的级联选择器需要使用lazyLoad函数,那就先开始寻找lazyLoad函数,使用ref查看组件实例,可以看到是在panel下。 再来看看源码,可以发现只需要传入Object数据即可,如:this.$refs.xxx.panel.lazyLoad(val)。 知道了传参和调用,但是传参的参数从哪来?如下图可以看到是从this.$refs.xxx.panel.menus[0]循环比对获取。 如果后端数据返回快的话可以达到要实现的选中效果,如果后端数据返回的较慢就会出现没选中的情况(可以自己在lazyLoad加个一秒延迟测试),这时就需要使用handleExpand(handleExpand也在panel下),并且要在请求结束后执行handleExpand,如何在请求结束时执行handleExpand,我们对代码进行如下修改: 先声明一个waitItemExecution函数并赋给menus[0]循环出的数据,最后在lazyLoad中执行waitItemExecution函数。效果如下图,是不是发现input框没有数据,这还是得去element-ui源码内寻找答案,接着往下看。 当级联选择器选择完毕时,watch下的checkedValue会触发,并执行computePresentContent接着computePresentContent再调用computePresentText。 是不是认为只要对checkedValue进行赋值,input框就有值了?可以试着去查看ref获取的实例下的checkedValue,你会发现已经有值在里面,那为什么没有触发呢?因为!isEqual(val, value)是判断不相等为true,而我们调用的方法不全,导致val和value相等,所以if里面的方法不执行,其实我们只需要调用computePresentText。waitItemExecution函数修改如下: 这样就实现了动态加载级联选择器默认选中的问题。以上的方法只解决了一层和二层的级联情况,超过二层的级联情况不适用,下面将给出最终解决方案代码。 2. 不同层级间的默认选中解决方法 对不同层级的默认选中只需要封装函数并互相调用就可实现(一到N层都可使用),以下是完整代码: <template><div id="app"><el-cascader v-model="current" :props="props" ref="cascader"></el-cascader></div> </template> <script> let id = 0; let list = [{value: '0',}, {value: '1',}, {value: '2',}, {value: '3',}, ] export default {name: 'App',data() {return {current: [],props: {lazy: true,lazyLoad(node, resolve) {const {level} = node;function f() {list = list.map((item, i) => ({label: level ? `${node.value}-${i}` : item.value,value: level ? `${node.value}-${i}` : item.value,leaf: item.value === '2' && level === 0 ? true : `${node.value}-${i}` === '3-2' ? true : level >= 2}))resolve(list)}if (level > 0) {setTimeout(() => {f()node.func && node.func(node)}, 1000)return}f()}}};},mounted() {this.current = ['1', '1-3', '1-3-0']// this.current = ['3', '3-2']// this.current = ['2']// this.current = ['0', '0-2', '0-2-3']for (let item of this.$refs.cascader.panel.menus[0]) {if (item.value === this.current[0]) {this.loadItem(item)return}}},methods: {handleItem(val) {if (val && val instanceof Object) {this.loadItem(val)}},loadItem(val) {val.func = this.waitItemExecutionthis.$refs.cascader.panel.lazyLoad(val)},waitItemExecution(val) {for (let item of val.children) {if (this.current[val.level] === item.value) {this.handleItem(item)break}}this.$refs.cascader.panel.handleExpand(val)this.$refs.cascader.computePresentText()},} } </script> 最后 对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。 ———————————————— 原文链接:https://blog.csdn.net/web22050702/article/details/127299704
-
使用element-ui级联选择器Cascader时遇到的问题。 由于数据量过多,在进行级联选择的时候使用的是动态加载的方式。这一情况在表单中十分常见。正常的级联选择用这一组件十分便捷,但在表单修改编辑时,发现动态加载是无法准确回显的,查阅了很多资料,都比较复杂,这里记录一下我使用的简单方法,如有问题还希望各位大神指正 。因为是动态加载,编辑回显也是需要提前把数据加载出来的,赋值之前列表数据已经有了么? 最后怎么解决了呢?我是听过强制重新渲染来解决的 我的解决方案是偷了个懒,让后台同时给了上次选中的value值和label的值。然后vue文件中data里面新增两个字段来保存,一个是保存value的数组,一个是将label拼接“/”后作为字符串保存起来,当该字符串有值时就把el-cascader的placeholder的值设置为这个字段,并且在placeholder有值时,动态添加一个class将el-cascader中placeholder的字体颜色设置为有输入值的颜色(添加的class >>> .el-input__inner::placeholder { color: #606266;})。想了半天,另辟蹊径,最简单暴力的方法… 捂脸 当然这种操作方式对不开放搜索功能的el-cascader比较友好,反正是动态加载的子节点,搜也搜不出来,如果是加了filterable属性的,一获取焦点的时候placeholder值就没了. 我的解决方案是 编辑状态下用一个el-select回显当前的选择项,当然是要初始化数据的值的, 点击变更, 给这个select隐藏, 把cascader显示出来。 <!--核心是设置key值--><el-cascader :key="resetCascader" v-model="form.orgRank" :props="orgRank" ref='orgRank'></el-cascader>//props: {// userDetailData: {// type: Object,// default: null// }//},data() { return { resetCascader: 0, //记录key值 //其他代码(补充lazyLoad) //orgRank: { // lazy: true, // async lazyLoad (node, resolve) { // const { level } = node // if(!node.data) { // const res = await getOrgList() // const nodes = Array.from(res.data).map(item=>({ // value:item.id, // label:item.name, // leaf: level >= 1 // })) // resolve(nodes) // }else{ // const res = await getOrgRankList(node.data.value) // const nodes = Array.from(res.data).map(item=>({ // value:item.id, // label:item.name, // leaf: level >= 1 // })) // resolve(nodes) // } // } //} }}//watch: {// userDetailData(newValue) {// this.addAndEdit(newValue)// }//},methods: { addAndEdit(userData) { // 通过修改 key 值,实现数据回显,将组件重新渲染 this.resetCascader++ if(userData) { //this.form = { // name: userData.name, // username: userData.username, // email: userData.email, // role: userData.roles[0].id //} this.form.orgRank = [] this.form.orgRank.push(userData.orgId, userData.rank) } },}相关的业务代码已经注释掉了,留下的就是解决这个问题的核心代码了。通过为组件设定key值,使组件重新渲染,监听到需要编辑数据userDetailData的变化后,将key值改变,触发懒加载lazyLoad方法,最后再将数据添加到绑定的v-model中即可。
-
如果你有幸刷到这篇文章,恭喜你,困扰你的问题总算有解决方法了。本篇文章解决你所有级联懒加载回显的问题和修改样式不生效问题。 问题描述: 我的需求是调了三个下拉框接口进行关联。在form表单里进行选择传值都是没问题的。刚开始数据少没有出现问题。第二天数据多了测试提了个bug,三级联动竟然不显示数据了。 然后就是两个周的探索,夜不能寐啊。两个周啊!! 网上给的方法各式各样。甚至有说回显必须有options,使用递归把options的数据填好进行回显。纯属扯淡。 附上代码 html: <el-cascader v-model="data.eventComboBoxValue" :props="cascaderProps" clearable /> js: cascaderProps() { return { lazy: true, lazyLoad: this.lazyLoad }; } methods:{ async lazyLoad(node, resolve) { let level = node.level; let result; switch (level) { case 0: // 类型 let initRes = await eventList(); result = initRes.data.pageResult.list; break; case 1: //一级目录 let firstParams = { upstreamId: node.data.value }; let firstRes = await eventList(firstParams); result = firstRes.data.pageResult.list; break; case 2: // 二级目录 let secondParams = { eventTypeId: node.data.value }; let secondRes = await eventList(secondParams); result = secondRes.data.pageResult.list; result.forEach(item => { item.leaf = level >= 2; }); break; default: result = []; break; } resolve(result); }, } 这样是一般写法,很多小伙伴这样写也不会有问题,但是看下请求数据的列表。某一个列表重复请求了多次。解决方法是在请求前加一层判断,已经有数据了就不要重复请求了。 if (node.children && node.children.length > 0) return; 到了这一步还是没有回显。仔细看你的数据是不是有重复项?比如第一层和第二层id一样?恭喜你,遇到了和我一样的问题。出现问题的原因是。cascader的每一项id都不能重复,否则就不会进行下一层的加载了。和后端商量了几种解决方案。给出最完美的方案。 请求列表的时候多传一个自定义字段,我传的是fromLinkage:1,让后端知道我是在调级联列表,这么做是为了不影响其他模块下拉列表的功能。 然后后端返回一个唯一标识避免重复,我们采用的是拼接列表名称。 把返回的这一项作为你的value值,这样每一层的value都是唯一了。完美解决问题。正常回显。 至此有用过级联el-cascader的伙伴都能解决问题了。那么点赞出门左转,可以摸鱼啦~~ 以下内容偏傻瓜式教学,供尚不能解决问题的新人参考。 综上所述,我点击第二层的时候传参应该传id:3,但是现在传了id:'upstreamid3',因为你原来的value值已经绑定成了后端返回的key。value是从node中拿出来的,那我能不能拿到之前的3传给后端呢?当然可以。 只需在你rosolve的数组里添加一个自定义字段,下一轮你就能从node中拿到你存的flag了! 第二层、第三层请求传给后端。 总结:一般这种回显会出现在编辑、查看弹窗或者路由跳转中,如果你的代码还有问题不能回显。弹窗或者新的页面中中加个v-if每次关闭销毁,获取到详情再创建即可。 如果解决了你的问题请点赞!点赞!让我看看有多少被这个问题折磨的铁子们~~~ 另外新版本的element级联会有一页数据太多展示不下的问题,修改样式竟然没生效,我们会使用的是less,less穿透使用/deep/,scss穿透使用::v-deep。都不生效。 最终解决方案是把scope去掉,成功解决~ 点赞收藏加关注,前端探讨不迷路~~ ———————————————— 原文链接:https://blog.csdn.net/liuwenjie_/article/details/126279731
-
中奖结果公示感谢各位小伙伴参与本次活动,本次活动获奖名单如下:请各位获奖的伙伴在10月16日之前点击此处填写收货地址,如逾期未填写视为弃奖。再次感谢各位小伙伴参与本次活动,欢迎关注华为云DTSE Tech Talk 技术直播更多活动~直播简介【直播主题】0基础玩转OpenTiny跨端跨框架组件库,实现一站式前端进阶【直播时间】2023年10月11日 16:30-18:00【直播专家】莫春辉 华为云前端开发 DTSE技术布道师【直播简介】你还在为构建web页面却不知道选哪个组件库而苦恼吗? 你还在为从Vue2项目升级到Vue3的工作量大而惆怅吗? 你还在为不同框架的组件库由于API不同,需要重复开发而薅头发吗? 本期直播将聚焦于OpenTiny跨端、跨框架、跨版本的TinyVue组件库,其中包含了无渲染Renderless设计理念的实现方式,以及分析业务逻辑的思路及方法。让开发者能够通过一套代码在不同版本、不同框架、不同终端中使用,从而提升开发效率,保证用户在不同场景下的极致交互体验。直播链接:cid:link_1活动介绍【互动方式】直播前您可以在本帖留下您疑惑的问题,专家会在直播时为您解答。直播后您可以继续在本帖留言,与专家互动交流。我们会在全部活动结束后对参与互动的用户进行评选。【活动时间】即日起—2023年10月12日【奖励说明】评奖规则:活动1:直播期间在直播间提出与直播内容相关的问题,对专家评选为优质问题的开发者进行奖励。奖品:华为云定制U型按摩枕活动2:在本帖提出与直播内容相关的问题,由专家在所有互动贴中选出最优问题贴的开发者进行奖励。奖品:华为云定制POLO衫更多直播活动直播互动有礼:官网直播间发口令“华为云 DTSE”抽华为云定制棒球帽、填写问卷抽华为云定制长袖卫衣等好礼分享问卷有礼 :邀请5位朋友以上完成问卷即可获得华为云定制飞盘。老观众专属福利:连续报名并观看DTT直播3期以上抽送华为云DTT定制T恤。【注意事项】1、所有参与活动的问题,如发现为复用他人内容,则取消获奖资格。2、为保证您顺利领取活动奖品,请您在活动公示奖项后2个工作日内私信提前填写奖品收货信息,如您没有填写,视为自动放弃奖励。3、活动奖项公示时间截止2023年10月13日,如未反馈邮寄信息视为弃奖。本次活动奖品将于奖项公示后30个工作日内统一发出,请您耐心等待。4、活动期间同类子活动每个ID(同一姓名/电话/收货地址)只能获奖一次,若重复则中奖资格顺延至下一位合格开发者,仅一次顺延。5、如活动奖品出现没有库存的情况,华为云工作人员将会替换等价值的奖品,获奖者不同意此规则视为放弃奖品。6、其他事宜请参考【华为云社区常规活动规则】。
-
富文本编辑器,如果有旧编辑器,再添加新编辑器,如何实现兼容?
-
在前段代码中引入 weui.css ,weuix.css 和js jquery-weui.min.js就可以使用weui的一些样式了 按照官方的文档中 $.toast("我是文本","text"); 弹出的样式应该如下: 但是我在实际中使用弹出的结果却是这个样子: 为什么 原因肯定是weui的样式和其他的样式冲突了 我们看看 $.toast 这一串代码: t.toast=function(t,a,r) { "function"==typeof a&&(r=a); var o,s="weui-icon-success-no-circle", c=i.duration; "cancel"==a?(o="weui-toast_cancel",s="weui-icon-cancel"):"forbidden"==a?(o="weui-toast--forbidden",s="weui-icon-warn"):"text"==a?o="weui-toast--text":"number"==typeof a&&(c=a), e('<i class="'+s+' weui-icon_toast"></i><p class="weui-toast_content">'+(t||"已经完成")+"</p>",o),setTimeout(function(){n(r)},c)} 大概能看出来 cancel ,forbidden,text 这些都是一些选项,当选择而不同的时候,出现不同的样式 text 应该是没有图标,为什么有图标了 我在页面上设置100,来查看这个样式 可以看到的是图标来源于这一部分 我们选中 i 这个标签,看右侧使用的样式: 果然是其他的样式干扰的 如果我们引入的其他的css作用不大,我们可以找到直接删除了 或者将 important 删除了 因为这次的样式调试用了很长的时间,特此记录 希望对你有所帮助 ———————————————— 原文链接:https://blog.csdn.net/datouniao1/article/details/111311058
-
1. toFixed()方法需注意,保留两位小数,将数值类型的数据改变成了字符串类型2. Math.floor(),不四舍五入 ,向下取整注意,不改变数据类型3. 字符串匹配注意,先将数据转换为字符串,最后再转为数值类型4. 四舍五入保留2位小数(若第二位小数为0,则保留一位小数)注意,数据类型不变5. 四舍五入保留2位小数(不够位数,则用0替补)注意,数据类型变为字符串类型
-
JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。pageContext.request.contextPath 是一个在JSP页面中使用的表达式,用于获取当前Web应用程序的上下文路径。 具体解释如下: pageContext 是一个隐含对象,可以在JSP页面中直接使用,它提供了对页面上下文的访问。通过pageContext对象,可以获取当前页面的请求对象(request)、响应对象(response)、会话对象(session)等。 request 是pageContext对象的一个属性,它代表当前页面的HTTP请求对象。通过request对象,可以获取关于当前请求的各种信息,例如请求参数、请求头、会话状态等。 contextPath 是request对象的一个属性,它代表当前Web应用程序的上下文路径。上下文路径是Web应用程序在服务器上部署的根路径,它可以是目录名或虚拟目录。例如,如果应用程序的上下文路径为/myapp,那么contextPath的值就是/myapp。 所以,pageContext.request.contextPath 表达式的作用就是获取当前Web应用程序的上下文路径。它通常用于构建相对路径或完整URL,确保生成的链接或表单操作与当前应用程序的部署路径保持一致。 ${pageContext.request.contextPath}是JSP取得绝对路径的方法,等价于<%=request.getContextPath()%> 。 也就是取出部署的应用程序名或者是当前的项目名称。 比如我的项目名称是SSM在浏览器中输入为 http://localhost:8080/SSM/index.jsp ${pageContext.request.contextPath}或<%=request.getContextPath()%>取出来的就是/SSM, 而"/"代表的含义就是 http://localhost:8080 可以使用el表达式,方法一: <c:set var="basePath" value="${pageContext.request.contextPath}"/> 然后获取这个值: ${basePath} 可以使用el表达式,方法二: <c:set var="basePath" value="<%=request.getContextPath()%>"/> 然后获取这个值: ${basePath} 把绝对路径的值以key-value 的形式存在请求范围,可以直接使用{basePath}取出 ———————————————— 版权声明:本文为CSDN博主「茂念」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_43802688/article/details/89532658
-
js的简介 JavaScript(简称“JS”)是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式。 [1] JavaScript在1995年由Netscape公司的Brendan Eich,在网景导航者浏览器上首次设计实现而成。因为Netscape与Sun合作,Netscape管理层希望它外观看起来像Java,因此取名为JavaScript。但实际上它的语法风格与Self及Scheme较为接近。 [2] JavaScript的标准是ECMAScript。截至2012年,所有浏览器都完整的支持ECMAScript 5.1,旧版本的浏览器至少支持ECMAScript 3标准。2015年6月17日,ECMA国际组织发布了ECMAScript的第六版,该版本正式名称为ECMAScript 2015,但通常被称为ECMAScript 6或者ES2015。 在WEB开发中,时常会用到javascript来获取当前页面的url网址信息,在这里是我的一些获取url信息的小总结。 下面我们举例一个URL,然后获得它的各个组成部分:http://i.jb51.net/EditPosts.aspx?opt=1 1、window.location.href(设置或获取整个 URL 为字符串) var test = window.location.href; alert(test); 返回:http://i.jb51.net/EditPosts.aspx?opt=1 2、window.location.protocol(设置或获取 URL 的协议部分) var test = window.location.protocol; alert(test); 返回:http: 3、window.location.host(设置或获取 URL 的主机部分) var test = window.location.host; alert(test); 返回:i.jb51.net 4、window.location.port(设置或获取与 URL 关联的端口号码) var test = window.location.port; alert(test); 返回:空字符(如果采用默认的80端口(update:即使添加了:80),那么返回值并不是默认的80而是空字符) 5、window.location.pathname(设置或获取与 URL 的路径部分(就是文件地址)) var test = window.location.pathname; alert(test); 返回:/EditPosts.aspx 6、window.location.search(设置或获取 href 属性中跟在问号后面的部分) var test = window.location.search; alert(test); 返回:?opt=1 PS:获得查询(参数)部分,除了给动态语言赋值以外,我们同样可以给静态页面,并使用javascript来获得相信应的参数值。 7、window.location.hash(设置或获取 href 属性中在井号“#”后面的分段) var test = window.location.hash; alert(test); 返回:空字符(因为url中没有) 8、js获取url中的参数值 一、正则法 function getQueryString(name) { var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); var r = window.location.search.substr(1).match(reg); if (r != null) { return unescape(r[2]); } return null; } // 这样调用: alert(GetQueryString("参数名1")); alert(GetQueryString("参数名2")); alert(GetQueryString("参数名3")); 二、split拆分法 function GetRequest() { var url = location.search; //获取url中"?"符后的字串 var theRequest = new Object(); if (url.indexOf("?") != -1) { var str = url.substr(1); strs = str.split("&"); for(var i = 0; i < strs.length; i ++) { theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]); } } return theRequest; } var Request = new Object(); Request = GetRequest();<br>// var id=Request["id"]; // var 参数1,参数2,参数3,参数N; // 参数1 = Request['参数1']; // 参数2 = Request['参数2']; // 参数3 = Request['参数3']; // 参数N = Request['参数N']; 三、指定取 比如说一个url:http://i.jb51.net/?j=js,我们想得到参数j的值,可以通过以下函数调用。 function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配 var context = ""; if (r != null) context = r[2]; reg = null; r = null; return context == null || context == "" || context == "undefined" ? "" : context; } alert(GetQueryString("j")); 四、单个参数的获取方法 function GetRequest() { var url = location.search; //获取url中"?"符后的字串 if (url.indexOf("?") != -1) { //判断是否有参数 var str = url.substr(1); //从第一个字符开始 因为第0个是?号 获取所有除问号的所有符串 strs = str.split("="); //用等号进行分隔 (因为知道只有一个参数 所以直接用等号进分隔 如果有多个参数 要用&号分隔 再用等号进行分隔) alert(strs[1]); //直接弹出第一个参数 (如果有多个参数 还要进行循环的) } } javascript 获取当前 URL 参数的两种方法 //返回的是字符串形式的参数,例如:class_id=3&id=2& function getUrlArgStr(){ var q=location.search.substr(1); var qs=q.split('&'); var argStr=''; if(qs){ for(var i=0;i<qs.length;i++){ argStr+=qs[i].substring(0,qs[i].indexOf('='))+'='+qs[i].substring(qs[i].indexOf('=')+1)+'&'; } } return argStr; } //返回的是对象形式的参数 function getUrlArgObject(){ var args=new Object(); var query=location.search.substring(1);//获取查询串 var pairs=query.split(",");//在逗号处断开 for(var i=0;i<pairs.length;i++){ var pos=pairs[i].indexOf('=');//查找name=value if(pos==-1){//如果没有找到就跳过 continue; } var argname=pairs[i].substring(0,pos);//提取name var value=pairs[i].substring(pos+1);//提取value args[argname]=unescape(value);//存为属性 } return args;//返回对象 } 另外列出一些 javascript 获取url中各个部分的功能方法: window.location.host; //返回url 的主机部分,例如:www.xxx.com window.location.hostname; //返回www.xxx.com window.location.href; //返回整个url字符串(在浏览器中就是完整的地址栏),例如:www.xxx.com/index.php?class_id=3&id=2 window.location.pathname; //返回/a/index.php或者/index.php window.location.protocol; //返回url 的协议部分,例如: http:,ftp:,maito:等等。 window.location.port //url 的端口部分,如果采用默认的80端口,那么返回值并不是默认的80而是空字符 以上就是本文的全部内容,希望对大家理解如何获取当前页面url网址信息有所帮助。 原文链接:https://www.jb51.net/article/82519.htm
-
PM:喂,那个切图仔,我这里有个100G的视频要上传,你帮我做一个上传后台,下班前给我哦,辛苦了。 我:。。。 相信每个切图工程师,都接触过文件上传的需求,一般的小文件,我们直接使用 input file,然后构造一个 new FormData()对象,扔给后端就可以了。如果使用了 Ant design 或者 element ui 之类的ui库,那更简单,直接调用一下api即可。当然了,复杂一些的,市面上也有不少优秀的第三方插件,比如WebUploader。但是作为一个有追求的工程师,怎么能仅仅满足于使用插件呢,今天我们就来自己实现一个。 首先我们来分析一下需求 一个上传组件,需要具备的功能: 需要校验文件格式 可以上传任何文件,包括超大的视频文件(切片) 上传期间断网后,再次联网可以继续上传(断点续传) 要有进度条提示 已经上传过同一个文件后,直接上传完成(秒传) 前后端分工: 前端: 文件格式校验 文件切片、md5计算 发起检查请求,把当前文件的hash发送给服务端,检查是否有相同hash的文件 上传进度计算 上传完成后通知后端合并切片 后端: 检查接收到的hash是否有相同的文件,并通知前端当前hash是否有未完成的上传 接收切片 合并所有切片 架构图如下 接下来开始具体实现 一、 格式校验 对于上传的文件,一般来说,我们要校验其格式,仅需要获取文件的后缀(扩展名),即可判断其是否符合我们的上传限制: //文件路径 var filePath = "file://upload/test.png"; //获取最后一个.的位置 var index= filePath.lastIndexOf("."); //获取后缀 var ext = filePath.substr(index+1); //输出结果 console.log(ext); // 输出:png 但是,这种方式有个弊端,那就是我们可以随便篡改文件的后缀名,比如:test.mp4 ,我们可以通过修改其后缀名:test.mp4 -> test.png ,这样即可绕过限制进行上传。那有没有更严格的限制方式呢?当然是有的。 那就是通过查看文件的二进制数据来识别其真实的文件类型,因为计算机识别文件类型时,并不是真的通过文件的后缀名来识别的,而是通过 “魔数”(Magic Number)来区分,对于某一些类型的文件,起始的几个字节内容都是固定的,根据这几个字节的内容就可以判断文件的类型。借助十六进制编辑器,可以查看一下图片的二进制数据,我们还是以test.png为例:由上图可知,PNG 类型的图片前 8 个字节是 0x89 50 4E 47 0D 0A 1A 0A。基于这个结果,我们可以据此来做文件的格式校验,以vue项目为例: <template> <div> <input type="file" id="inputFile" @change="handleChange" /> </div> </template> <script> export default { name: "HelloWorld", methods: { check(headers) { return (buffers, options = { offset: 0 }) => headers.every( (header, index) => header === buffers[options.offset + index] ); }, async handleChange(event) { const file = event.target.files[0]; // 以PNG为例,只需要获取前8个字节,即可识别其类型 const buffers = await this.readBuffer(file, 0, 8); const uint8Array = new Uint8Array(buffers); const isPNG = this.check([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); // 上传test.png后,打印结果为true console.log(isPNG(uint8Array)) }, readBuffer(file, start = 0, end = 2) { // 获取文件的二进制数据,因为我们只需要校验前几个字节即可,所以并不需要获取整个文件的数据 return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { resolve(reader.result); }; reader.onerror = reject; reader.readAsArrayBuffer(file.slice(start, end)); }); } } }; </script> 以上为校验文件类型的方法,对于其他类型的文件,比如mp4,xsl等,大家感兴趣的话,也可以通过工具查看其二进制数据,以此来做格式校验。 以下为汇总的一些文件的二进制标识: 1.JPEG/JPG - 文件头标识 (2 bytes): ff, d8 文件结束标识 (2 bytes): ff, d9 2.TGA - 未压缩的前 5 字节 00 00 02 00 00 - RLE 压缩的前 5 字节 00 00 10 00 00 3.PNG - 文件头标识 (8 bytes) 89 50 4E 47 0D 0A 1A 0A 4.GIF - 文件头标识 (6 bytes) 47 49 46 38 39(37) 61 5.BMP - 文件头标识 (2 bytes) 42 4D B M 6.PCX - 文件头标识 (1 bytes) 0A 7.TIFF - 文件头标识 (2 bytes) 4D 4D 或 49 49 8.ICO - 文件头标识 (8 bytes) 00 00 01 00 01 00 20 20 9.CUR - 文件头标识 (8 bytes) 00 00 02 00 01 00 20 20 10.IFF - 文件头标识 (4 bytes) 46 4F 52 4D 11.ANI - 文件头标识 (4 bytes) 52 49 46 46 二、 文件切片 假设我们要把一个1G的视频,分割为每块1MB的切片,可定义 DefualtChunkSize = 1 * 1024 * 1024,通过 spark-md5来计算文件内容的hash值。那如何分割文件呢,使用文件对象File的方法File.prototype.slice即可。 需要注意的是,切割一个较大的文件,比如10G,那分割为1Mb大小的话,将会生成一万个切片,众所周知,js是单线程模型,如果这个计算过程在主线程中的话,那我们的页面必然会直接崩溃,这时,就该我们的 Web Worker 来上场了。 Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。具体的作用,不了解的同学可以自行去学些一下。这里就不展开讲了。 以下为部分关键代码: // upload.js // 创建一个worker对象 const worker = new worker('worker.js') // 向子线程发送消息,并传入文件对象和切片大小,开始计算分割切片 worker.postMessage(file, DefualtChunkSize) // 子线程计算完成后,会将切片返回主线程 worker.onmessage = (chunks) => { ... } 子线程代码: // worker.js // 接收文件对象及切片大小 onmessage (file, DefualtChunkSize) => { let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice, chunks = Math.ceil(file.size / DefualtChunkSize), currentChunk = 0, spark = new SparkMD5.ArrayBuffer(), fileReader = new FileReader(); fileReader.onload = function (e) { console.log('read chunk nr', currentChunk + 1, 'of'); const chunk = e.target.result; spark.append(chunk); currentChunk++; if (currentChunk < chunks) { loadNext(); } else { let fileHash = spark.end(); console.info('finished computed hash', fileHash); // 此处为重点,计算完成后,仍然通过postMessage通知主线程 postMessage({ fileHash, fileReader }) } }; fileReader.onerror = function () { console.warn('oops, something went wrong.'); }; function loadNext() { let start = currentChunk * DefualtChunkSize, end = ((start + DefualtChunkSize) >= file.size) ? file.size : start + DefualtChunkSize; let chunk = blobSlice.call(file, start, end); fileReader.readAsArrayBuffer(chunk); } loadNext(); } 以上利用worker线程,我们即可得到计算后的切片,以及md5值。 三、 断点续传+秒传+上传进度计算 在拿到切片和md5后,我们首先去服务器查询一下,是否已经存在当前文件。 如果已存在,并且已经是上传成功的文件,则直接返回前端上传成功,即可实现"秒传"。 如果已存在,并且有一部分切片上传失败,则返回给前端已经上传成功的切片name,前端拿到后,根据返回的切片,计算出未上传成功的剩余切片,然后把剩余的切片继续上传,即可实现"断点续传"。 如果不存在,则开始上传,这里需要注意的是,在并发上传切片时,需要控制并发量,避免一次性上传过多切片,导致崩溃。 // 检查是否已存在相同文件 async function checkAndUploadChunk(chunkList, fileMd5Value) { const requestList = [] // 如果不存在,则上传 for (let i = 0; i < chunkList; i++) { requestList.push(upload({ chunkList[i], fileMd5Value, i })) } // 并发上传 if (requestList?.length) { await Promise.all(requestList) } } // 上传chunk function upload({ chunkList, chunk, fileMd5Value, i }) { current = 0 let form = new FormData() form.append("data", chunk) //切片流 form.append("total", chunkList.length) //总片数 form.append("index", i) //当前是第几片 form.append("fileMd5Value", fileMd5Value) return axios({ method: 'post', url: BaseUrl + "/upload", data: form }).then(({ data }) => { if (data.stat) { current = current + 1 // 获取到上传的进度 const uploadPercent = Math.ceil((current / chunkList.length) * 100) } }) } 在以上代码中,我们在上传切片的同时,也会告诉后端当前上传切片的index,后端接收后,记录该index以便在合并时知道切片的顺序。 当所有切片上传完成后,再向后端发送一个上传完成的请求,即通知后端把所有切片进行合并,最终完成整个上传流程。 大功告成!由于篇幅有限,本文主要讲了前端的实现思路,最终落地成完整的项目,还是需要大家根据真实的项目需求来实现。 ———————————————— 版权声明:本文为CSDN博主「大转转FE」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/P6P7qsW6ua47A2Sb/article/details/125175992
-
1. 场景描述:因为生产环境组件服务进程执行缓慢导致部分资源无法释放,进而引起了各种任务超时。研究源码发现,部分执行过长的是操作都是在单线程中串行 。这就意味着,单个过程的执行效率会影响到整个流程的调度周期。为此,我们需要对部分组件源码进行改造,串行改并行。串行改并行,我们要小心流程执行顺序之间的依赖关系和各个线程对共享变量的读写。这里的前提是我们得知道改哪里。其实我们的需求很明确,执行过程耗时长的我们优先改造,也就是我们需要找到组件的性能瓶颈。但是如何确认呢?最终,我是通过火焰图观察,找出了耗时比较长的过程。下面记录一下这个过程,以便日后需要的时候可以有所帮助。 2. 火焰图火焰图是通过可交互的图片反映出程序执行过程中的调用栈和大致的CPU占用百分比。在火焰图中,顺着Y轴从下往上看表示的是调用顺序,高度表示的就是调用栈的深度。顺着X轴看,一个方法的长度表示的就是这个方法的被抽到的样本数,被抽到的次数越多,占用的CPU时间就越长。当把鼠标放在一个方法上时,会显示一段说明,例如(5222 samples, 7.6%),这个表示的就是,这个方法在采样期间被采样了5222次,占用总样本的7.6%。注意X轴不表示时间,不是说左边的方法一定在右边之前执行。火焰图应该是高低起伏的,如果都是很宽的平顶,那程序性能就需要重新评测了。另外,火焰图的颜色没有任何含义。火焰图是可交互的,在浏览器中我们打开火焰图之后可以直接CTRL+F进行搜索。输入完整的方法名或者正则表达式之后,所有匹配到的方法都是高亮显示出来。 单击这些高亮部分就会放大这一部分,显示选中方法的子方法(被调用的方法)。这样就可以在这张图中搜索自己想要确认的模块,然后找到比较宽的部分,定位到代码,确定是否可以修改。 3. 生成火焰图3.1 工具火焰图生成工具:javaPfro.zip 提取码:76o9这个工具包解压之后会用两个文件夹:async-profiler-master FlameGraph-master文件夹下部分可执行文件,可能需要755权限。这里不做一一声明,直接更改文件夹下所有文件的权限。chmod -R 755 async-profiler-master/*chmod -R 755 FlameGraph-master/*3.2 操作步骤火焰图只是以图片形式展示出了CPU中的调用栈,实际的数据还是需要从CPU中采集。所以生成火焰图共分为两步:采样和生成svg图。3.2.1 采样采样使用async-profiler-master工具,具体命令如下:./async-profiler-master/profiler.sh -d 10 -o collapsed -f /tmp/collapsed.txt 1234以上命令表示的意思是,采样时间为10秒,采样得到的数据重定向到/tmp/collapsed.txt,被采样进程id为1234。 3.2.2 生成svg图根据采样数据生成svg图,使用的是FlameGraph-master,具体命令如下:./FlameGraph-master/flamegraph.pl --colors=java /tmp/collapsed.txt > flamegraph.svg命令表示的意思是把/tmp/collapsed.txt这个文件转换svg火焰图,文件名为flamegraph.svg。然后,把这个文件拉到window环境下,用浏览器就可以打开了。这里我用的是chrome浏览器。 4. 分析火焰图分析火焰图一般需要先确定需要分析的类或方法名,或者代码入口方法,或者入口类。这样我们可以先定位到一个方法调用,再分析其调用栈。例如,在这张图片中,我确定的方法是定义在CoordinatorRunnable类中的,就可以直接搜索这个类。定位到这个类我们可以明显地看到有三个方法占用了大部分的时间。再继续追踪调用栈。可以看出,耗时大部分都花费在集合元素的比较上。这里我们如果需要优化的话,可以考虑一下比较器的逻辑或者可以根据场景判断一下是否可以选择其他的集合等等。转自 https://zhuanlan.zhihu.com/p/96245085
上滑加载中
推荐直播
-
一键部署DeepSeek大模型,解锁AI智能未来
2025/02/17 周一 16:00-17:00
华为云讲师团
云上体验DeepSeek大模型,用AI加速行业应用场景重塑,满足企业级业务需求
回顾中 -
DeepSeek华为云全栈解决方案
2025/02/18 周二 16:30-17:30
Young-华为云公有云解决方案专家
如何让大模型发挥更大能量助力业务?本期课程以真实案例展开,带您深入探索如何构建更完整的AI解决方案。
即将直播
热门标签