首页 文章 精选 留言 我的

精选列表

搜索[vue.js],共641篇文章
优秀的个人博客,低调大师

Vue.js 十五分钟入门

TypeScript 为 JavaScript 带来静态类型检查,让 JavaScript 编写中大型应用的时候可以应用工具来避免部分错误。 Vue 很早就支持 TypeScript,但配置起来比较麻烦,幸好有了 Vue CLI 3.0。安装好 vue-cli 之后,使用 vue create 项目名称 来创建项目,vue 脚本手架自动创建以项目名称命名的目录。 vue-cli 3 生成的项目结构比较科学,尤其是通过 components 和views 将作为控件的组件和作为页面的组件分离开来,结构更清晰。可以理解为 views 中定义的组件是要配置在路由中的,而 componets 中定义的组件是被其它组件调用的。 HTML 需要定义一个 <div> 作为 Vue 应用的容器,main.ts 中会通过 new Vue(...) 生成应用实例并将之与容器绑定。注意 HTML 中定义的 <div id="app"></div> 会被 App.vue 模板中定义的 <div id="app">...</div> 替换掉。 Vue 是一个组件化的框架,组件是 Vue 的基本元素。一个 Vue 应用是由若干组件构成的,组件与组件之间的嵌套或并列关系,最终可以用树形来表示。main.ts 中创建的 Vue 实例是最顶层组件。 每个 Vue 组件都有三个组成部分,即骨架(HTML)、样式(CSS/LESS/SCSS)和脚本(JavaScript/TypeScript)。可以在一个 .vue 文件中写完三个部分,也可以将样式和脚本部分分别写成独立的文件。笔者推荐独立文件的方式。 既然我们选用 TypeScript,使用上图所示的 class-style 来实现 Vue 组件更为适合。 除了 class-style 之外,也可以使用 config-style。配置风格是最早支持的风格,将 Vue 的各类成员(属性、数据、计算属性、方法等)独立定义,易于理解 Vue 实例的内部结构,但初学者容易搞不清楚 this 指向。 Vue 定义的组件需要注册才能在其它组件中使用。注册的方式分为全局和局部两种。使用 TypeScript 和类风格开发 Vue 应用时,推荐使用局部注册。局部注册比较符合模式化开发思想。 Vue 可以通过 {{ }} 语法在文本中插值。但是如果要将值插入属性,则应使用 : 号修饰属性名。组件属性(指 HTML 标签参数)可随意定义,加 @Prop() 修饰即可,如果属性是必须的,应该使用 : 来定义;可选属性则使用 !: 来定义。 在 HTML 或自定义组件标签中使用 @ 前缀的事件名,可以绑定事件处理函数。Vue 实现了部分 HTML 事件,比如 @click 可以直接绑定。组件也可以“定义”自己的事件,不需要提前声明,只需要 this.$emit() 直接触发即可。 Vue 本身是数据驱动渲染,所以数据(包括属性、计算属性等)变化可以触发界面数据呈现,但是界面的输入要反馈给组件,就需要用触发事件的方式来反馈。双向绑定是用于更新属性事件的语法糖,使用 :属性名.sync="..." 绑定。子组件中通过触发 update:属性名 事件来更新父组件中绑定的数据。 路由主要用于组织视图(页面)关系。最基本的要求是为路由配置每个路径对应的组件。name 可以当作路径的简短别名。路由操作一般会使用注入到 Vue 实例中的 $router 对象,常用 $router.push() 和$router.replace() 来跳转,二者的区别在于对 URL 历史的影响(可以想像) 路由项配置中的 component 可以指定为导入的的组件类,也可以指定一个异步(返回 Promise 的)函数,该函数动态加载组件并返回包含该组件类的 Promise 对象。上例中使用的 import() 动态引入语法。 做一个简单的登录界面加深对前面知识的理解和记忆。该示例特意避免了 Ajax 调用,以降低其复杂程度。 没有 Ajax 实现的远程认证,我们只能假设用户输入 pass 时为正确密码。用户名可任意输入,如果验证成功则会显示该用户已登录。 项目仍然是由 vue-cli 3 创建的。创建好之后去掉了 About 和 HelloWorld,加入了 Login,并将 Home 改造成三部分各自独立的文件结构。当然,顺便还按自己(或团队)的开发规范调整了下 tslint.json 中的配置。 App.vue、main.ts 和 router.ts 可以算得上是一个 Vue 应用的入口和基本配置。App.vue 中直接把控制权交给了 vue-router。注意,import 的时候不能省略 .vue 扩展名。 Login 组件中用到了双向绑定,由于属性(由 @Prop() 修饰)不可以在内部修改,甚至可以把它声明为 readonly(也许 Vue 3 会定义相关的规范)。注意到 keypress 事件有一个后缀,这在 Vue 中称为事件修饰符,可以用于快速处理一些特殊情况,比如 keypress.enter 表示Enter按下时。 在 Home 中使用 Login 组件时,Home 的 user 数据字段绑定到了 Login 的 user 属性上,.sync 修饰符表示这是一个双向绑定。前面 Login 的代码中,如果登录成功,Login 会通过 $emit("update:user", {...}) 来通知绑定数据发生变化,Vue 框架接收到这个通知并更新了绑定的 Home.user,这会导致计算属性 message 重算,并最终触发呈现“某用户已登录”。 Vue 入门很简单吧! 不过 Vue 本身含有非常丰富的功能,要用 Vue 搭建完整的应用,仍然需要了解大量 Vue 设计概念和操作技巧。建议读者们仔细阅读 Vue 官方提供教程和 API 手册,并保持在 Vue 相关技术社区的活跃度。 原码下载:百度网盘 全栈说起来是一个比较全面的知识栈,直白一点来说就是软件开发的各个部分都要了解一些。Web 全栈是其中一个分支,技术栈倾向于 Web 相关的知识,最主要的就是包含 Web 前端技术和后端技术。 Web 后端涉及的技术非常多,但前端开发最重要的一门技术就是 JavaScript。Node.js 把 JavaScript 带入后端之后,JavaScript 可以前后通吃。所以基于 JavaScript 的全栈技术在前后两端至少可以做到语言复用和大量 SDK 复用,减轻全栈技能点负担。 欢迎订阅我的专栏:JavaScript 全栈工程师养成记 本专栏是作者 20 年软件开发的经验总结,借助 JavaScript 语言来描述。本专栏不是从纯粹的语言层面来讲的,而是稍稍深入了一点,讲到了软件内涵相关的一些东西。其中有软件工程相关的东西,比如开发过程,需求,设计、工程技术等;有内容构建的东西,比如算法,数据结构,设计方法,模式和重构等。 专栏前半部分讲了大量与语言无关的东西,当然举例是用 JavaScript。这些东西是任何一个软件,任何一端都需要的内涵;后半部分则相对具体一些,会讲到具体的技术,比如应用框架和一些技术细节。

优秀的个人博客,低调大师

Vue.js 组件复用和扩展之道

软件编程有一个重要的原则是 D.R.Y(Don't Repeat Yourself),讲的是尽量复用代码和逻辑,减少重复。组件扩展可以避免重复代码,更易于快速开发和维护。那么,扩展 Vue 组件的最佳方法是什么? Vue 提供了不少 API 和模式来支持组件复用和扩展,你可以根据自己的目的和偏好来选择。 本文介绍几种比较常见的方法和模式,希望对你有所帮助。 扩展组件是否必要 扩展往往通过继承基础组件来达到功能复用的目的。要知道,所有的组件扩展方法都会增加复杂性和额外代码,有时候还会增加性能消耗。经验告诉我们,组合模式优于继承。 因此,在决定扩展组件之前,最好先看看有没有其他更简单的设计模式能完成目标。 下面几种模式通常足够替代扩展组件了: props配合模板逻辑 slot 插槽 JavaScript 工具函数 props配合模板逻辑 最简单的方法是通过props结合模板条件渲染,来实现组件的多功能。 比如通过type属性: MyVersatileComponent.vue <template> <divclass="wrapper"> <divv-if="type==='a'">...</div> <divv-else-if="type==='b'">...</div> <!--etcetc--> </div> </template> <script> exportdefault{ props:{type:String}, ... } </script> 使用组件的时候传不同的type值就能实现不同的结果。 //*ParentComponent.vue* <template> <MyVersatileComponenttype="a"/> <MyVersatileComponenttype="b"/> </template> 如果出现下面两种情况,就说明这种模式不适用了,或者用法不对: 组件组合模式把状态和逻辑分解成原子部分,从而让应用具备可扩展性。如果组件内存在大量条件判断,可读性和可维护性就会变差。 props 和模板逻辑的本意是让组件动态化,但是也存在运行时资源消耗。如果你利用这种机制在运行时解决代码组合问题,那是一种反模式。 slot(插槽) 另一种可避免组件扩展的方式是利用slots(插槽),就是让父组件在子组件内设置自定义内容。 //*MyVersatileComponent.vue* <template> <divclass="wrapper"> <h3>Commonmarkup</div> <slot/> </div> </template> //*ParentComponent.vue* <template> <MyVersatileComponent> <h4>Insertingintotheslot</h4> </MyVersatileComponent> </template> 渲染结果: <divclass="wrapper"> <h3>Commonmarkup</div> <h4>Insertingintotheslot</h4> </div> 这种模式有一个潜在约束, slot 内的元素从属于父组件的上下文,在拆分逻辑和状态时可能不太自然。scoped slot会更灵活,后面会在无渲染组件一节里提到。 JavaScript 工具函数 如果只需要在各组件之间复用独立的函数,那么只需要抽取这些 JavaScript 模块就行了,根本不需要用到组件扩展模式。 JavaScript 的模块系统是一种非常灵活和健壮的代码共享方式,所以你应该尽可能地依靠它。 MyUtilityFunction.js exportdefaultfunction(){ ... } MyComponent.vue importMyUtilityFunctionfrom"./MyUtilityFunction"; exportdefault{ methods:{ MyUtilityFunction } } 扩展组件的几种模式 如果你已经考虑过以上几种简单的模式,但这些模式还不够灵活,无法满足需求。那么就可以考虑扩展组件了。 扩展 Vue 组件最流行的方法有以下四种: Composition API mixin 高阶组件(HOC) 无渲染组件 每一种方法都有其优缺点,根据使用场景,或多或少都有适用的部分。 Composition API 组件之间共享状态和逻辑的最新方案是 Composition API。这是 Vue 3 推出的 API,也可以在 Vue 2 里当插件使用。 跟之前在组件定义配置对象里声明data,computed,methods等属性的方式不同,Composition API 通过一个setup函数声明和返回这些配置。 比如,用 Vue 2 配置属性的方式声明Counter组件是这样的: Counter.vue <template> <button@click="increment"> Countis:{{count}},doubleis:{{double}} </button> <template> <script> exportdefault{ data:()=>({ count:0 }), methods:{ increment(){ this.count++; } }, computed:{ double(){ returnthis.count*2; } } } </script> 用 Composition API 重构这个组件,功能完全一样: Counter.vue <template><!--asabove--><template> <script> import{reactive,computed}from"vue"; exportdefault{ setup(){ conststate=reactive({ count:0, double:computed(()=>state.count*2) }); functionincrement(){ state.count++ } return{ count, double, increment } } } </script> 用 Composition API 声明组件的主要好处之一是,逻辑复用和抽取变得非常轻松。 进一步重构,把计数器的功能移到 JavaScript 模块useCounter.js中: useCounter.js import{reactive,computed}from"vue"; exportdefaultfunction{ conststate=reactive({ count:0, double:computed(()=>state.count*2) }); functionincrement(){ state.count++ } return{ count, double, increment } } 现在,计数器功能可以通过setup函数无缝引入到任意 Vue 组件中: MyComponent.vue <template><!--asabove--></template> <script> importuseCounterfrom"./useCounter"; exportdefault{ setup(){ const{count,double,increment}=useCounter(); return{ count, double, increment } } } </script> Composition 函数让功能模块化、可重用,是扩展组件最直接和低成本的方式。 Composition API 的缺点 Composition API 的缺点其实不算什么——可能就是看起来有点啰嗦,并且新的用法对一些 Vue 开发者来说有点陌生。新技术总有个适应的过程,迟早会大面积应用。 mixin 如果你还在用 Vue 2,或者只是喜欢用配置对象的方式定义组件功能,可以用 mixin 模式。mixin 把公共逻辑和状态抽取到单独的对象,跟使用 mixin 的组件内部定义对象合并。 我们继续用之前的Counter组件例子,把公共逻辑和状态放到CounterMixin.js模块中。 CounterMixin.js exportdefault{ data:()=>({ count:0 }), methods:{ increment(){ this.count++; } }, computed:{ double(){ returnthis.count*2; } } } 使用 mixin 也很简单,只要导入对应模块并在mixins数组里加上变量就行。组件初始化时会把 mixin 对象与组件内部定义对象合并。 MyComponent.vue importCounterMixinfrom"./CounterMixin"; exportdefault{ mixins:[CounterMixin], methods:{ decrement(){ this.count--; } } } 选项合并 如果组件内的选项跟 mixin 冲突怎么办? 比如,给组件定义一个自带的increment方法,哪个优先级更高呢? MyComponent.vue importCounterMixinfrom"./CounterMixin"; exportdefault{ mixins:[CounterMixin], methods:{ //自带的`increment``方法会覆盖 mixin 的`increment`吗? increment(){...} } } 这个时候就要说到 Vue 的合并策略了。Vue 有一系列的规则,决定了如何处理同名选项。 通常,组件自带的选项会覆盖来自 mixin 的选项。但也有例外,比如同类型的生命周期钩子,不是直接覆盖,而是都放进数组,按顺序执行。 你也可以通过自定义合并策略改变默认行为。 mixin 的缺点 作为扩展组件的一种模式,mixin 对于简单的场景还算好用,一旦规模扩大,问题就来了。不仅需要注意命名冲突问题(尤其是第三方 mixin),使用了多个 mixin 的组件,很难搞清楚某个功能到底来自于哪里,定位问题也比较困难。 高阶组件 高阶组件(HOC)是从 React 借用的概念,Vue 也能使用。 为了理解这个概念,我们先抛开组件,看看两个简单的 JavaScript 函数,increment和double。 functionincrement(x){ returnx++; } functiondouble(x){ returnx*2; } 假设我们想给这两个函数都加一个功能:在控制台输出结果。 为此,我们可以用高阶函数模式,新建一个addLogging函数,接受函数作为参数,并返回一个带有新增功能的函数。 functionaddLogging(fn){ returnfunction(x){ constresult=fn(x); console.log("Theresultis:",result); returnresult; }; } constincrementWithLogging=addLogging(increment); constdoubleWithLogging=addLogging(double); 组件如何利用这种模式呢?类似地,我们创建一个高阶组件来渲染Counter组件,同时添加一个decrement方法作为实例属性。 实际代码比较复杂,这里只给出伪代码作为示意: importCounterfrom"./Counter"; //伪代码 constCounterWithDecrement=>({ render(createElement){ constoptions={ decrement(){ this.count--; } } returncreateElement(Counter,options); } }); HOC 模式比 mixin 更简洁,扩展性更好,但是代价是增加了一个包裹组件,实现起来也需要技巧。 无渲染组件 如果需要在多个组件上使用相同的逻辑和状态,只是展示方式不同,那么就可以考虑无渲染组件模式。 该模式需要用到两类组件:逻辑组件用于声明逻辑和状态,展示组件用于展示数据。 逻辑组件 还是回到Counter的例子,假设我们需要在多个地方重用这个组件,但是展示方式不同。 创建一个CounterRenderless.js用于定义逻辑组件,包含逻辑和状态,但是不包含模板,而是通过render函数声明scoped slot。 scoped slot暴露三个属性给父组件使用:状态count,方法increment和计算属性double。 CounterRenderless.js exportdefault{ data:()=>({ count:0 }), methods:{ increment(){ this.count++; } }, computed:{ double(){ returnthis.count*2; } }, render(){ returnthis.$scopedSlots.default({ count:this.count, double:this.double, increment:this.toggleState, }) } } 这里的scoped slot是这种模式里逻辑组件的关键所在。 展示组件 接下来是展示组件,作为无渲染组件的使用方,提供具体的展示方式。 所有的元素标签都包含在scoped slot里。可以看到,这些属性在使用上跟模板直接放在逻辑组件里没什么两样。 CounterWithButton.vue <template> <counter-renderlessslot-scope="{count,double,increment}"> <div>Countis:{{count}}</div> <div>Doubleis:{{double}}</div> <button@click="increment">Increment</button> </counter-renderless> </template> <script> importCounterRenderlessfrom"./CountRenderless"; exportdefault{ components:{ CounterRenderless } } </script> 无渲染组件模式非常灵活,也容易理解。但是,它没有前面那几种方法那么通用,可能只有一种应用场景,那就是用于开发组件库。 模板扩展 上面的 API 也好,设计模式也罢,都有一种局限性,就是无法扩展组件的模板。Vue 在逻辑和状态方面有办法重用,但是对于模板标签就无能为力了。 有一种比较 hack 的方式,就是利用 HTML 预处理器,比如 Pug,来处理模板扩展。 第一步是创建一个基础模板.pug文件,包含公共的页面元素。还要包含一个block input,作为模板扩展的占位符。 BaseTemplate.pug div.wrapper h3{{myCommonProp}}<!--commonmarkup--> blockinput<!--extendedmarkupoutlet--> 为了能扩展这个模板,需要安装 Vue Loader 的 Pug 插件。然后就可以引入基础模板并利用block input语法替换占位部分了: MyComponent.vue <templatelang="pug"> extendsBaseTemplate.pug blockinput h4{{myLocalProp}}<!--getsincludedinthebasetemplate--> </template> 一开始你可能会认为它跟 slot 的概念是一样的,但是有个区别,这里的基础模板不属于任何单独的组件。它在编译时跟当前组件合并,而不是像 slot 那样是在运行时替换。 参考资料: https://reactjs.org/blog/2016/07/13/mixins-considered-harmful.html https://adamwathan.me/renderless-components-in-vuejs/ 顺手点“在看”,每天早下班;转发加关注,共奔小康路~ 本文分享自微信公众号 - 1024译站(trans1024)。 如有侵权,请联系 support@oschina.cn 删除。 本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

Vue.js开发移动端经验总结

关注公众号前端人,回复“加群” 添加无广告优质学习群 移动端适配 相对于PC端来说,移动端设备分辨率百花齐放,千奇百怪,对于每一个开发者来说,移动端适配是我们进行移动端开发第一个需要面对的问题。 在移动端我们经常可以在head标签中看到这段代码: <metaname='viewport'content='width=device-width,initial-scale=1,user-scale=no'/> 通过meta标签对viewport的设置,定义了页面的缩放比例;要了解这些参数的意义,我们需要先知道几个视口宽度的意义。 layoutviewport布局宽度 就是网页的宽度visualviewport可视宽度,就是浏览器窗口的宽度,这个值决定了我们手机一屏能看到的内容; visualviewport和layoutviewport的大小关系,决定了是否会出现滚动条,当visualviewport更大或者刚好等于layoutviewport时是不会出现滚动条的。idealviewport为浏览器定义的可完美适配移动端的viewport,固定不变,可以认为是设备视口宽度device-width。 meta meta的设置其实就是对layoutviewport和visualviewport进行设置。width=device-width表示页面宽度layoutviewport与设备视口宽度idealviewport一致 initial-scale=1 表示页面宽度和网页宽度与设备视口宽度的初始缩放比例,visualviewport由这个比例决定,但是对于layoutviewport来说,它同时受到两个属性的影响,然后取其中较大的那个值。 user-scale=no禁止缩放 所以现在我们知道,这段在移动端常见的代码的意思,即将visualviewport和layoutviewport设置为idealviewport的值;这样我们在移动端就不会出现滚动条,网页内容可以比较好的展示出来,在这个前提下我们再考虑页面的适配问题。UI出图的时候一般是有一个固定的宽度的,而我们实际的移动端设备的宽度却都不太一样,但是如果页面元素的缩放比例和页面宽度的缩放比例一致,在不同尺寸的设备下我们网页的效果也将会是一致的。使用相对单位 rem rem 是相对于根元素 html 的 font-size 来做计算。通常在页面初始化时加载时通过对document.documentElement.style.fontSize 设置来实现。一般我们将根元素html的font-size设置为宽度的1/10,不同设备的宽度不同,但是同样数值的rem比例与设备的宽度比例是一致的。 document.documentElement.style.fontSize=document.documentElement.clientWidth/10+'px'; 在实际项目中我们无须在开发中自己进行转换,可以使用pxtorem在输出的时候将px转换为rem。 视口单位 将视口宽度window.innerWidth和视口高度window.innerHeight(即layoutviewport)等分为 100 份。 vw : 1vw 为视口宽度的 1% vh : 1vh 为视口高度的 1% vmin : vw 和 vh 中的较小值 vmax : 选取 vw 和 vh 中的较大值和rem相比较,视口单位不需要使用js对根元素进行设置,兼容性稍差,但是大部分设备都已经支持了,同样的无须再开发时进行单位换算,直接使用相关的插件postcss-px-to-viewport在输出的时候进行转换。修改viewport 之前我们提到了layoutviewport布局宽度实际上不是一个固定值,而是通过meta设置属性,通过idealviewport计算出来的值,我们可以通过控制meta的属性来将layoutviewport固定为某一个值。一般设计图的宽度为750px,现在我们的目标就是将layoutviewport设置为750px; layoutviewport受到两个属性的影响,width属性我们之间设置为750,initial-scale缩放比例应该为idealviewport的宽度/750;当我们未改变meta标签属性的时候,layoutviewport的值其实就是idealviewport的值,所以可以通过document.body.clientWidth或者window.innerWidth来获取。 ;(function(){constwidth=document.body.clientWidth||window.innerWidthconstscale=width/750;constcontent=`width=750,initial-scale=${scale},minimum-scale=${scale},maximum-scale=${scale},viewport-fit=cover`;document.querySelector('meta[name="viewport"]').content=content})() 设置完成之后,layoutviewport在不同的设备中会始终保持为750px,我们开发时可以直接使用设计稿尺寸。布局样式 布局的方式可以是各种各样的,但是出于兼容性的考虑,有些样式我们最好避免使用,难以解决的问题,那就不去面对。需要谨慎对待的fixed position:fixed在日常的页面布局中非常常用,在许多布局中起到了关键的作用。它的作用是:position:fixed的元素将相对于屏幕视口(viewport)的位置来指定其位置。并且元素的位置在屏幕滚动时不会改变。但是,在许多特定的场合,position:fixed的表现与我们想象的大相径庭。 iOS弹出键盘;软键盘唤起后,页面的 fixed元素将失效(iOS认为用户更希望的是元素随着滚动而移动,也就是变成了 absolute定位),既然变成了absolute,所以当页面超过一屏且滚动时,失效的 fixed 元素就会跟随滚动了。 当元素祖先的 transform 属性非 none时,定位容器由视口改为该祖先。说的简单点,就是position:fixed的元素会相对于最近的并且应用了transform的祖先元素定位,而不是窗口。导致这个现象的原因是使用了transform的元素将创建一个新的堆叠上下文。 堆叠上下文(Stacking Context): 堆叠上下文是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的z 轴上延伸,HTML元素依据其自身属性按照优先级顺序占用层叠上下文的空间。 顺序: 总之堆叠上下文会对定位关系产生影响。想要进一步可以查看不受控制的position:fixed。 键盘弹出与使用transform属性的情况在移动端是很常见的,所以需要谨慎使用position:fixed。 推荐使用flex flex,即弹性布局,移动端兼容性较好,能够满足大部分布局需求。现在我们使用flex来实现h5中常见的顶部标题栏+中部滚动内容+底部导航栏的布局 页面跳转 转场动画 在vue中我们通过vue-router来管理路由,每个路由跳转类似与在不同的页面之间进行切换,从用户友好的角度来说,每次切换页面的时候最好添加一个转场效果。如果转场动画不区分路由是打开新页面、还是返回之前页面我们只需要在外使用添加一个动画效果即可; 但是一般打开和返回是应用不同的动画效果的,所以我们需要在切换路由的时候区分路由是前进还是后退。为了区分路由的动作,我们在路由文件中设置meta为数字,meta表示其路由的深度,然后监听$route,根据to、from meta值的大小设置不同的跳转动画。如果应用到多种跳转动画,可以根据详情,具体情况具体应用。 <template><transition:name="transitionName"><router-view></router-view></transition></template> exportdefault{name:'app',data(){return{transitionName:'fade'}},watch:{'$route'(to,from){lettoDepth=to.metaletfromDepth=from.metaif(fromDepth>toDepth){this.transitionName='fade-left'}elseif(fromDepth<toDepth){this.transitionName='fade-right'}else{this.transitionName='fade'}}}} 登录跳转 vue-navigation 虽然这样能够实现跳转效果,但是需要在编写router时添加设置,比较麻烦;我们可以使用开源项目vue-navigation来实现,更加方便,无须对router进行多余的设置。 npmi-Svue-navigation 安装,在main.js中导入: importNavigationfrom'vue-navigation'Vue.use(Navigation,{router})//router为路由文件 在App.vue中设置: this.$navigation.on('forward',(to,from)=>{this.transitionName='fade-right'})this.$navigation.on('back',(to,from)=>{this.transitionName='fade-left'})this.$navigation.on('replace',(to,from)=>{this.transitionName='fade'}) vue-navigation插件还有一个重要的功能就是保存页面状态,与keep-alive相似,但是keep-alive保存状态无法识别路由的前进后退,而实际应用中,我们的需求是返回页面时,希望页面状态保存,当进入页面时希望获取新的数据,使用vue-navigation可以很好的实现这个效果。 具体使用可以查看vue-navigation有详细使用说明与案例。另外也可以尝试vue-page-stack,两个项目都能实现我们需要的效果,vue-page-stack借鉴了vue-navigation,也实现了更多的功能,并且最近也一直在更新。PS: 这里的动画效果引用自animate.scss; 底部导航栏 之前我们已经实现了底部导航栏的基本样式,这里我们再做一些说明。当页面路由路径与router-link的路由匹配时,router-link将会被设置为激活状态,我们可以通过设置active-class来设置路径激活时应用的类名,默认为router-link-active,而激活的类名还有一个router-link-exact-active,这个类名是由exact-active-class来设置的,同样是设置路径激活时应用的类名;active-class与exact-active-class其实是由路由的匹配方式决定的。 一般路由的匹配方式是包含匹配。举个例子,如果当前的路径是 /a 开头的,那么 也会被设置 CSS 类名。按照这个规则,每个路由都会激活 ,而使用exact属性可以使用“精确匹配模式”。精确匹配只有当路由完全相同的时候才会被激活。路由守卫 移动端的路由守卫一般不会太复杂,主要是登录权限的判断,我们设置一个路由白名单,将所有不需要登录权限的路由放入其中;对于需要登录的路由做判断,没有登录就跳转登录页面,要求用户进行登录后在访问,如果登录后需要返回原有路由就把目标页面的路由作为参数传递给登录页面,再在登录后进行判断,如果存在目标页面参数就跳转目标页面,没有就跳转首页。 如果你的应用涉及到权限,那需要标注每个路由需要的权限,在meta中设置roles,roles是数组来保存需要的权限;从后台的接口中获取用户拥有的权限和roles进行对比就可以判断是否具有相关权限了。 constwhiteList=['/login']router.beforeEach((to,from,next)=>{consthasToken=store.getters.authif(hasToken){if(to.path==='/login'){next({path:'/'})}else{constneedRoles=to.meta&&to.meta.roles&&to.meta.roles.length>0if(needRoles){constroles=store.state.user.roles;consthasRoles=roles.some((role)=>{returnto.meta.roles.includes(role)})if(hasRoles){next()}else{next('/403')}}else{next()}}}else{if(whiteList.includes(to.path)){next()}else{next('/login')}}}) 组件自动加载 在我们的项目中,往往会使用的许多组件,一般使用频率比较高的组件为了避免重复导入的繁琐一般是作为全局组件在项目中使用的。而注册全局组件我们首先需要引入组件,然后使用Vue.component进行注册;这是一个重复的工作,我们每次创建组件都会进行,如果我们的项目是使用webpack构建(vue-cli也是使用webpack),我们就可以通过require.context自动将组件注册到全局。创建components/index.js文件: exportdefaultfunctionregisterComponent(Vue){/***参数说明:*1.其组件目录的相对路径*2.是否查询其子目录*3.匹配基础组件文件名的正则表达式**/constmodules=require.context('./',false,/\w+.vue$/)modules.keys().forEach(fileName=>{//获取组件配置constcomponent=modules(fileName)//获取组件名称,去除文件名开头的`./`和结尾的扩展名constname=fileName.replace(/^\.\/(.*)\.\w+$/,'$1')//注册全局组件//如果这个组件选项是通过`exportdefault`导出的,//那么就会优先使用`.default`,//否则回退到使用模块的根。Vue.component(name,component.default||component)})} 之后在main.js中导入注册模块进行注册,使用require.context我们也可以实现vue插件和全局filter的导入。 importregisterComponentfrom'./components'registerComponent(Vue) 通过v-model绑定数据 v-model是语法糖,它的本质是对组件事件进行监听和数据进行更新,是props和on监听事件的缩写,v-model默认传递value,监听input事件。 现在我们使用v−model来实现下数字输入框,这个输入框只能输入数字,在组件中我们只需要定义value来接受传值,然后在输入值满足我们输入条件(输入为数字)的时候使用on监听事件的缩写,v-model默认传递value,监听input事件。 现在我们使用v-model来实现下数字输入框,这个输入框只能输入数字,在组件中我们只需要定义value来接受传值,然后在输入值满足我们输入条件(输入为数字)的时候使用on监听事件的缩写,v−model默认传递value,监听input事件。 现在我们使用v−model来实现下数字输入框,这个输入框只能输入数字,在组件中我们只需要定义value来接受传值,然后在输入值满足我们输入条件(输入为数字)的时候使用emit触发input事件。 <template><div><inputtype="text":value="value"@input="onInput"></div></template> exportdefault{name:'NumberInput',props:{value:String},methods:{onInput(event){if(/^\d+$/.test(event.target.value)){this.$emit('input',event.target.value)}else{event.target.value=this.value}}}} 使用的时候,我们只需要使用v-model绑定值就可以了。v-model默认会利用名为value的prop和名为input的事件,但是很多时候我们想使用不同的prop和监听不同的事件,我们可以使用model选项进行修改。 Vue.component('my-checkbox',{model:{prop:'checked',event:'change'},props:{//thisallowsusingthe`value`propforadifferentpurposevalue:String,//use`checked`asthepropwhichtaketheplaceof`value`checked:{type:Number,default:0}},//...}) <my-checkboxv-model="foo"value="somevalue"></my-checkbox>//上述代码相当于:<my-checkbox:checked="foo"@change="val=>{foo=val}"value="somevalue"></my-checkbox> 通过插件的方式来使用组件 在很多第三方组件库中,我们经常看到直接使用插件的方式调用组件的方式,比如VantUI的Dialog弹出框组件,我们不但可以使用组件的方式进行使用,也可以通过插件的形式进行调用。 this.$dialog.alert({message:'弹窗内容'}); 将组件作为插件使用的原理其实并不复杂,就是使用手动挂载Vue组件实例。 importVuefrom'vue';exportdefaultfunctioncreate(Component,props){//先创建实例constvm=newVue({render(h){//h就是createElement,它返回VNodereturnh(Component,{props})}}).$mount();//手动挂载document.body.appendChild(vm.$el);//销毁方法constcomp=vm.$children[0];comp.remove=function(){document.body.removeChild(vm.$el);vm.$destroy();}returncomp;} 调用create传入组件和props参数就可以获取组件的实例,通过组件实例我们就可以调用组件的各种功能了。 <template><divclass="loading-wrapper"v-show="visible">加载中</div></template> exportdefault{name:'Loading',data(){return{visible:false}},methods:{show(){this.visible=true},hide(){this.visible=false}}} <stylelang="css"scoped>.loading-wrapper{position:absolute;top:0;bottom:0;width:100%;background-color:rgba(0,0,0,.4);z-index:999;}</style> constloading=create(Loading,{})loading.show()//显示loading.hide()//关闭 第三方组件 移动端各种组件、插件已经相对完善,在项目开发中重复造轮子是一件很不明智的事情;开发项目时我们可以借助第三方组件、插件提高我们的开发效率。 常用组件库 VantUI是有赞开源的一套轻量、可靠的移动端Vue组件库;支持按需引入、主题定制、SSR,除了常用组件外,针对电商场景还有专门的业务组件,如果是开发电商项目的话,推荐使用。官方文档关于主题定制是在webpack.config.js中进行设置的: //webpack.config.jsmodule.exports={rules:[{test:/\.less$/,use:[//...其他loader配置{loader:'less-loader',options:{modifyVars:{//直接覆盖变量'text-color':'#111','border-color':'#eee'//或者可以通过less文件覆盖(文件路径为绝对路径)'hack':`true;@import"your-less-file-path.less";`}}}]}]}; 但我们的项目可能是使用vue-cli构建,这时我们需要在vue.config.js中进行设置: module.exports={css:{loaderOptions:{less:{modifyVars:{'hack':`true;@import"~@/assets/less/vars.less";`}}}}} 另外vux、mint-ui也是很好的选择。 常用插件 better-scroll是一个为移动端各种滚动场景提供丝滑的滚动效果的插件,如果在vue中使用可以参考作者的文章当 better-scroll 遇见 Vue。 swiper是一个轮播图插件,如果是在vue中使用可以直接使用vue-awesome-swiper,vue-awesome-swiper基于Swiper4,并且支持SSR。 原文地址:blog.csdn.net/weixin_44705688/article/details/103961664 1.如果看到这里,说明你喜欢这篇文章,请点赞、在看 2.关注公众号前端人,回复资料包领取我整理的前端进阶资料包 3.回复加群,加入前端进阶群,和小伙伴一起学习讨论! 本文分享自微信公众号 - 前端人(FrontendPeople)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册