利用vue-router和compoment重構代碼--踩坑(一)

業務主要功能

  • 獲取全部的數據庫列表javascript

  • 點擊某一個數據庫列表的時候,右側分頁展現數據css

  • 點擊右側某一條數據的時候,現實數據詳情html


如下是以前的頁面,存在如下問題:

  • 前段開發沒有工程化(webpack)vue

  • 主要功能耦合,列表,詳情,(檢索,重構的是爲了加功能方便)java

  • 左側的數據庫連接是直接跳頁的,分頁的連接是跳頁的,右側點擊的詳情頁倒是vue-resource加載的webpack

  • 代碼結構混亂,以前爲了快速實現功能。全部代碼寫在一個文件上。難讀。web

功能效果圖

數據列表頁效果



數據詳情效果



代碼重構思路

  • 前段模塊化開發,用webpack,參考我vue-router

  • 利用compoment組件化,組件化原則:組件只須要告訴別本身什麼狀態,狀態自治。組件不要去要求別的組件作什麼數據庫

  • 由於用vue就要體驗spa,根據頁面功能,利用vue-router配置頁面路由編程


重構開始

  1. 由於功能少,因此就略過了 前段模塊化開發,用webpack,參考我這篇

  2. 由於以前全部代碼都是寫在一個文件的,如今爲了代碼清晰易讀易擴展,將前段js代碼拆分爲三個文件

    compoments.js對應抽離的組件

router.js配置路由文件

show_database.js vue實例

  1. 分別將頁面抽成6個組件

itemsNumber--顯示數據條數

databaseLists--左側數據庫列表

itemsLists--右側數據列表

pagination --底部的分頁

itemDetail --詳情頁

listCompoment --vue-router用到的組件包含itemsListspagination

  1. 頁面路由暫時分紅列表/core/:core和詳情/detail/:id兩個路由,之後還有個檢索頁的路由

由於數據列表和詳情的數據是獨立接口獲取的,這樣分符合功能
(想了好久,沒想到更好地想法,第一次接觸vue-router,一邊文檔,一邊coding)


重構中---踩坑--填坑

1、填坑工具

2、遇到的那些坑

  • vue-router文檔中的一些功能只有在新版本中才有效,一開始怕3.0太冒進了,就選了個2.0,一段時間後發現一些功能死活不成功如:router.push等。細看文檔。原來是新版本特有的。因此之後看選版本要對着文檔選,實在不行就選擇最新的大版本,如3.0

  • vue-router中如何給組件傳props?細看文檔向路由組件傳遞 props搞定

  • vue-router中如何監聽路由組件中的事件?由於路由組件listCompoment獲取到數據庫列表中須要向外發送找到的數據

    //發送找到的數據
              this.$emit('num-found',this.numFound);

    我記得在官方文檔經過事件向父級組件發送消息
    v-on:num-found在組件上監聽是官方文檔的作法。可是路由組件怎麼綁定事件呢?$emit的事件是能夠用$on來接受的?;然而試了不能夠;

折騰了好久,直接電話老同窗,得知能夠直接在router-view中綁定事件監聽

router-view(v-on:num-found='getnumFound')
  • 若是是觸發事件是包含大寫的卻不能成功

    this.$emit(:'numFound',this.numFound);
    v-on:numFound

  • 。。。。。。未完待續

貼代碼

  • templates/views/show_database/show_database.pug

    extends ../../layouts/default
      include ../../mixins/footer-js
      include ../../mixins/search_components
      block css
          link(rel="stylesheet", href="/styles/document/document_search.css")    
          style.
              .result_static {
                  padding: 15px 0;
                  margin-bottom: 20px;
                  border: #BDE8F2 1px solid;
                  background-color: #EFF6FA;
                  text-align: center;
                  font-size: 14px;
              }
              .result_static strong {
                  color: #F30;
                  font-size: 18px;
                  font-weight: normal;
                  padding: 0 5px;
              }
              .show_database_item{
                  border-bottom: 1px solid #e5e6e7;
                  margin-top: 15px;
                  padding-bottom: 5px;
              }
              .show_database_item h4{
                  color: #259;
                  box-sizing: border-box;
                  font-size: 14px;
                  font-weight: bold;
                  letter-spacing: 1px;
                  line-height: 16px;
                  text-align: left;
              }
              .show_database_item p{
                  font-weight: normal;
                  text-align: left;
                  word-break: break-all;
                  color: #222;
                  letter-spacing: 1px;
                  font-size: 13px;
              }
      block content
          script(type='text/x-template',id='items_number')
              div.result_static 找到相關數據
                  strong(v-text='number || 0')
                  | 條
          script(type='text/x-template',id='database_lists')
              .list-group
                  a.list-group-item(v-on:click='jumpNew(core.core._id,50,0)',href='javascript:void(0);',v-for="(core,index) in cores",v-bind:key="index", v-bind:class="{'active':core.core._id==currentId}",v-text="core.core.alias || core.core.name")
          script(type='text/x-template',id='items_lists')
              div
                  .col-xs-12(v-for="(item,index) in data",v-bind:key="index")
                      div.show_database_item
                          h4 {{ parseInt(start)+(index+1)}}、
                              a(href='javascript:void(0);',v-on:click.prevent="showDetail(item.id)",v-text="item.name || item.Title || item.title || item.productname")
                          p {{item | content}}
          script(type='text/x-template',id='item_detail')
              .col-xs-12.col-sm-8.col-md-9(v-if="isShowDetail")
                  .row
                      .col-xs-12
                          h5(v-on:click="backFn") 
                              a(href='javascript:void(0);') <<返回
                      .col-xs-12
                          table.table.table-bordered.table-striped(v-if="tableData.length")
                              tbody
                                  tr(v-for="(item,index) in tableData",v-bind:key="index")
                                      td.text-center(v-text="item.name")
                                      td(v-text="item.value")
          script(type='text/x-template',id='pagination')
              div.text-center
                  nav(aria-label="Page navigation")
                      ul.pagination
                          li(v-for="item in pagesList",v-bind:class="{'active':item.show}")
                              a(v-bind:href="''+item.link")
                                  span(v-text="item.label")
          script(type='text/x-template',id='items_search')
          script(type='text/x-template',id='list_compoment')
              .col-xs-12.col-sm-8.col-md-9
                  .row
                      items-lists(v-bind:data='data',v-bind:show-detail='showDetail',v-bind:start='start')
                      pagination(v-bind:pages-list='pagesList')
    
          .row#app
              //- .patent-search-div.row
                  if normalInfo && normalInfo.title
                      div.patent-info.col-sm-3.text-center !{normalInfo.title}
                  else
                      div.patent-info.col-sm-3.text-center 檢索
                  .patent-search-main.col-sm-9
                      //檢索框
                      +searchBox(normalInfo,keyword)
              .col-xs-12.col-sm-4.col-md-3
                  items-number(v-bind:number='numFound')
                  database-lists(v-bind:cores='cores',v-bind:current-id='currentId',v-bind:jump-new='jumpNew')
              //- .col-xs-12.col-sm-8.col-md-9(v-if="!isShowDetail")
                  .row
                      items-lists(v-bind:data='data',v-bind:show-detail='showDetail',v-bind:start='start')
                      pagination(v-bind:pages-list='pagesList')
              //- item-detail(v-bind:is-show-detail='isShowDetail',v-bind:table-data='tableData',v-bind:back-fn='closeDetail')
              router-view(v-on:num-found='getnumFound')
      block page-js
          script(src="https://cdn.bootcss.com/vue/2.5.16/vue.js")
          script(src="https://cdn.bootcss.com/vue-resource/1.5.0/vue-resource.js")
          script(src="https://cdn.bootcss.com/vue-router/3.0.0/vue-router.js")    
          //- script(src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js")
          //- script(src="https://cdn.bootcss.com/vue-resource/1.5.0/vue-resource.min.js")
          //- script(src="https://cdn.bootcss.com/vue-router/3.0.0/vue-router.min.js")
          script(src="/js/show_database/compoments.js")
          script(src="/js/show_database/router.js")    
          script(src="/js/show_database/show_database.js")
  • public/js/show_database/show_database.js

    var vm = new Vue({
          el:'#app',
          data:{
              name:'show_database',
              cores:[],
              currentId:'',
              currentCore:'',
              data:[],
              numFound:0,
              start:0,
              rows:50,
              pagesList:[],
              tableId:'',
              isShowDetail:false,
              detailData:{},
              tableData:[]
          },
          created:function () {
              this.$on('num-found',function (num) {
                  console.log(num);
              })
          },
          mounted:function  () {
              console.log(this.$router.params);
    
              // if (this.$router.params.core) {
              //     this.currentId = this.$router.params.core;
              // }
              // if (this.$router.query.rows) {
              //     this.rows = this.$router.query.rows;
              // }
    
              // if (this.$router.query.start) {
              //     this.start = this.$router.query.rows
              // }
    
              if (location.search) {
                  var search = location.search.slice(1,location.search.length);
                  var l = search.split('&&');
                  for (var index = 0; index < l.length; index++) {
                      var  element = l[index];
                      var ll = element.split('=');
                      if (ll.length&&ll[0]&&ll[1]&&ll[0]=='start') {
                          this.start = ll[1];
                          console.log(ll[1]);
    
                      }
                      if (ll.length&&ll[0]&&ll[1]&&ll[0]=='rows') {
                          this.rows = ll[1];
                          console.log(ll[1]);
    
                      }
                      if (ll.length&&ll[0]&&ll[1]&&ll[0]=='id') {
                          this.currentId = ll[1];
                          console.log(ll[1]);
    
                      }
                  }
              }
              //獲取全部的數據庫,過濾後返回
              this.$http.get('/api/core')
              .then(function (response) {
                  if (response&&response.body.result) {
                      this.cores = response.body.result.filter(function (core) {
                          if (core.core.core&&core.core.core.indexOf('newscore')>-1) {
                              return false;
                          }
                          return core.core.core;
                      })
                      if (!this.currentId&&this.cores.length) {
                          this.currentId = this.cores[0].core._id || '';
                          this.tableId = this.cores[0].core._id || '';
                          // this.getDatabaseData(this.currentId);
                          this.$router.push({ name: 'core', params: {
                              core: this.currentId,
                              rows:this.rows,
                              start:this.start
                          },
                          query: { 
                              rows: this.rows,
                              start:this.start
                           }
                      })
                      }
                      var id = this.currentId;
                      var tableId,currentCore;
                      this.cores.filter(function (core) {
                          if (core.core._id == id) {
                              tableId = core.core._id
                              currentCore = core;
                          }
                          return false;
                      });
                      if (tableId) {
                          this.tableId = tableId;
                      }
                      if (currentCore) {
                          this.currentCore = currentCore;
                      }
                  }
              }).catch(function (err) {
                  console.log(err);
              });
    
              if (this.currentId) {
                  // this.getDatabaseData(this.currentId);
                  console.log(this.currentId,'dfdfdsfsdfsdf');
    
                  this.$router.push({ name: 'core', params: {
                      core: this.currentId,
                      rows:this.rows,
                      start:this.start
                  },
                  query: { 
                      rows: this.rows,
                      start:this.start
                   }
              })
              }
          },
          methods:{
    
              //獲取數據        
              // getDatabaseData(id){
              //     var id = id || this.currentId;
              //     this.currentId = id;
              //     var url = '/api/collection/search/'+id+'?start='+this.start+'&&rows='+this.rows;
              //     this.$http.get(url)
              //     .then(function (response) {
              //         console.log(response);
              //         this.data = response.body.result.docs;
              //         this.numFound = response.body.result.numFound;
              //         this.pagesList = getPageList(this.numFound,this.rows,this.start,'/show_database?id='+this.currentId)
              //     }).catch(function (err) {
              //         console.log(err);
              //     });
              // },
              // 展現詳情
    
              //監聽num-found事件
              getnumFound(num){
                  this.numFound = num;
              },
              showDetail(id,evt){
    
                  if (!id || !this.tableId) {
                      return ;
                  }
                  var url = '/api/collection/search/'+this.tableId+'/'+id;
                  this.$http.get(url).then(function (response) {
    
                      if (response.body.success) {
                          this.detailData = response.body.result;
                          this.isShowDetail = true;
                      }else{
                          alert(response.body.message)
                      }
                  }).catch(function (err) {
                      console.log(err);
    
                  });
              },
              closeDetail(){
                  this.isShowDetail = false;
              },
              //TODO 重構
              jumpNew(core,rows,start){
                  this.currentId = core;
                  this.$router.push({ name: 'core', params: {
                      core: core,
                      rows:rows,
                      start:start
                  },
                  query: { 
                      rows: rows,
                      start:start
                   }
                  })
              }
    
          },
          watch:{
              detailData:function (nv,ov) {
                  console.log(nv,ov);
    
                  if (nv) {
                      var arr = [];
                      for (var key in nv) {
                          if (nv.hasOwnProperty(key)) {
                              var e = nv[key];
                              var obj = {
                                  name:'',
                                  value:''
                              };
                              obj.value= e;
                              //獲取中文名稱
                              if (this.currentCore&&this.currentCore.schema&&this.currentCore.schema.length) {
                                  obj.name =  getAlias(this.currentCore.schema,key)
                              }
                              arr.push(obj);
                          }
                      }
                      this.tableData = arr;
                  }
              }
          },
          components:{
              'items-number':itemsNumber,//結果數目顯示
              'database-lists':databaseLists,//數據庫列表展現
              'items-lists':itemsLists,//數據列表展現
              'pagination':pagination,//分頁
              'item-detail':itemDetail,//詳情
              'list-compoment':listCompoment
          },
          router:router
      })
  • public/js/show_database/compoments.js

    var itemsNumber = {
          template:'#items_number',
          props:['number'],
      };
      var databaseLists = {
          template:'#database_lists',
          props:['cores','currentId','jumpNew'],
      };
      var itemsLists = {
          template:'#items_lists',
          props:['data','showDetail','start'],
          filters:{
              content:function (value) {
                  var ss = '';
                  // console.log(value);
                  if (!value) {
                      return ss;
                  }
                  if (typeof value =='string') {
                      return value;
                  }
                  if (typeof value =='object') {
                      for(var key in value){     
                          //獲取中文名稱
                          var name = key;
                          if (vm.currentCore&&vm.currentCore.schema&&vm.currentCore.schema.length) {
                              name =  getAlias(vm.currentCore.schema,key)
                              // console.log(name);
    
                          }
                          if (value.hasOwnProperty(key) === true && key!='id'){  
                              var s = name+':'+value[key]+';'
                              ss+=s;
                          }                 
                      }  
                  }
                  if(ss&&ss.length>200){
                      ss = ss.slice(0,200)+'...'
                  }
                  return ss;
              }
          }
      };
      var pagination = {
          template:'#pagination',
          props:['pagesList']
      };
    
      var itemDetail = {
          template:'#item_detail',
          props:['isShowDetail','tableData','backFn']
      }
      var listCompoment = {
          template:'#list_compoment',
          // props:['data','showDetail','start','pagination'],
          props:['core','rows','start'],
          components:{
              'pagination':pagination,//分頁
              'item-detail':itemDetail,//詳情
              'items-lists':itemsLists
          },
          data:function () {
              return {
                  data:[],
                  showDetail:false,
                  pagination:[],
                  numFound:0,
                  currentId:'',
                  pagesList:[]
              }
          },
          methods:{
              //獲取數據        
              getDatabaseData(id){
                  var id = id || this.currentId;
                  this.currentId = id;
                  var url = '/api/collection/search/'+id+'?start='+this.start+'&&rows='+this.rows;
                  this.$http.get(url)
                  .then(function (response) {
                      // console.log(response);
                      this.data = response.body.result.docs;
                      this.numFound = response.body.result.numFound;
                      //發送找到的數據
                      this.$emit('num-found',this.numFound);
                      this.pagesList = getPageList(this.numFound,this.rows,this.start,'/show_database?id='+this.currentId)
                  }).catch(function (err) {
                      console.log(err);
                  });
              }
          },
          created:function () {
              console.log(this.$route.params)
              // console.log(this.core,this.rows,this.start)
              this.getDatabaseData(this.core);
          },
          watch:{
              '$route':function (to, from) {
                  this.getDatabaseData(this.core);
                  console.log(to,from);
    
              }
          }
      }
      function getAlias(schema,name) {
          if (!schema || !name || !schema.length) {
              return '';
          }
          var alias=name;
          for (var index = 0; index < schema.length; index++) {
              var e = schema[index];
              if (e.name && e.name == name && e.alias) {
                  alias = e.alias;
                  break;
              }
          }
          return alias;
      }
      function getPageList(total, rows, start, url) {
        var rtn = getPagesInfo(total, rows, start);
        var pages = rtn.pages;
        var _out = [];
        if (rtn.currentPage != 1) {
          _out.push({
            label: '上一頁',
            link: url+'&&start='+rows*(rtn.previous - 1)+'&&rows='+rows
          //   link: toSearch(query, 'start', (rtn.previous - 1) * rtn.rows)
          })
        }
        if (rtn.pages.indexOf(1) < 0) {
          _out.push({
            label: '首頁',
            link: url
          //   link: toSearch(query, 'start', 0)
          })
        }
        pages.map((p, i) => {
          _out.push({
            show: p == rtn.currentPage,
    
            link: p == '...' ? "" : url+'&&start='+rows*(p-1)+'&&rows='+rows,
          //   toSearch(query, 'start', (p - 1) * rtn.rows),
          //   link: p == '...' ? "" : toSearch(query, 'start', (p - 1) * rtn.rows),
            label: p
          })
        })
        if (rtn.pages.indexOf(rtn.totalPages) < 0) {
          _out.push({
            label: rtn.totalPages,
            link: url+'&&start='+rows*(rtn.totalPages - 1)+'&&rows='+rows,
          //   toSearch(query, 'start', (rtn.totalPages - 1) * rtn.rows)
          //   link: toSearch(query, 'start', (rtn.totalPages - 1) * rtn.rows)
          })
        }
        if (rtn.currentPage != rtn.totalPages) {
          _out.push({
            label: '下一頁',
            link: url+'&&start='+rows*(rtn.next - 1)+'&&rows='+rows,
          //   toSearch(query, 'start', (rtn.next - 1) * rtn.rows)
          //   link: toSearch(query, 'start', (rtn.next - 1) * rtn.rows)
          })
        }
        return _out;
      }
    
      function getPagesInfo(total, rows, start) {
        total = parseInt(total);
        rows = parseInt(rows);
        start = parseInt(start);
        var totalPages = Math.ceil(total / rows);
        var currentPage = parseInt(start / rows) + 1;
        var pagaSize = rows;
        var rtn = {
          total: total,
          currentPage: currentPage,
          totalPages: totalPages,
          pages: [],
          previous: (currentPage > 1) ? (currentPage - 1) : false,
          next: (currentPage < totalPages) ? (currentPage + 1) : false,
          first: 0,
          last: totalPages * pagaSize,
          rows: pagaSize,
        };
        getPages(rtn, 10);
        console.log(rtn);
    
        return rtn;
      }
    
      function getPages (options, maxPages) {
          var surround = Math.floor(maxPages / 2);
          var firstPage = maxPages ? Math.max(1, options.currentPage - surround) : 1;
          var padRight = Math.max(((options.currentPage - surround) - 1) * -1, 0);
          var lastPage = maxPages ? Math.min(options.totalPages, options.currentPage + surround + padRight) : options.totalPages;
          var padLeft = Math.max(((options.currentPage + surround) - lastPage), 0);
          options.pages = [];
          firstPage = Math.max(Math.min(firstPage, firstPage - padLeft), 1);
          for (var i = firstPage; i <= lastPage; i++) {
              options.pages.push(i);
          }
          if (firstPage !== 1) {
              options.pages.shift();
              options.pages.unshift('...');
          }
          if (lastPage !== Number(options.totalPages)) {
              options.pages.pop();
              options.pages.push('...');
          }
      }
  • public/js/show_database/router.js

    // 0. 若是使用模塊化機制編程,導入Vue和VueRouter,要調用 Vue.use(VueRouter)
    
      // 1. 定義(路由)組件。
      // 能夠從其餘文件 import 進來
      // var Foo = { template: '<div>foo-><router-link to="/bar">Go to Bar</router-link></div>' }
      // var Bar = { template: '<div>bar-><router-link to="/foo">Go to Foo</router-link></div>' }
    
      // 2. 定義路由
      // 每一個路由應該映射一個組件。 其中"component" 能夠是
      // 經過 Vue.extend() 建立的組件構造器,
      // 或者,只是一個組件配置對象。
      // 咱們晚點再討論嵌套路由。
      var routes = [
        { 
            path: '/core/:core', 
            component: listCompoment,
            name:'core',
            props:function (route) {
              //   console.log(route,'-----')
              //   routes.query.rows = route.params.rows;
              //   routes.query.start = route.params.start;
                return {
                    core:route.params.core,
                    rows:route.params.rows,
                    start:route.params.start
                }
            }
          }
          // ,
      //   { 
      //       path: '/detail/:tableId/:itemId', 
      //       component:itemDetail,
      //       name:'detail',
      //       props:{
      //         isShowDetail:this.isShowDetail,
      //         tableData:this.tableData,
      //         backFn:this.closeDetail
      //       }
      //     }
      ]
    
      // 3. 建立 router 實例,而後傳 `routes` 配置
      // 你還能夠傳別的配置參數, 不過先這麼簡單着吧。
      var router = new VueRouter({
        routes: routes,
        mode: 'history',
        base:'/show_database/'
        //   routes // (縮寫)至關於 routes: routes
      })
    
      // 4. 建立和掛載根實例。
      // 記得要經過 router 配置參數注入路由,
      // 從而讓整個應用都有路由功能
      // var app = new Vue({
    
      // }).$mount('#app')
    
      // 如今,應用已經啓動了!

其實代碼還沒重構完。。

相關文章
相關標籤/搜索