2022-6-12 130 3
Vue

1.优化前先分析依赖//首先安装依赖npminstallwebpack-bundle-analyzer--save-dev//然后在vue.config.js中进行引入constBundleAnalyzerPlugin=require('webpack-bundle-analyzer').BundleAnalyzerPlugin;//然后添加如下代码configureWebpack:{plugins:[newBundleAnalyzerPlugin({analyzerMode:'server',analyzerHost:'127.0.0.1',analyzerPort:8888,reportFilename:'report.html',defaultSizes:'parsed',openAnalyzer:true,generateStatsFile:false,statsFilename:'stats.json',statsOptions:null,logLevel:'info'}),]}当打包或者运行时,会在本地8888端口展示依赖情况,然后自行分析。2.采用路由懒加载在写路由时,不要将所有的组件都一下加载全,应该使用import()进行懒加载。这样只有当访问这个路由时,才会加载对应的模块。cosntroutes=[{path:"/home",component:()=>import('@/view/Home')//使用import进行懒加载}];3.进行GZIP压缩需要在Webpack中构建gz文件,然后在Nginx中启用gzip。//首先安装依赖npminstallcompression-webpack-plugin@1.1.12//然后在vue.config.js中进行引入constCompressionWebpackPlugin=require('compression-webpack-plugin');//然后添加以下代码configureWebpack:{plugins:[newCompressionWebpackPlugin({filename:'[path].gz[query]',algorithm:'gzip',test:/\.js$|\.json$|\.css/,threshold:10240,//只有大小大于该值的资源会被处理minRatio:0.8,//只有压缩率小于这个值的资源才会被处理})]}然后在Nginx中进行以下配置,启用GZIP。#开启gzip。gzipon;#开启后如果能找到.gz文件,直接返回该文件,不会启用服务端压缩。gzip_staticon;#文件大于指定size才压缩,以kb为单位。gzip_min_length1;#用于识别http协议的版本,早期的浏览器不支持gzip压缩,用户会看到乱码,所以为了持前期版本加了此选项,目前此项基本可以忽略gzip_http_version1.1;#压缩级别,1-9,值越大压缩比越大,但更加占用CPU,且压缩效率越来越低。gzip_comp_level9;#压缩的文件类型。gzip_typestext/cssapplication/javascriptapplication/json;使用CDN引入资源在打包时,会将import导入的东西,打包成js文件,然后该文件就会很大.如果我们的服务器带宽很小,那么还要加载这些资源就很慢,这样的话我们可以使用cdn的方式,去让用户请求其他服务器获取资源。我们需要在index.html中进行使用link或者script标签的方式去引入对应的资源。然后在vue.config.js中进行配置。//Key:和package中的名称一样,value:全局变量名//一定要将Vue引入[通过cdn,也要在这里进行配置],因为有些文件依赖着它。configureWebpack:{externals:{'vue':"Vue",'element-ui':"ELEMENT",'axios':'axios','jquery':'$','vue-router':'VueRouter','vuex':'Vuex'}}

2022-5-30 122 0
2022-5-28 74 0
Vue

1.安装npminstallvee-validate@2.0.02.引入该插件需要使用Vue.use引入,我们可以新建一个plugin文件夹,然后在里面进行引入。importVuefrom'vue';importVeeValidatefrom'vee-validate';此时,我们还没使用Vue.use()进行引入,我们可以先进行配置。constconfig={errorBagName:'errors',//为收集错误的对象起一个变量名,它存在每个组件的this中,如果和页面中的产生冲突,则可以更改这里delay:100,//表示获取输入信息的时间[毫秒]locale:'zh_CN',//验证消息的默认语言,一定要将这里写成zh_CN,否则自定义验证规则返回的验证消息是英文的。strict:true,//表示没有设置规则的表单不进行验证events:'input',//默认[input],input表示当输入时和表单失去焦点时都进行验证,blue表示当失去焦点时在验证。};然后进行引入。Vue.use(VeeValidate,config);3.基本使用此时,我们只能使用vee-validate提供的内置验证规则,用法如下。<!--1.我们必须为表单提供一个name属性,否则vee-validate不知道这个表单是哪一个。2.需要使用v-validate指令,来选择验证规则,我们可以输入单个也可以输入多个,可以使用字符串也可以使用对象形式。2.1(重要):如果使用字符串的方式,则需要在最""里面再写一个单引号将规则包住,否则会将规则名当成一个变量,第一个就是这样。--><inputname="age"v-validate="'required'"->单个规则写法v-validate="'required|between:1,120'"->多个规则写法,每个规则使用|管道符分隔v-validate="{required:true,between:[1,120]}"->对象写法,将需要的规则置true即可,此时不需要在里面包一层单引号了,如果其中的值是多个[例如between],则将值写成数组即可。/><!--1.这里是提示错误信息的,当使用该插件后,每个组件上都拥有了一个errors的计算属性[在config中可以修改该变量名]。2.errors是一个数组,里面存储的是错误信息,我们通过v-show来控制它是否显示,如果没有错误has()则返回一个false,那么该span就不显示。3.如果有错误了,那么has()则会返回一个true,那么我们就通过first()方法,拿到errors数组中的第一条错误信息来展示。4.注意(重要):在has()以及first()中,函数的参数值,都需要填写你校验关联表单的name值。--><spanclass="error-msg"v-show="errors.has('age')">{{errors.first('age')}}</span>所有内置规则:after{target}-比target要大的一个合法日期,格式(DD/MM/YYYY)alpha-只包含英文字符alpha_dash-可以包含英文、数字、下划线、破折号alpha_num-可以包含英文和数字before:{target}-和after相反between:{min},{max}-在min和max之间的数字confirmed:{target}-必须和target一样date_between:{min,max}-日期在min和max之间date_format:{format}-合法的format格式化日期decimal:{decimals?}-数字,而且是decimals进制digits:{length}-长度为length的数字dimensions:{width},{height}-符合宽高规定的图片email-不解释ext:[extensions]-后缀名image-图片in:[list]-包含在数组list内的值ip-ipv4地址max:{length}-最大长度为length的字符mimes:[list]-文件类型min-max相反mot_in-in相反numeric-只允许数字regex:{pattern}-值必须符合正则patternrequired-不解释size:{kb}-文件大小不超过url:{domain?}-(指定域名的)url4.将验证消息修改为中文我们首先将中文包引入进来,也需要将vee-validate下的Validator通过{Validator}方式引入进来。importzh_CNfrom'vee-validate/dist/locale/zh_CN';importVeeValidate,{Validator}from'vee-validate';//把这个代码,将最顶部相同的代码替换掉即可。然后创建一个对象:dict,该对象里有一个messages属性[值也是对象]。然后使用VeeValidate.Validator.localize(语言,dict对象)方法进行调用即可。vardict={messages:{...zh_CN.messages}};VeeValidate.Validator.localize("zh_CN",dict);5.修改字段名:此时,返回的验证消息显示的是phone,我们应该将它替换成显示手机号。我们只需要在dict对象中添加以下属性:attributes[它的值也是一个对象]。该对象中的key,就是你input中对应的name属性值。vardict={messages:{...zh_CN.messages,//在这里可以进行重写required:(field,args)=>`${filed}是一个必填内容!`},attributes:{phone:"手机号",code:"验证码"}};6.自定义验证规则:使用Validator.extend(规则名称,规则配置对象)方法可以自定义验证规则。在对象中,一共有两个必须定义的属性,它们都是一个函数。getMessage(field,args):返回的错误信息。field:字段名称,使用的是dict.attributes中的。args:在规则后携带的值。validate(value,args):验证规则,必须返回一个true或者false,或者是Promise实例。value:控件内输入的内容。该函数如果返回的是true,则代表着验证通过。该函数如果返回的是false,则代表不通过,那么就会执行getMessages函数,进行返回错误信息。//手机号验证规则Validator.extend('mobile',{getMessage:field=>`${field}格式不正确!`,validate:value=>/^[1][3-9][\d]{9}$/.test(value)//test是验证正则的,通过返回true});7.提交时验证是否通过在我们提交表单时,应该去判断所有字段都已经验证通过了。/*在提交时,应该先调用该方法,如果都已经验证通过,则返回一个true,否则返回false。*/constvaliRes=awaitthis.$validator.validateAll();if(!valiRes)return;//.......

2022-5-28 67 0
Vue

事件委托1.需求:在三级联动菜单中,我们一共有一千多个内容,并且需要点击其中的一个内容,就需要去跳转路由。2.解决分析:在渲染时为组件绑定上@click事件、使用事件委托。3.分析绑定@click:如果为每一个内容都绑定一个@click,那么就相当于添加了一千多个回调函数,对性能很不友好,但是可以实现功能。4.分析事件委托:如果我们为三级联动菜单的父元素添加一个点击事件,同样,也可以解决该问题,并且,采用该方式只需要添加一个@click,通过查找触发源去判断执行哪些操作。在JavaScript中,拥有事件冒泡的机制,当点击一个子元素时,触发父元素的事件,然后在爷爷元素触发事件,直到触发到祖元素的事件。在祖元素的点击事件回调函数中,拥有一个event属性,该属性是一个对象,里面有一个target属性,该属性存储的就是触发源头的DOM信息,这样就知道点击的哪个元素,从而触发了祖元素的事件。然后我们在通过自定义属性或者标签名,去判断该执行哪些操作。5.事件委托和事件冒泡:事件委托是利用事件冒泡的机制,它们并不一样。6.事件委托的缺点:如果在向上冒泡时,突然被某一层给把事件冒泡阻止掉了[event.stopPropagation],那么就不会冒泡到祖元素了,接着事件委托对应的处理函数也就不会执行了。对于不支持冒泡的事件,无法向上级传递。

2022-5-3 55 0
Vue

1.说明在编程式路由导航当中,如果重复点击一个链接[路由导航],那么就会抛出一个NavigationDuplicated异常,该异常并不会影响我们的程序执行。在声明式路由导航中,不会出现这种情况。这种情况只会在vue-router@3.1.0+版本出现,因为它引入了primise。目前@3.1.1版本,官方已经修复了此问题。2.为什么会出现这样的错误router.push(location,onComplete?,onAbort?)router.replace(location,onComplete?,onAbort?)以上是路由跳转的两个函数,注意看它的第二个和第三个参数,在官方文档中是这么写的:当导航跳转成功完成之后,会执行onComplete回调,它相当于resolve。当导航到相同的路由,或者此次路由未导航成功之前,又导航到其他路由时就会执行onAbort回调,它相当于reject。在@3.1.0+后,可以省略这两个参数,如果忽略了,那么就会返回一个Promise。如果填写了这两个参数,返回的就是undefined。那么,当没有传递第二个和第三个参数时,并且点击的是同一个导航,就会返回reject。当返回reject后,我们并未捕获这个错误,然后控制台就会报红。解决办法【3.3为最优方法】3.0:降级处理,使用#3.1.1版本。3.1:在调用方法时,传递上第二个和第三个参数。this.$router.push("/search",()=>{},()=>{});3.2:在push后链式调用catch()方法,捕获错误。注意:不能使用try…catch的形式去捕获,这种捕获方式只能捕获同步方法的错误。this.$router.push("/search").catch((err)=>{});3.3:对push和replace方法进行二次封装,在router->index.js中封装即可。//保存一份原有的方法letoriginPush=VueRouter.prototype.push;letoriginReplace=VueRouter.prototype.replace;//修改原型上的函数内容,如果传递了resolve和reject则使用传递的,否则默认处理内容为空//在调用原有的push时[相当于调用上面保存的那一份],应该让VueRouter实例调用,应该修改上下文。VueRouter.prototype.push=function(location,resolve,reject){if(resolve&&reject){originPush.call(this,resolve,reject)}else{originPush.call(this,location,(res)=>{},(err)=>{});}}VueRouter.prototype.replace=function(location,resolve,reject){if(resolve&&reject){originReplace.call(this,resolve,reject)}else{originReplace.call(this,location,(res)=>{},(err)=>{});}}

Vue

.sync修饰符:注意:该修饰符在Vue3.0版本中已经取消了,被替换成了v-model。1、简介:在一般情况下,当父组件给子组件传递一个自定义属性后,例如传递的自定义属性是一个字符串,那么我们在子组件中是不可以直接进行修改的,如果修改的话,就会报错。但是我们可以在父组件中为这个子组件的实例上绑定一个自定义事件,当子组件触发该自定义事件时,在去修改父组件中的数据,从而达到想要的效果。当我们使用.sync修饰符时,就相当于为被传递的自定义属性值,添加了一个双向绑定,从而就可以在子组件中,去直接修改父组件中的数据。2、未使用.sync修饰符修改父组件数据:顺序:首先在父组件中,为子组件传递数据,以及绑定自定义事件(changeText)。然后点击子组件中的按钮,触发自身实例上的自定义事件,从而修改父元素数据。页面:在父组件中,为子组件传递数据,以及绑定自定义事件。在changeText事件中,$event的值是$emit()触发事件时传递的值,然后这个值,就赋值给data中的text了,从而达到了子给父传值的效果。<divid="app"><test:prop-text='text'@changeText='text=$event'></test></div>子组件:接收父组件传递的自定义属性,在点击按钮时,触发changeText事件,并携带值。lettest={template:`<div><p>{{propText}}</p><button@click='changeText'>修改propText</button></div>`,props:["propText"],methods:{changeText(){this.$emit("propText","text的值被子组件修改咯!~");}}}父组件:注册子组件。constvm=newVue({el:"#app",data:{text:"我现在展示的是App组件的内容~"},components:{test},});3、使用.sync修饰符修改父组件数据-传递字符串:页面:对比第2行代码:在:prop-text后添加了.sync修饰符。并且将绑定的自定义事件删除了。<divid="app"><test:prop-text.sync='text'></test></div>子组件:对比第10行代码,触发的事件名需要写成以下格式,其中update:是固定的。update:在props中接收的属性名当触发该事件时,就会去寻找组件自身实例上prop-text属性绑定的值,然后去修改它。lettest={template:`<div><p>{{propText}}</p><button@click='changeText'>修改propText</button></div>`,props:["propText"],methods:{changeText(){this.$emit("update:propText","text的值被子组件修改咯!~");}}}父组件:constvm=newVue({el:"#app",data:{text:"我现在展示的是App组件的内容~"},components:{test},});

2022-4-1 498 0
Vue

0x01-工作原理:0、State:它是一个对象,里面存储的是N个组件共享的数据。1、VueComponents:一堆组件,这些组件需要共享State中的数据。2、dispatch():这是一个API,当调用它之后,就会进入Actions这个步骤。参数:①:执行的函数名,假设这里的函数是add,然后就会去Actions对象中去匹配这个add函数。②:为这个函数参数传递的数据,假设这里的参数是1。2.1、Actions:它里面存储的是一个对象,这个对象中,全是函数,这些函数是要我们自己写的,既然在dispatch()中选择了add函数,那么在这个对象中肯定是要写一个add函数的。并且在这个对象中,函数可以接收到两个参数:①:context->(上下文)。②:value->(就是dispatch()传递的第二个参数:1)。然后我们需要在这个函数中,使用context属性来调用commit()函数。在调用commit()函数时,需要为该函数传递两个参数,请看下面。3、commit():当使用context上下文属性调用commit()方法后,就会进入Mutations这个步骤。在调用commit()函数时,需要为该函数传递两个参数:①:调用Mutations中的哪个函数,肯定是add。②:传递的参数,一般就是Actions中的value属性。3.1、Mutations:它里面存储的也是一个对象,它存储是也是全是函数,这些函数也是我们自己添加的。我们在commit()中选择调用add函数,那么该对象中肯定也要有一个add()函数的。在这个对象中的方法,也可以接收到两个参数:①:state对象。②:value,也就是commit传递的第二个属性。然后,我们就可以在这个函数中直接操作state对象中的属性了。4、render:当State中的属性值发生变化时,就会重新帮我们解析组件。5、Actions和Mutations的区别:如果在调用dispatch()函数时,我们不知道传递一个什么数据,必须要请求后端的接口才能知道传递什么,那么我们就需要在Actions对象中的函数中请求后端接口,然后在调用commit()。或者我们需要进行延时操作,在500毫秒之后在操作State对象中的数据,那么就需要在Actions对象中的函数中进行延时操作,在500毫秒之后直接调用commit()进行操作State对象。那么也就发现,如果有逻辑业务层操作的话,都是在Actions对象函数中完成业务逻辑。而Mutations中的函数,是不要进行业务逻辑的,它负责的就是最终修改State中的数据。如果我们知道初始传递一个什么数据,则可以不进行Actions这一步,直接调用commit()进行Mutations这一步进行修改数据即可。并且它们的函数名也应该有所区分,在Actions中的函数进行小写,而在Mutations中的函数进行大写。6、总结:如果知道初始数据,并且不需要业务逻辑,则可以让组件直接调用commit()函数。如果需要业务处理,则必须让组件调用dispatch()函数,然后在通过上下文调用commit()函数。Mutations这一步骤,才是最终修改State数据的步骤。

2022-2-16 84 0
Vue

在了解Vue中的数据代理之前,我们首先了解一下Object对象下的definePropert()方法。0x01-Object.defineProperty()方法:Object.defineProperty()方法可以用来为对象增加属性,并且被添加属性很特殊,可以设置是否允许值被更改,或者如果访问这个属性的时候,它可以执行什么操作,这个属性的值被更改时,它可以执行什么操作,非常的NB!!1.1-注意:它应该是直接使用Object调用该方法,而不是一个Object类型的实例调用。//错误-不应该使用object类型的实例来调用varobj={};obj.definePropert();//正确-应该使用Object构造对象调用此方法Object.defineProperty();1.2-参数:obj:要定义属性的对象.prop:要添加属性的名称.descriptor:配置项.1.3-配置项:value:1.默认值:undefined。2.描述:被添加属性的值,可以是任何JS中的值。enumerable:1.默认值:false。2.描述:在遍历时,只有enumerable为true,被添加的属性才会出现,否则不出现。writable:1.默认值:false。2.描述:1.只有writable为true时,value的值才可以有效的被更改。2.为false时,修改也不会报错,但是打印该对象会发现值并未修改。get:1.默认值:undefined。2.说明:1.它的值应该是一个函数,当访问被添加的属性时,就会调用该方法。2.该函数的返回值会用作被添加属性的值。set:1.默认值:undefined。2.说明:1.它的值应该是一个函数,当被添加的属性的值发生修改时,就会调用该方法。2.该方法接收一个参数,值就是被新赋予的值。1.4-案例:问题:1.将num变量的值,添加到person对象的age属性中。2.当我们修改num这个变量值时,访问person.age,使它的值也随着num发生改变。3.当我们修改person.age时,使num也随着person.age改变。思路:1.我们只需要为在配置项中添加一个get,每次访问该属性时,都会去访问num这个变量,从而每次输出的都是num的值。2.我们还可以添加set,当修改person.age属性时,将value的参数值赋值给num,使它的值也随其改变。letnum=19;letperson={};Object.defineProperty(person,"age",{//每当访问person.age时,就会执行该方法.//return回的内容,就会当做person.age的值.get(){returnnum;},//当person.age被修改时,就将新值赋予给num.//从而在通过getter访问num时,还是同步的数据.set(value){num=value;}});0x02-Vue数据代理:Vue就用到了数据代理,在我们操作vm.属性时,它就用到了set和get方法,最终操作的就是_data中的数据,(后面仅仅是我猜想)->而_data也用到了代理,当它的值发生变化时,也会通过set方法去修改Dom元素的值,否则怎么会如Vue所介绍,数据驱动视图呢?

2021-12-24 92 0