您当前位置: 南顺网络>> 官方资讯>> 建站知识

和尤雨溪一起进阶vue

1 初级版

借助vue的动态组件,可以实现一个简单的路由功能,如下

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> 
<div id="app">     
    <a href="#foo">foo</a>     
    <a href="#bar">bar</a>     
    <component :is="url"></component> 
</div> 
<script>     
// 这是一个比较简单的解决方案,但是有一个问题,初始化的时候无法匹配  
   window.addEventListener('hashchange', () => {         
       app.url = window.location.hash.slice(1)     
    });    
    let app = new Vue({       
      el: '#app',         
      data() {          
         return {              
            url: null             
            }        
         },         
       components: {         
           foo: {template: `<div>foo-component</div>`},             
           bar: {template: `<div>bar-component</div>`}        
         }     }) 
 </script>

2 改进版

解耦微改进一下,将路由提取到一个路由表中,

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> 
<div id="app"> </div> 
<script> 
    const Foo = {template: '<div>foo</div>'} 
    const Bar = {template: '<div>bar</div>'} 
    const NotFound = {template: '<div>not found</div>'} 
    // 在对象里面统一配置路由 
    const routeTable = {     'foo': Foo,     'bar': Bar }
     window.addEventListener('hashchange', () => {     app.url = window.location.hash.slice(1) }) 
     let app = new Vue({     
         el:'#app',         
         data() {         
             return {            
                  url: window.location.hash.slice(1)         
               }  },        
         render(h) {          
            return h('div', [             
                h('a', {attrs: {href: '#foo'}}, 'foo'),            
                     '|',               
                       h('a', {attrs: {href: '#bar'}}, 'bar'),                
                       h(routeTable[this.url] || NotFound),           
                         ])        
                          } })
 </script>

3 最终版

上面都是处理简单的url, 实际开发的时候,配置的路由都是多页面,多组件,路由的path也会比较长,如/a/b, /a/b/c, 还有动态路由,比如/a/:id,这个时候上面的方法就不能准确匹配了, 如果你是正则达人,你可以自己试试解析这些复杂的path,不是的话就使用别人封装好的第三方库吧,这里推荐path-to-regexp, 这个库的作用作者一句话就概述完了:

Turn a path string such as/user/:nameinto a regular expression

大家可以点进去链接了解一下用法,这里我们介绍接下来要用的部分

const keys = [] const regexp = pathToRegexp('/foo/:id', keys) // regexp = /^\/foo\/((?:[^\/]+?))(?:\/(?=$))?$/i // keys = [{ delimiter: "/", name: "id", optional: false, partial: false, pattern: "[^\/]+?", prefix: "/", repeat: false}] // 得到了正则表达式regexp, 传入实际的url执行正则的exec方法 // 不匹配 const match1 = regexp.exec('/test/route'); // null const match3 = regexp.exec('/foo');        // null // 匹配 const match2 = regexp.exec('/foo/fooId'); // ["/foo/fooId", "fooId", index: 0, input: "/foo/fooId", groups: undefined] 复制代码

ok, 我们可以解析path了,来看看接下来如何实现

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> 
// 这里是下载到本地同目录引入的 
<script src='./path-to-regexp.js'></script> 
<div id="app"></div> 
<script>   
  const Foo = {      
     props: ['id'],         
     template: `<div>foo with id: {{id}} </div>`     
     }     
     const Bar = {      
        template: `<div>bar</div>`    
         }     
     const NotFound = {      
        template: `<div>not found</div>`   
        }     
     const routeTable = {         '/foo/:id': Foo,         '/bar': Bar,     }    
      // 处理路由     
      const compiledRoutes = [];     
      Object.keys(routeTable).forEach(path => {      
         const dynamicSegments = []         
         const regex = pathToRegexp(path, dynamicSegments)         
         const component = routeTable[path]         
         compiledRoutes.push({         
             component,             
             regex,             
             dynamicSegments        
          })     })     
          window.addEventListener('hashchange', () => {      
             app.url = window.location.hash.slice(1);     
            })     
            const app = new Vue({      
               el: '#app',         
               data() {         
                   return {             
                       url: window.location.hash.slice(1)           
                         }        
                          },        
             // 渲染那个路由,路由属性         
             render(h) {         
                 const url = '/' + this.url             
                 let componentToRender             
                 let props = {}             
                 compiledRoutes.some(route => {              
                    const match = route.regex.exec(url)                 
                    if (match) {                
                         componentToRender = route.component                     
              // 上一步已经可以匹配到url对应的组件了                   
              // 这里多做一步,获取动态id作为props的属性传入组件                     
              route.dynamicSegments.forEach((segment,index) => {                     
                  props[segment.name] = match[index+1]                    
                   })                
                    }           
                      })            
               return h('div', [             
                   h('a', { attrs: { href: '#foo/123' } }, 'foo123'),                
                    '|',                
                     h('a', { attrs: { href: '#foo/234' } }, 'foo234'),                 
                     '|',                 
                     h('a', { attrs: { href: '#bar' } }, 'bar'),                
                     h(componentToRender || NotFound, { props })            
                    ])       
                    } 
                     }) 
              </script>




编辑:--史志成