zoukankan      html  css  js  c++  java
  • 25.Vue技术栈开发实战-多Tab页开发







    点击tab左侧的菜单会对应的选中这个菜单

    首先做一点修改,本节课用mock来做拦截。
    路由列表做了一些修改,给每一个路由对象都加了meta对象。这是路由源信息对象,每一个都加一个title属性。

    并且没一个路由对象都有一个name值,并且是不重复的

    嵌套路由

    路由列表所有的name都写在这

    路由列表生成左侧菜单

    宽度改成200

    默认是false


    store的严格模式先关掉

    左侧的菜单之前是这里我们写死的

    现在左侧的菜单哟啊根据路由列表去实现。下面这里把menuList删掉。

    我们要获取store里面促成黏糊的routers,开面是过滤路由列表权限后的数据

    引入mapState


    我们还需要对结果进行过滤。匹配的*和 /login这两个页面我们是不希望他出现在左侧的菜单的。

    所以在这里做一个简单的过滤,使用filter筛选出来不等于*和不等于login的

    筛选出来上之后赋值

    加上.meta





    现在就是根据路由列表生成的菜单

    菜单超出屏幕高度让它滚动
    给sider加个类名

    高度为100%,超出隐藏,

    当前菜单超出被隐藏了,但是它没法滚动了。

    它的里面还有一个容器

    让ivu的这个元素,y轴超出滚动,水平方向超出 隐藏。

    这样就有滚动态条了。

    滚动条看起来比较丑,而且mac电脑和window电脑滚动台的样式还不一样。

    所以如果不希望看到这个滚动条的话



    这样它的宽度就变宽了

    超出的部分被它的父容器,超出隐藏了。

    所以当前我们看不到滚动条,而且还能滚动。也有个缺点就是有的人看不到滚动条,反而不知道这里可以滚动。根据自己的需求进行添加。

    多标签

    用到iview的tab组件

    复制这里代码

    router-view下注释掉。然后代码复制到这里。

    tab不放在card里面,在上面嵌套在div里面。

    在加一个div,把card和里面的router-view嵌套在里面。



    先把标签的内容都去掉。




    修改样式

    首先是不希望下面有间距





    只用TabPane生成标签。在里面不做内容的渲染,本页面还是只有一个router-view ,还是在router-view里面渲染页面。

    标签肯定是通过一个数组来v-for循环生成。我们把这个数组存到store里面。在store里面新建tabNav



    index引入这个模块。

    先来定义一个数组,用来保存打开页面的列表。所有tab的标签是通过这个数组来渲染的。



    拿到store里面的tabList,然后循环生成TabPane。这里不应该简单的存一个路由的name,因为这里如果要做动态路由,还有带参数的页面的话,同样name

    把这里的name改成params

    同样把这里也改成params

    这里区别是后面的参数不同,页面其实是不同的页面。这样就没法用params来区别页面。

    所以我们把name、params、query都存进去,存一个对象,
    这里先把key写上。

    待会会来写一下 ,先来解决的简单的,不带参数的路由。不带动态参数的路由。就这样直接用item.name就可以了。


    现在是没有标签的

    接下来是打开一个页面。现在的菜单点击没有做跳转。

    在这里我们直接做跳转,直接push 然后里面传入路由的name就可以了。这是es6的简写形式,

    当我们点击菜单

    跳转到对应的页面上。







    countTo是我们直接在路由列表里面定义的。匹配的就是count-to这个组件。


    没有使用layout这个父组件。所以我们点击是跳转到了单独的页面。

    当点击这三个菜单的时候

    变化的是中间的内容区域

    是因为我们使用了layout这个父组件。这三个页面都是作为它的嵌套路由来渲染的,

    路径上的component是一级路由,后面的是二级路由。切换的是后面的

    演示我们就先用这三个页面来做演示,其他的地方就先不改了。

    当前打开的页面保存到tabList里面

    定义一个mutation方法。接收一个route

    把这个路由对象拿到后,我们添加到tabList里面。
    当路由变化的时候添加。所以这里可以用watch,监听路由的变化


    引入mapMutations,它是一个方法。

    把这个方法引进来

    当路由发生变化,把跳转的新的路由对象传进去。




    多次点击的效果。有重复添加的问题。

    当前tab如果存在,那么就不再添加,我们先来做简单的判断,只有name不同。
    用find做判断,没有找到name相同的。那么才去添加。

    直接不添加tab了

    前面用叹号,后面用 三等号


    重复的点击,不会重复的添加了


    点击菜单,对应的tab选中效果。tab组件可以绑定一个value

    value是name


    给他绑定一个value,当前点击的是谁,路由对象就是谁。

    所以这里直接局势$router.name

    label改成meta.title 标签上显示的name值。

    再给他一个name值

    这样他就知道你当前选中的是哪一个。这里删掉


    切换不同的页

    如果你这个页面是动态路由,后面有参数,参数是变化的。根据不同的参数来显示不同的内容。

    还有就是带query参数的。如果这两种情况,你都希望不同的参数,打开不同的标签页的话。只通过name是不够的


    name值应该包括当前路由的name值,还包裹它的参数。还有query参数相关的信息。

    加一个按钮和事件

    params加上一个随机数,得到秒。

    然后进行跳转



    这改成random


    点击打开了新的tab页面

    这里就是随即生成的参数。

    打开多个params的页面,不会重复添加。因为我们tab添加的时候,判断的是tab的name

    所以需要一个方法来判断,如果name相同,参数也一样,才算是一样。


    用一下之前在tolls内定义的方法



    tabList[index]就是当前遍历的项。当前这里也可以用forEach

    我们要来定义一个新的方法routeEqual 两个参数,

    params1等于route1.params或者是一个空对象。如果route1没有这个params那么就是个空对象。

    至少route的name是相同的

    &&继续往下判断。如果name相同,那么就继续来判断param。判断这连个params和query我们还要来定义方法。判断两个对象里面的属性名和属性值一一对应相等。

    方法定义在tools。判断两个对象的值和属性都相等。

    个数也相等,值也相等。作为一个工具方法,定义在tools 内。

    用Object.keys获取到它所有的属性名。

    属性的个数不相同,那么直接return false


    长度都是0,那么就是俩空对象,那么长度就都是相等的。

    使用some方法,会遍历这个数组,它里面传入一个回调函数。

    如果有任何一个这两个属性的key不同,那么就返回true。



    回调函数内有任何一条遍历结果返回true,那么就是true,如果所有的都是false,那么就是false

    和some对应的方法还有every 只有所有的回调函数都返回true,它才是true,有任何一条是false,它就是false

    只要有一条不相等就是true,所以这里我们要做一个取反。

    使用定义好的方法

    这个地方来判断。

    如果params1和2这俩对象相等

    再来判断query1和2

    判断当前tabList索引和 当前路由对象是相等,那么就返回true

    这样mutations里面判断,就是用我们定义的方法routeExist

    还是会出现重复的,好像有点问题

    这里改成直接调用方法,取反

    这样就不会有重复的了

    打开参数页面





    再来打开

    参数不相同,依然心打开的是tab页

    出现的问题,这两个tab都被选中的状态。因为我们的name是相同的,选中的状态我们是通过name来绑定的。


    所以这里就不能用当前路由的name来做标识了。


    name、params和query里面的信息通通都包含。所以我们要拼一个字符串。定义一个方法getTabNameByRoute

    我们把这个方法定义在Utils里

    如果想在这里用,我们必须把他挂载到data上面。

    $route变量,都是挂载到vue实例上 的。

    所以我们必须要把他放到这个vue实例上。才能在template里面使用。

    util里面定义方法

    首先传过来一个路由对象,把它解析过来。首先把name赋值给res返回的结果。

    如果params不是undefined说明你这个路由对象里面是包含了params这个字段的,并且params它的属性,
    Object.keys 它会把它里面所有的属性名取出来,然后放到一个数组里面,如果length不为0 说明它里面是有属性的。

    包含了params就给这个res拼字符串。拼成下面这种格式的,id是参数用下划线和value分隔开。 &后面拼接的是query的参数。

    定义一个方法,取出来params里面的键值对。

    Object.entries

    直接可以把一个对象变成一个二维数组,没一个元素是一个数组,数组里面第一个值是key,第二只是value,。但是我们这里不用entries方法。
    取键值对有个es6的方法



    如果有多个属性,那么就是另外一个数组

    需要对它进行排序,因为你的param是一个对象。里面所有属性读出来顺序是不一定的。所以如果你直接拿来拼字符串,虽然里面键值对可能都相同,但是你最后拼出来的顺序不同。也会导致最后比较不正确。所以这里先进行排序。

    传两个参数,a[0]减去b[0]。 这是比较两个数组第一个值做排序,

    拍完序后做遍历,这里有个参数 就是遍历当前的数组,它里面有个值,第一个值是key,第二个值是value,所以这里用解构赋值。获取到第一个值用key来表示,第二个值用value来表示。

    然后用下划线,把他们凭借起来。

    接下来处理query。前面 &符号来拼接。

    最后把res返回,这样这个方法就定义好了。








    故意把参数改成26,会选中26的tab

    实现tab页被点击时,事件触发,同时选中左侧菜单

    添加tab事件,绑定一个handleClickTab

    参数是点击的tab的name值。拿到这个name值,我们首先要做跳转。

    先做跳转push传入name是不行的。

    这几个参数的tab的name都是argu,只不过他们的params不同,所以直接push一个name是不行的 ,

    所以我们要根据name得到一个路由对象。这个name是我们拼接出来的里面包含了param和query信息。


    getRouteById这个方法我们在util里面


    先用includes判断是不是包含&符号。说明就包含query,

    分割

    为了保险起见,取数组长度减一,就是这个数组的最后一个元素。

    在用下划线来切割。



    如果我们的属性分别是a和b 。。那么拼接出来的就是下面这样。

    应下划线分割出来就是下面这样

    所以每次循环我们+2

    query和这部分一样,所以我们把这部分代码拆出来。拆成一个函数。

    封城成一个函数

    有冒号就表示有params

    自后这个res就是包含name或者包含params或者包含query的这样一个对象。

    那么通过id我们就可以拿到一个对象了。这里输出看一下



    点击tab输出,

    这里就得到了一个对象

    这里有点问题

    我们把这个id也输出来看下

    看一下拿到的id




    这里分隔字符串,改成用变量

    点击,路由也发生了改变


    点击表格,路由在变,

    菜单的联动

    菜单我们用的iview的menu组件。它有个属性叫做。它有个属性叫做active-name这里的值取的是路由的name
    现在点击文件夹,左侧的菜单也联动的被选中了。

    希望点击里面的子菜单的时候,他的父级 可以展开。

    用到菜单的另一个属性:openName

    展开父级别菜单

    这是一个计算属性,我们要通过一个当前打开激活的路由菜单,展开他的父级menu。
    所以当前的$router变化了,它的展开就应该也要变化,

    根据当前打开的路由对象的name值,然后把这个routers传进去。





    这是一个计算属性。这是在state的router模块里面。

    下面来封装这个方法

    传入两个参数,一个name,一个是routerList

    先定义一个结果数组arr,然后遍历这个routerList。如果当前点击的name和路由里面路由对象是相同的。

    push到arr数组。为什么这里用some ,而不是用foreach呢,因为如果用foreach 他会遍历所有的元素。就算你中间满足条件已经找到这个元素了。还是会把后面的元素都遍历了。而这里用some,一旦下面return 返回了true。那么后面没有遍历到的元素,他都不会再进行遍历了。这样节省一些时间。

    判断当前有子菜单,并且子菜单的数量不为0.

    递归,调用下自身。

    name还是那个name。参数2 就是item的children了。

    如果childArr的长度不为0的话,说明 上面是返回了。说明你当前遍历的这个路由对象,它的children里面,有一个路由对象它是当前激活的路由对象,

    把返回来的childArr和 arr 合并。

    最后把这个arr返回。



    这里是vuex,之前写错



    点击没展开


    如果激活的是表格的话,那么得到的应该有component.

    输出最后得到的值




    展开,iview的组件,需要手动的触发更新才会展开



    做一个监听。给菜单加一个ref

    监听,openNames这个变量。nextTick会保证你视图渲染完之后。再调用里面的逻辑。

    这样就自动打开父级菜单了。

    当前菜单是关闭的,当我点击文件夹这个tab

    点击后会展开父级别的菜单。

    标签关闭

    加一个可关闭的属性




    这里点击关闭后。实际上tabList里面的数据是没有清空的。

    所以我们不用它自带的关闭。这里有个on-tab-remove。当你点击差号关闭的时候,它会触发这个事件。但是还存在一个问题。你怎么在这里面处理你的tabList数组。

    自己实现tab的关闭

    label可以传入render函数。

    这里传一个labelRender函数,给它传一个render函数。

    默认参数是h就是我们的渲染函数

    这里我们需要给render函数传递一个当前的item参数


    所以这里我们要用到一个闭包。返回一个函数。

    在这里面做渲染

    渲染一个div

    看页面效果。tab是被渲染的。

    加一个图标,是关闭按钮。区别原来的差号,我们给它一个图标。


    给图标绑定一个事件。icon组件本身是没有事件的,所以我们要用nativeOn这个前缀来表示给icon组件最外层的标签绑定一个click事件。

    要给他传参数,这里要用bind

    关闭要去tabList里面删掉一个路由对象。还是要通过name、params、query这些信息找出来。

    把item传进去,调用方法getTabNameByRoute 上面方法接收id。

    当设置点击事件的时候,它其实会触发父级的点击事件。

    所以这里不希望事件冒泡。接收一个event对象。调用stopPropagation方法来阻止冒泡。


    移除方法,我们定义到store的action里面。
    我们返回一个Promise,因为我们还要做后续的操作。

    route加上$符号

    首先通过id获取当前的路由对象

    获取到这个路由对象之后呢,我们来找它的索引,这个路由对象在tabList数组里面是在哪个位置。使用findIndex方法,可以传入一个回调函数,通过这个函数传入你查找的条件,最后它会返回给你索引值。




    我们来比较一下,如果相等就返回。

    最后找到这个路由后,把它删掉。删除操作我们放到mutations里面去操作。

    commit提交一个mutation 传入索引

    页面内使用action




    测试

    点击关闭


    报了个错误


    输出看下id是什么


    再打印下,得到的路由




    传递的参数是一个对象,传入id 然后当前的路由对象。

    然后方法的名字也写错了,重新改一下

    点击关闭

    tab被关闭了。

    关闭了标签后,应该跳到别的页面

    例如有两个tab。关闭了一个tab 后,应该默认选中另外一个tab。


    所以在这要判断一下,这就是为什么要传当前那个路由对象

    做操作。关闭标签后,我们应该跳转到哪个页面。

    你要关闭的就是要打开的这个页的话。表示右边还有标签 那么就是下一个。


    如果当前打开的这个标签是最后一个。那么nextRoute就是它的前一个。




    最后获取下name、params、query.。如果取不到了 就默认用home_index来做跳转。

    把这三个值返回 回去,是个对象


    接收promise进行跳转

    测试


    关闭后 自动跳转到下一个。


    如果关闭的不是当前

    那么就直接关掉,不用走跳转。


    关闭最后一个

    那么现实的就是左边的tab

    本地存储tabList

    tabList是存在store里面的。一刷新页面就没了。

    utils里面定义两个方法



    tabLlist默认应该存localStorage中读取,如果有就读取,没有就是空数组。

    在这保存

    我们只存有用的,得到一个能够王localStorage里面存的列表。然后存map后的对象。



    这里删除后,也重新存一下


    刷新


    刷新后 依然存在,而且还能做跳转。



    在首页这,清空浏览器的缓存




    添加标签是在watch里面,监听route的变化。如果变化了就往里面添加。如果有就不往里面添加。



    点击表格,并没有往下面添加tab。好像没有监听到变化一样。


    ruter里面,首页是layout

    这里的父组件也是layout

    当下面的路由做变化的时候,/component这一级就变了。 这里你配置的是component.

    这里配置的是home

    这个路由变了,那么这个组件就会重新去渲染。

    它是在app.vue这里。是这个地方渲染改变了。

    所以这个layout组件。watch都没有进行,这个组件已经被注销又重新去渲染了。

    所以这里是没有生效的


    如果想让他有效果。把这个逻辑放到。app.vue

    替换这里




    方法也引用一下,复制过去








    layout之类相关的删掉就可以了

    再次测试

    先清空缓存。





    默认登陆页也被添加进来了。

    这里简单的做下过滤


    再次清空缓存,刷新页面重新来测试












    每次点击也都是做的跳转。


    以上多tab页就算是是开发完成了。

    本节代码


     

    结束

  • 相关阅读:
    js判断是否是ie浏览器且给出ie版本
    自定义的好看的单选复选框功能
    Gaze Estimation学习笔记(2)-It's Written All Over Your Face Full-Face Appearance-Based Gaze Estimation
    Gaze Estimation学习笔记(1)-Appearance-Based Gaze Estimation in the Wild
    软件工程个人总结博客
    软件工程结对编程博客
    软件工程第一次阅读作业
    软工第0次个人作业
    OO第四次博客作业
    OO第三次博客作业
  • 原文地址:https://www.cnblogs.com/wangjunwei/p/13611356.html
Copyright © 2011-2022 走看看