element-ui查询分页/mixins/组件封装与注册

1.关于页面在首次加载后不查询分页错误问题(排除首次分页带条件)

有句话说得好:解决问题的思维不能由产生问题的思路去解决!这是个很好的例子:在项目中某个查询页面,首次进入页面的时候将其中所有的数据全数渲染下来,也可以根据查询条件过滤数据,按照先限制 条件,再点击查询,然后分页的 顺序还说,一直没什么问题,但是在首次加载时,选中了其中一些条件,但是没有点击查询,分页的时候还是将查询的条件带过去了再进行的分页,这就很不对劲了!

<template>
 <div class="container">
   <el-form ref="searchInfo" :model="form">
     <el-form-item label="城市" prop="form.city">
       <el-select v-model="form.city">
         <el-option v-for="item in cities" :key="item.key" :label="item.value" :value="item.key">
         </el-option>          
       </el-select>
     </el-form-item>
     <el-form-item label="部门" prop="form.dept">
       <el-select v-model="form.dept">
         <el-option v-for="item in depts" :key="item.key" :label="item.value" :value="item.key">
         </el-option>          
       </el-select>
     </el-form-item>
     <el-form-iitem>
      <el-button @click="search"><i class="el-icon-search"></i>查询</el-button>
     </el-form-item>
   </el-form>
   
   <el-table :data="tableData">
     <el-table-column label="姓名" prop="name"/>
     <el-table-column label="报销单号"  prop="no"/>
     <el-table-column label="单据类型" prop="type"/>
     <el-table-column label="单据状态">
       <template slot-scope="scope">
         <span>{{scrop.row.status==1?:"业务审批":"财务审批"}}</span>
       </template>
     </el-table-column>
   </el-table>
   <pagination @pagination="handlePage" :page.sync="pagination.page" :page-limit="pagination.limit" :page-total="pagination.total" :page-sizes="pagination.pageSizes">
 </div>
</template>
<script>
import searchService from "@/api/emp"
 export default{
   data(){
     return{
       form:{
         dept:'',
         city:''
       },
       formData:{
         dept:'',
         city:''
       },
       cities:[
         {key:0,value:'东京'},
         {key:1,value:'北京'},
         {key:2,value:'上海'}
       ],
       depts:[
         {key:0,value:'运营部'},
         {key:1,value:'研发部'},
         {key:2,value:'财务部'}
       ],
       tableData:[],
       pagination:{
         page:1,
         total:0,
         limit:20,
         pageSizes:[20,50,100]
       }
     }
   },
   mounted(){
     this.enterSearch()
   },
   methods:{
     handlePage(val){
       this.pagination.ppage=val.page
       this.pagination.limit=val.limit
  this.enterSearch() }, enterSearch(){
//首次进入页面的时候,查询的是全部的信息 let json={ pageCurrent:this.pagination.page, pageSize:this.pagination.limit, catalog:this.formData } this.dealSearch(json) }, dealSearch(json){ //这里集中处理查询 searchService(json).then(res=>{ let data=res.data //查询到的数据 this.tableData=data.records this.pagination.page=data.pageCurrent //当前页 this.pagination.limit=data.pageSize //每页数据 this.pagination.total=data.rowCount //总条数 }) }, search(){ this.formData={...this.form}this.enterSearch() } } } </script>

在思考的时候,很容易从结果出发去思考怎么跳过首次不带参数的查询与分页,这就是造成思维困局的原因,这样的思路基本上就是死胡同了,是我一开始的 思路,后来在大神的指点下将一个不接收参数的拷贝查询条件的对象作为首次查询的条件,在点击到"查询"按钮的时候再去对这个空 的对象进行赋值,就可以将首次加载和带条件去查询的功能区分开了,这也是程序思维,经验是很有意义的,可以在解决不同问题的方法中综合整理出新问题的解决思路,有学到.

需要注意的是,在赋值给formData的时候,应该是对form的深拷贝,直接赋值的话还是将form的地址赋予了formData,这样就造成了在操作后,多次修改form查询条件,依然将其带入了formData当中,所以formData只能拿form当时的对应属性值,而不是form本身!!!!!

2.项目中公用数据调取

项目某些页面会用到项目的数据设置,当然这不是像vuex那样可以在组件内影响其变化的,也不是可以作为组件间传递参数的方式来使用的,而是,像一些被频繁用到的数据配置的数据和方法,第一次用是学习将element-ui中设置date-picker的时间区段限制:带快捷选项的时间日期,其中日期区段限制的代码很长且我们不会取改变它,这个时候可以将这段存在一个专门存放的文件里,复用的时候取取就行。

在 src建立一个文件夹mixins,文件mixin.js

const mixin={
 data(){
  return {
   //这里写跟组件中一样格式的数据格式
  }
 },
 methods:{
  //可以复用的函数
 }
}

export default mixin

 

在组件中使用时,需要引入文件import mixin from "@/mixins/mixin"

在组件export default后与data平行:mixins:[mixin]

注意,在export 和export default的时候,export default只能有一个,所以引入的mixin不是以对象方式引入的{mixin};

 

2.在同一个组件,只有传递进去的参数获取到的数据不同,其余代码都相同,做一个封装公用

在做一个查询页面的时候,两个页签显示的表格显示字段一模一样,只是由于传入的type不同,获取到渲染table的数据不同而已。

这样要写连个完全一样的组件加到el-tab-pane里面,实在不能忍,明明就几个字不一样而已!!然鹅,需要从父组件添加用以发送请求的一部分数据(各自区别的部分),在子组件补充发送请求的数据参数(相同部分),然后在子组件执行发送请求的方法getData抛出后被父组件调用。

在父组件出发子组件方法的相应位置使用:this.$refs.child.getData(查询参数),来触发子组件上的事件。但是在引入标签的时候引入一次(组件在父组件只有一个指代)的话,为其赋予不同的ref,亲测失败!

解决方法:同一个组件在父组件引入两次分别命名,成功!开心~~代码如下:

子组件——包含el-table的组件

data(){
 return {
   common:{type:'XXX'}
 }
},
methods:{
 getData(json){
   let query={...json,...this.common}
  //使用query发送请求
 }
}

  父组件中:

import child1 from "./child.vue"
import child2 from "./child.vue"
export default{
components:{
'component-a':child1,
'component-b':child2
}
}

  可以看出,同一个路径被以不同的名称引入的2次,由于名称不同,子组件的作用域亦不同。

父组件中

<component-a ref='coma'></component-a>

data中:
uniquedata:{value:'XXX',...}

methods中触发子组件行为:

handleDraft(){
 this.$refs.coma.getData(this.uniquedata)
}

  

3.在父子组件中有很多的数据交互,使用$emit来获取有点艰涩

以下需要高清楚指代的对象,以免出错

A.使用this.$children.属性/方法获取子组件上的属性或方法——$children为当前组件的直接子组件,是一个数组

B.使用this.$parent.属性/方法获取父组件上的属性或方法——$parent指向的是当前组件的根实例

C.$attrs,$listeners分别可以用来实现祖孙通讯,孙组件使用其分别可以获取祖组件的属性和方法

D.inject,privide 注入与共享,通常也可以用来祖孙通讯

4.组件批量注册

在项目中使用一些非常常用的组件(比如按钮之类的元素)时,把其成为基础组件,会在很多页面中都被频繁用到,这时候按照组件注册成全局组件会有一大堆引入注册的操作:

//写在存放components文件夹里用来管理统一注册组件的index.js文件
import buttonDanger from "./buttonDanger" impot buttonInfo from "./buttonInfo" export defaul{ components:{ buttonDanger, buttonInfo } }

 后来还是找到了基础组件自动化全局注册使用webpack里面的require.context来解决

//在main.js中全局导入基础组件:
import Vue from 'vue' import upperFirst from 'lodash/upperFirst' import camelCase from 'lodash/camelCase' const requireComponent = require.context( // 其组件目录的相对路径 './components', // 是否查询其子目录 false, // 匹配基础组件文件名的正则表达式 /Base[A-Z]\w+\.(vue|js)$/ ) requireComponent.keys().forEach(fileName => { // 获取组件配置 const componentConfig = requireComponent(fileName) // 获取组件的 PascalCase 命名 const componentName = upperFirst( camelCase( // 获取和目录深度无关的文件名 fileName .split('/') .pop() .replace(/\.\w+$/, '') ) ) // 全局注册组件 Vue.component( componentName, // 如果这个组件选项是通过 `export default` 导出的, // 那么就会优先使用 `.default`, // 否则回退到使用模块的根。 componentConfig.default || componentConfig ) })

 但是,后来经过实践发现组件注册并没有那么晦涩,而是仅仅将局部组件注册到全局而已。

5.组件封装复用

封装可复用的组件我看了这篇在vue中封装复用的组件

目录结果如下:

整理其中内容如下:

toast.js

import Vue from 'vue'; 
import Toast from './Toast.vue';     //引入组件
let ToastConstructor  = Vue.extend(Toast) // 返回一个“扩展实例构造器”

let myToast = ({text,duration})=>{
  if(!text){
    return
  }
    let toastDom = new ToastConstructor({
        el:document.createElement('div')    //将toast组件挂载到新创建的div上
  })
  //这里读取到的toastDom是在Toast.vue里的代码片段中整个的外部div元素,以及其上的data、事件、dom关系
  console.log('toastDom')
  console.log(toastDom)
    document.body.appendChild( toastDom.$el )   //把toast组件的dom添加到body里
    
    toastDom.text = text;
    toastDom.duration = !duration?2000:duration;
 
    // 在指定 duration 之后让 toast消失
    setTimeout(()=>{
        toastDom.isShow = false;  
    }, toastDom.duration);
}
export default myToast;

toast.vue:

<template>
    <div class="toast"  v-if="isShow" ref="toa">
        <div class="toast-div">{{ text }}</div>
    </div>
</template>
 
<script>
export default{
    data(){
        return {
            text:'',
            isShow:true
        }
    }
}
</script>
 
<style>
*{
    margin: 0;
    padding: 0;
}
.toast{
    display: flex;
    justify-content: center;
    align-items: center;
    height:40px;
    width:200px;
    padding:5px 15px;
    position: fixed;
    left: 50%;
    transform: translate(-50%, 0);
    margin-top: 5rem;
    background: red;
    line-height: 0.7rem;
    color: #FFFFFF;
    padding: 0 0.2rem;
    border-radius: 0.2rem;
}
</style>

main.js:

import toast from "@/components/toast/toast"
Vue.prototype.$toast=toast

在其他组件中使用:

<button @click="showToast">打开toast</button>
<script>

export default {
  name: 'HelloWorld',
  methods:{
    showToast(){
      this.$toast({text:"hello world"})
    }
  }
}
</script>

6.全局组件注册

全局组件注册是在管理整个组件库的components文件夹建立index.js,逐个引入组件然后在Vue注册:

import Vue from "vue"
import toast from "./toast/Toast.vue"
import demo from "./demo/Demo"
let components={toast,demo}

let install=(Vue,opts={})=>{
  Object.keys(components).forEach(key=>{
    Vue.component(key,components[key])
  })
}
export default install

再在main.js中:

import component from "@/components"
Vue.use(component)

 

前端小白,拾人牙慧,若有高见,欢迎留言~

posted @ 2020-05-08 22:21  轻染  阅读(733)  评论(0编辑  收藏  举报