vue初识

186 阅读15分钟

框架的作用:

  • 1.为了替代jquery
    1. 内部出了模块问题,让开发者用起来更简单
    1. 直接调用就可使用
    1. 高效。不用自己写代码,并且运行快速
    1. 浏览器兼容性好
    1. 成本低

适用前端框架的规则

    1. 目录
    • public/static-->静态资源文件夹-->不会被webpack之类的工具编译 - img
    • stylesheet
    • js
      • 字体
  • src 源代码开发目录,也就是我们操作的主要核心目录
    • common 公共资源文件夹
    • assets 项目开发所需要的的静态文件夹-->会被webpack之类的工具编译
      • img
      • stylesheet
      • js
    • component 公共存放目录
      • Tab 项目头部
      • TabBar 项目底部
      • List 列表
    • router 路由配置文件夹
    • store 项目数据仓库文件夹
    • utils 项目的公共函数封装库
      • 大小写转换
      • 时间、日期、REM、cookie等
    • pages/views 项目核心页面
      • home
      • shopcar
      • user
      • catgory
      • detail
      • xxx

vue的发展历史

    1. 1.0 -->2014
    1. 2.0 -->2016
    1. 3.0 -->2019

vue是一个MVVM框架,实现了双向数据绑定

    1. 别名:
    • 深入响应式原理
    • 双向数据绑定原理
    • 数据响应原理
    1. 文字叙述:
    • Vue是通过数据劫持来实现深入响应式原理的,数据劫持指的是通过js的Object.dafinePerproty中的getter 和setter对数据进行拦截的,当第一次绑定数据时,会触发getter,对象的属性值改变时,会自动触发setter,进而修改视图内容

插值表达式(模板语法)

    1. 表达式语法一般会用在哪里?
    • 使用形式:参考后端 -ejs语法:<% %>
  • 2.js的支持
    • null和undefind是不会显示的,其他数据类型都是支持的,可以显示
    • 凡是全局对象绑定在window身上的在表达式中都不能使用
  • 3.如何使用:
    • 内容中使用
    • 属性中使用
      • 指令
      • 目的
      • 操作DOM(因为命令是直接绑定在DOM上的)
      • 属性的写法
        1. v-html:可以解析xml类型数据
        1. v-text:可以解析普通数据
      • 双向数据绑定效果指令
        • v-model (表单控制绑定)
        • 只能用于表单
        • v-model默认绑定value属性
        • VM改变V随之改变
        • V改变,VM也随之改变
      • 使用单向数据绑定来实现双向数据绑定
      • <input type="text" :val="msg" v-on:input="change"
      • p>{{msg}} p/> -对{}{}的支持:

      number: {{ num }}

      -

      string: {{ str }}

      -

      boolean: {{ bool }}

      -

      null: {{ nul }}

      -

      undefined: {{ und }}

      -

      object: {{ obj.name }}

      -

      array: {{ arr[ 1 ] }}

      -

      function: {{ fn() }}

      -

      {{ arr.join(',') }}

      -

      三目运算符: {{ 5 > 3 ? '成立' : '不成立' }}

      -

      短路原则: {{ 5 < 3 && '成立' || '不成立' }}

      - 单向数据绑定 - v-bind:="" - 将vue中数据赋值给属性值 - 简写: - :xx="" - 实现类名绑定: - 正常写法: -

      - 对象写法 - :class="{}" - 数组写法 - :class="[]" - 实现样式绑定: - 正常写法: -

      - 对象写法 - :style="{}" - 数组写法 - :style="[]"
  • 流程控制-条件渲染
      1. v-if
    • 控制的事元素的存在与否
      1. v-else-if
      1. v-else
      1. v-show条件展示 -控制的事元素的display:none属性 -以初始条件为假时,v-show的性能损耗较高
    • 频繁切换使用:v-show
    • 不是频繁切换:v-if -例子: -判断 -条件展示 -v-show = "f" 老王 -条件判断
    • 单路分支 -v-if = "flag" 距离放假2周
    • 双路分支
    • v-if = "flag"双路 - 1
    • v-else 双路 - 2
    • 多路分支
    • v-if = "text === 'A'" A
    • v-else-if = "text === 'B'" B
    • v-else> C
    • script:
    • new Vue:({ -el:""
      -data: {
    • f: false, -flag: false, -text: 'A' )}
  • 流程控制-循环(列表渲染)
  • 列表渲染参数最多可以写三个,分别为item,key,index
  • 列表渲染,要在渲染的元素身上加一个key,作为这个元素的唯一标识
    • 例子:
      • 数值
        • li v-for="(item,index) of num" :key=item.id>{{item }} -- {{ index }}</li
      • 字符
      • li v-for="(item,index) of str" :key=index>{{item }} -- {{ index }}</li -普通对象
      • li v-for="(item,key,index) of obj" :key=index>{{item }} --{{key}}-- {{ index }}</li
      • 数组
      • li v-for="(item,index) of arr" :key=index>{{item }} -- {{ index }}</li -普通json数据
      • li v-for="(item,index) of json" :key=index>{{item }} -- {{ item.id }}</li
      • 多层数据结构
      • ul> li v-for = "item of nestData" :key = "item.id"> h3> {{ item.name }} </h3
        {{ ele.name }}

    事件处理器

    • vue是通过{}{}语法来实现数据绑定效果的
    • 格式:
      • v-on:事件类型='事件处理程序'
    • 简写
      • @:事件类型='事件处理程序'
    • 使用:
      • 先申明在绑定事件
        • 先写好事件处理程序,然后再去绑定原生身上
        • 《button @click = "handler"> 普通事件 </button》
        • li v-for ="(item,index) of todos" :key = "item.id" button @click = "事件处理程序(index,item.task)"> 输出索引和任务内容 </button 《/li》
        • 如果一个函数中既有普通函数,又有事件对象
          • 使用event来代替事件对象 
-button @click = "事件处理程序(event,10 )"> 普通参数 + 事件对象 </button

    事件修饰符

    • 事件修饰符
      • stop stopPropagation()
      • prevent preventDefault()
      • self
      • xxxx
    • 重点记忆
      • stop
      • prevent
      • slef
      • once -使用
      • @click.stop
      • @click.once
      • @click.xxx

    按键修饰符

    • 按键修饰符是对键盘 事件的修饰
    • 键盘事件:keyup keydown keypress(按下再放起来之后)
    • 使用
      • @keyup="msg"
      • @keyup.13="msg"
      • @keyup.enter="msg"
      • @keyup.p="msg"
      • @click.right="msg"
      • xxx

    自定义事件

    • vm.$on-->自定义事件名称,自定义事件的事件处理程序
    • $emit-->触发自定义事件

    自定义指令

    • 全局定义
      • Vue.directive(指令名称,指令的配置项)
      • Vue.dirctive('focus',{
      • bind(el,binding,vnode,oloVnode),
      • inserted(el,binding,vode,oldVnode){
      • console.log( inserted -> el", el) // 当前元素
      • console.log("西阁: inserted -> binding", binding) // 指令的全部信息
      • console.log("西阁: inserted -> vnode", vnode) // 指令的元素对应的虚拟节点console.log("西阁: inserted -> oldVnode", oldVnode) // 指令的元素对应改变前的虚拟节点 } if ( binding.modifiers.xige ) { el.focus() } else { el.value = binding.value el.style.background = '#ccc' } },// inserted表示指令绑定的元素被插入页面时触发 // updated () {}, // 指令绑定的元素或其子元素发生改变时触发 // componentUpdate () {}, // 指令绑定的组件或其子组件发生改变时触发 unbind () { // console.log( 'unbind') } // 指令绑定的元素被删除 })
    • 局部定义
      • directives:{指令名,指令的配置}

    computed 计算属性

    • 是对已有数据进行计算和赋值
    • 好处
      • 1.逻辑还是交给vm处理
        1. 在模板中,使用全局变量一样使用
      • 3.如果计算是普通方法,那么这个计算不能改,安全,稳定 -注意 -计算属性如果是一个方法,这个方法后不加() -

        {{ num*2 }} </p》

    watch 侦听属性

    • watch: { firstName ( val ) { this.fullName = val + this.lastName }, lastName ( val ) { this.fullName = this.firstName + val }, num: { deep: true, // 深度监听
      handler ( val ) { // 当num发生改变时,触发的方法 console.log( val ) } } }
    • 总结:如何使用
      1. methods:事件处理程序
      1. watch又大量数据交互和异步处理时进行
      1. computed
      • 有逻辑处理
      • v中象全局变量一样使用

    混入

      1. 全局混入 Vue. minxin(不推荐)
      1. 局部混入 minxins
    • 作用:
      • 将选项中某一个或是多个单独分类出去管理,让职能更加单一高效,符合模块化思想

    key的重要性

      1. sameVode函数-->决定当前节点是否patch,如不相同,则节点将会销毁/添加
      1. createKeyToOldIdx 函数-->该函数的作用是 当 对比两个子节点数组时,建立 key-index映射代理遍历查找 sameNode.提高性能。
    • 总结
    • 1.key能够决定节点是否应该被删除、添加、修改,当节点被删除、添加时,会发生以下事件
      • 完整地触发组件的生命周期钩子
      • 触发过度
      1. 对比两个子节点数组时,建立key-index映射代替遍历查找sameNode,提高性能
    • 3.key值是每一个vnode的唯一标识,以便diff算法进行统计比较,我们可以更快的拿到oldVnode中相对应的节

    component:用来注册组件

    • 作用:
      • 组件化是为了解决多人协作冲突问题
      • 复用
    • 概念:
      • 组件是一个html、css、js、img等的一个聚合体
    • 属于扩展性功能
    • 通过Vue.extend()来扩展
    • 注册当前组建的名字,配置项:配置当前组件的模板以及组件所使用数据方法等等

    template:模板

      1. 特点:有且只能有一个根节点
      1. 官方推荐的模板写法,写在script标签内,一定要定义类型是x-template
    • 《script type="x-template" id=""》
      1. 在vue内配置template会替换掉我们当前绑定的元素
    • 适用于组件的嵌套

    组件通信

    • 为什么要进行通信
    • 组件是一个聚合体,将来项目要合并,那么必然各个组件之间需要建立联系,支个联系就是数据通信
    • data为什么是一个函数?
      • 组件是一个聚合体,也是一个整体,他需要一个独立的作用域,也就是他的数据需要是独立的,目前js的最大特点是函数式编程,而函数恰好提供一个独立作用域,所以我们data在除根组件外都是函数
    • 为什么data函数需要返回一个返回值,返回值还是对象,不能是数组吗?
      • vue通过es5的Object.definePerproty属性对一个对象进行getter和setter设置,而data选项是作为VUE深入响应式核心的选项
    • 分类
      • 父子组件通信
        • 过程:
        • 父组件将自己的数据通v-bind绑定在子组件身上
        • 子组件通过props属性接收
      • props属性数据验证
        • 验证数据类型
          • type:数据类型
        • 验证数据大小(判断条件)
          • validator(val){ return val>0 }-->验证函数
      • 子父组件通信(通过事件形式)
        • 是通过自定义事件
          • 事件的发布
            • 通过绑定元素身上实现
          • 事件的订阅
            • 通过this.$emit触发
      • 总结:
        • 父子组件通信、子父组件通信理解:
          • 父组件传给子组件的数据不能够直接在子组件内修改,能够修改父组件属性的只有父组件自己
            • 就是父组件通过props向下传递数据给子组件
          • 子组件如何与父组件通信:
          • 子组件要通过$emit()发布事件,然后父组件通过@子组件发布的事件,去执行对应的方法修改数据
      • bus事件总线
      • 使用场景: 可用于非关联组件之间的通信
      • 作用:
      • 触发事件和监听事件,巧妙而轻量的实现了任何组件间的通信
      • 具体实现方式
        • var Event=new Vue();
        • Event.$emit(事件名,数据);
        • Event.$on(事件名,data => {});
        • $on监听自定义事件,因为有时不能确定何时触发事件,一般会在mounted或created钩子中来监听

    axios&&fetch:数据请求

    • axios 对已获得的数据进行了一层封装XSRF

      • axios底层自动对数据进行了格式化
      • axios参数根据get和post决定
        • get请求 参数要通过data发送
        • post请求 参数要通过 params发送
          • 如果你直接使用npmjs.com官方文档,会有坑
          • 解决步骤
              1. 先设置请求头
              1. URLSearchParams的构造器函数得到params对象
            • 3.使用params对象身上的append方法进行数据的传参
    • fetch并没有进行封装,拿到就是格式化后的数据

      • fetch进行了多一层的格式化
        • res.json()
        • res.blob()格式化二进制
        • res.text()
      • 1.fetch的get请求的参数是直接连接在url上的,我们可以使用Node.js提供的url或是querystring模块来将Object-->String
        • fetch的请求返回值是promise对象,所以我们可以使用.then().catch(),但要记住.then()至少要写两个,第一个then是用来格式化数据的,第二个then是可以拿到格式化后的数据
        • 格式化处理方式有
          • fetch('./data.json') .then(res=>{ res.json() //res.text() res.blob() }) .then( data => console.log(data)) .catch( error => console.log( error ))

    过滤器

    • 特点:
      • 渲染格式化后的文本却不改变其本身内容
    • 作用
      • 文本数据格式化
    • 全局过滤器 filter -须在vue实例声明前定义过滤器,否则会出现检测不到过滤器的情况
    • {{ dateStr | date }}
    <div>{{ dateStr | date('YYYY-MM-DD hh:mm:ss') }}</div>
    - <script>
     Vue.filter('date', function(value, format) {
    // value 要过滤的字符串内容
    // format 过滤器的参数
     })
     </script>
    
    • 局部过滤器 filters
    • 局部过滤器是在某一个vue实例的内容创建的,只在当前实例中起作用
    • { data: {}, // 通过filters 属性创建局部过滤器 filters: { filterName: function(value) {} } }

    插槽

    • 可以写任何模板代码
      • 插槽用于决定将所携带的内容,插入到指定的某个位置,使得模块分块,具有模块化特质。
      1. 默认插槽
      • 《slot> 标题 </slot》
      1. 具名插槽
      • 顾名思义就是带名字的插槽
      • 通过给组件中间的元素起名slot 可以在组件中通过name去找对应的插槽解析
      1. 作用域插槽
      • 可以在组件内解析数据
      • 在template元素上添加属性slot-scope
      • 插槽中的内容不能访问父级作用域

    生命周期

    • 分为三个阶段,8个钩子函数
      1. beforeCreate:组件创建前:
      • 作用:
        • 为整个生命周期做准备工作,初始化实例的事件 和生命周期
      • 意义:
        • 数据拿不到
        • 真实DOM拿不到
      1. Created:组件创建结束:
      • 作用:
        • 初始化Data数据
      • 意义:
      • 数据可以拿到
      • 真实DOM拿不到
      1. beforeMount:组件挂载前:
      • 即将挂载编译后的HTML到对应位置时触发的函数
      • 内部完成事务:
          1. 先判断el选项-new Vue是否有el
          • 有,继续判断是否有template选项,证明有子组件
            • 有template,那么我们通过 render函数将jxs解析为VDOM对象模型
          • 无template,那么我们需要通过outHTML手动渲染
            • outHTML,元素外进行渲染,并且会代替原来的容器盒子,并且template在实例内会被解析,将来不会渲染到页面
        • 无 那么我们需要手动挂载
          • new Vue().$mount('#app')
      • 意义:
      • 数据可以拿到
      • 真实DOM没有拿到
      1. Mounted:组件挂载结束:
      • 这里是将编译好的HTML挂载到页面完成后执行的钩子函数,形成真实DOM(编译好的HTML替换vue实例上的el属性指向的DOM对象或替换对应的html标签里的内容)
      • 作用:
        • 发布HTML请求页面初始化需要的数据
      • 注意:
        • 这个函数在vue的整个生命周期中只会执行一次。如有页面数据的变化,会执行update函数来更新数据
      • 意义:
      • 数据可以拿到
      • 真实DOM可以拿到
      1. beforeUpdate 组件更新前
      • 作用:
        • 这里会实时监听data数据变化,如有更新,那么会重新渲染vdom
      • 意义:
        • 数据可以拿到
        • 真实DOM也可以拿到
      1. updated 组件更新结束
      • 作用:
        • VDOM重新渲染,然后通过render函数解析为VDOM对象模型,在通过Diff进行比对生成patch补丁对象,然后重新渲染为真实DOM
        • 只改变变化的部分,其他部分不改
      1. beforeDestroy 组件销毁前
      • 外部销毁
        • 通过开关完成
          • DOM被删除了
          • 组件也被删除了
    • 8.destroy 组件销毁结束
      • 内部销毁
        • 通过调用$destroy()来完成
          • DOM没有被删除
            • 需手动删除
          • 组件被删除了

    vue/cli[脚手架]

    • 什么是cli?
      • cli是vue提供的一个用来快速构建项目环境的一个工具,底层使用的是webpack
    • 使用
      • cli的安装
        • npm换源:npm config set registry registry.npmjs.org
          • 使用淘宝镜像加速
        • npm i @vue/cli -g//$yarn global add @vue/cli
      • 验证是否安装成功
        • $ vue 看是否有东西输出,如果输出命令提示,证明安装成功
      • 查看版本号:$vue --version
      • vue create +项目名称
      • 启动本地服务器:npm run serve// $yarn serve
      • 生产模式下,把写好的内容进行编译打包,最后部署到服务器上
        • npm run build 或者yarn build
      • 查看当前项目默认的webpack配置信息
        • $vue inspect
      • 在当前项目中安装插件
        • vue add [plugin]
      • 以图形化界面创建和管理项目
        • vue ui
      • 修改默认的webpack配置
        • 先创建vue.config.js 文件,在这个文件中修改相关配置

    分析目录

    • node_modules 项目的依赖包
      • cli3 webpack配置放在node_modules中
    • public 静态资源目录( 生产环境 )【 这个目录下的静态资源不会被webpack 编译 】
      • img
      • js
      • CSS
      • favicon.ico 项目标题的logo
      • index.html 根实例组件的模板,也是整个项目的容器
    • src 源代码开发目录( 也是开发者主要开发的目录文件夹 )
      • assets 开发环境的静态资源目录 ( 这个目录中的资源会被webpack编译)
        • assets中如果图片的小小 < 4K 我们就将这个图片转化成 base64
        • base64它是我们前端处理图片的一种形式,将图片路径进行编码,它可以减少一次ajax请求,达到前端性能优化的一个方案,但是base64有一个弊端,这个弊端就是会污染html结构
      • components 组件存储目录
        • xxx.vue文件 单文件组件 一个vue文件就是一个组件
          • 组成部分:
            • template模板 ( 必须写的 )
            • script脚本 ( 可写可不写)
            • style样式 ( 可写可不写 )
              • scoped 作用是可以减少命名冲突,规定一个样式的作用域
    • gitignore git上传忽略文件配置
    • babel.config.js 优雅降级配置文件 用来将es6 --> es5
    • package.json 整个项目的依赖配置文件
    • README.md 整个项目启动的说明性文件
    • .browserslistrc 浏览器版本的支持
    • postcss.config.js 项目css预处理的配置
    • package.lock 整个项目的依赖性文件的信息

    cli导入导出

    • 它是 webpack + es6模块化来集中实现的
      • es6模块化:
      • 模块的定义 const obj = {} const fn = function(){}
      • 模块的导出有两种形式
        • export default //默认导出一个
        • export // 批量导出,导出多个
      • 模块的引入
        • export default 导出 import xxx from '../xxx.xx'
        • 如果是export 导出
        • improt { xx } from '../xx.xx' || import * as xx from '../xx.xx'
    • 特殊说明
      • cli3 将webpack配置放在 node_modules,所以Vue并不希望大家去修改这部分webpack配置 如果我们将来需要更改webpack配置,那么我们需要在 项目 根目录 下创建一个 vue.config.js文件

    vue-router

    • 是构成 SPA( single page App )单页面应用 的关键技术
      • 多页面应用 有多个html文件,通过a标签的连接联通各个页面
      • 缺点:
        • 开发起来太冗余,编译、压缩很耗时间
        • 页面之间的跳转速度太慢,这个时候就会出现一个严重的问题,白屏
    • 单页面应用
      • 不需要刷新页面,因为它就是一个页面
      • 这个页面内容在切换
      • 单页面内容之间的切换要想实现我们就是用路由
      • 如今我们的app、后台管理系统 主要的开发形式就是spa
    • vue-router-基础:
      • 1.vue 路由的mode(模式)有几种, 分别是什么?在那些环境下运行?
        • 。 hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。 #/home
        • history: 依赖 HTML5 History API 和服务器配置。【需要后端支持】 /home
        • abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。【 这个模式不常用 】
        • 总结:
          • hash/history 常用于浏览器端,abstract用于服务端
    • 2.路由的使用步骤
      • i. 安装 vue-router yarn add vue-router
      • ii. 在src目录下创建一个router目录, 里面创建一个index.js文件 , 这个目录就是router的模块
      • 安装stylus npm install stylus stylus-loader --save-dev
      • iii. 引入第三方的依赖包, 并注册路由:
        • 注意: import这个关键字要放在整个文件的上
          • import Vue from 'vue'
          • import VueRouter from 'vue-router'
          • Vue.use( VueRouter ) //使用vue-router这个第三方插件
      • iv. 创建了一个router对象实例,并且创建路由表
        • const routes = [
        • {
        • path: '/home',
        • component: Home
        • }//每一个对象就是一个路由
        • ]
        • const router = new VueRouter({ -routes//路由表 必写的
        • })
      • v. 导出router实例
        • export default router{routes}
      • vi. 入口文件main.js中引入路由实例 router , 然后在根实例中注册
        • import router from './router/index.js'
        • new Vue({
          • router,
          • render: (h) => App
          • }).$mount('#app')
      • vii.给路由一个路由展示区域
      • 如果是以及路由, 那么我们放在App组件中,用一个 的组件表示
        • 他是承载路由注册后组件的集合
      • viii.当页面第一次的打开的时候, 需要做一个重定向, 就是要自动跳转到 /home 这个路由上
        ​ - const routes = [
        • { //我们要求这个路由的配置要放在路由表的最上方
        • path: '/',
        • redirect: '/home'
        • } -]
      • ix.业务: 错误路由匹配 - const routes = [ - { - path: '/error', - component: Error - }, - { //这个就是错误路由匹配, vue规定这个必须放在最下面,它必须将上面的路由全找一遍,找不到才用当前这个
        • path: '**',
        • redirect: '/error'
        • }
        • ]
      • x.vue路由模式的确定 mode
        • i.如果你使用的是 hash , 那么a标签就可以了
        • ii.如果你使用 history , 那么我们最好将a标签改成 router-link 这个组件
        • router-link 这个组件 身上必须要有一个 to 属性
          • 路由跳转:
            • 放在App组件中 router-link to="/" exact>首页</router-link
        • router-link 这个组件身上加一个 keep-alive属性可以进行浏览器缓存
      • xi.二级路由
        • 注意: 写好配置之后,不要忘记了, 在对应的一级路由的组件中书写 路由展示区域:放在Shopcar组件中router-view></router-view
        • const routes = [
        • {
          • path: '/shopcar',
          • component: Shopcar,
          • children: [
          • {
          • path: 'yyb', //不写 /
          • component: Yyb
          • }
          • ] -}
        • ]
      • xii.命名路由
        • 作用: 就是简写路径了
        • 使用: 单项数据绑定to属性 -放在App组件中 router-link :to = "{name:'yyb'}"/>
        • .{
        • path: '/shopcar', -component: Shopcar, -//子路由 -children: [ -{
        • path: 'yyb', // 容易犯错点 /yyb X
        • component: Yyb,
        • name: 'yyb' //命名路由
        • },
        • {
        • path: 'junge',
        • component: Junge
        • }
        • ]
        • }
      • vue路由-进阶 --> 动态路由
        • 核心功能: - 路由传参 - 路由接参

        • 动态路由:url中路由是改变的,但是改变路由公用一个组件 -​ export default new Router({

                   mode: "history",
                 
                   routes: [{
                 
                 ​    path: "/",
                 
                 ​    component: Index,
                 
                 ​    //配置子路由
                 
                 ​    children: [{
                 
                 ​      path: "a",//子路由的配置path不要加/
                 
                 ​      component: A
                 
                 ​    }]
                 
                   },
                 
                   {
                 
                 ​    path: "/Login",
                 
                 ​    components: {
                 
                 ​      default: Login,
                 
                 ​      a: A
                 
                 ​    }
                 
                   }, {
                 
                 ​    path: "/Datile",
                 
                 ​    component: Datile
                 
                   },
                 
                   {
                 
                 ​    //动态路由
                 
                 ​    path: "/Datile:ids",
                 
                 ​    component: B,
                 
                 ​    children: [{
                 
                 ​      path: "a",
                 
                 ​      componenet: A
                 
                 ​    }, {
                 
                 ​      path: "a/:xx",
                 
                 ​      componenet: A
                 
                 ​    }]
                 
                   }
                 
                   ]
                 
                 })