项目七遇到的知识点

一、vue3.0写法

  • 这次项目使用vue3.0来写,写的过程中突然发现差别挺大的,感觉不会写vue了,所以总结总结。。。

  • This is an 官网地址:

1、安装vue-cli 3.0

  • npm i @vue/cli -g

2、运行

  • npm run serve

3、TypeScript的支持

  • 遇到的vue3.0写法

        import { Watch, Component, Vue, Emit, Prop } from "vue-class-decorator";
        // 没有组件
        @component
    
        // 有组件
        // import children from "./components/children.vue";
        // @component({ components:{children} })
    
        export default class MyChildren extends Vue{
          username = ""; // 名字
          //userId 父子之间传值,必传默认是null
          @Prop({ type: String, required: true, default: null})
          userId: string;
          @Emit("changeChildren")
          changeChildren(){}
      
        created(){}
        mounted(){}
          // 方法
          cancel() {
      	  // 调用自定义函数
      	  this.changeChildren()
          }
      }
    
  • 以下是我百度看到的,写的非常详细

  • 在3.0版本中,选择启动typescript语法后,vue组件的书写格式有特定的规范。

  • 示例代码

百度查看的结果
 
     import { Component, Emit, Inject, Model, Prop, Provide, Vue, Watch } from "vue-property-decorator"
	const s = Symbol('baz')
	@Component
	export class MyComponent extends Vue {
	  @Emit()
	  addToCount(n: number){ this.count += n}
	  @Emit('reset')
	  resetCount(){ this.count = 0 }
	  @Inject() foo: string
	  @Inject('bar') bar: string
	  @Inject(s) baz: string
	  @Model('change') checked: boolean
	  @Prop()
	  propA: number
	  @Prop({ default: 'default value'})
	  propB: string
	  @Prop([String, Boolean])
	  propC: string | boolean
	  @Provide() foo = 'foo'
	  @Provide('bar') baz = 'bar'
	  @Watch('child')
	  onChildChanged(val: string, oldVal: string) { }
	  @Watch('person', { immediate: true, deep: true})
	  onPersonChanged(val: Person, oldVal: Person){}
	}
  
以上代码相当于
 
  const s = Symbol("baz");
  export const myComponent = Vue.extend({
    name: "MyComponent",
    inject: {
      foo: "foo",
      bar: "bar",
      [s]: s
    },
    model: {
      prop: "checked",
      event: "change"
    },
    props: {
      checked: Boolean,
      propA: Number,
      propB: {
        type: String,
        default: "default value"
      },
      propC: [String, Boolean]
    },
    data() {
      return {
        foo: "foo",
        baz: "bar"
      };
    },
    provide() {
      return {
        foo: this.foo,
        bar: this.baz
      };
    },
    methods: {
      addToCount(n) {
        this.count += n;
        this.$emit("add-to-count", n);
      },
      resetCount() {
        this.count = 0;
        this.$emit("reset");
      },
      onChildChanged(val, oldVal) {},
      onPersonChanged(val, oldVal) {}
    },
    watch: {
      child: {
        handler: "onChildChanged",
        immediate: false,
        deep: false
      },
      person: {
        handler: "onPersonChanged",
        immediate: true,
        deep: true
      }
    }
  });
  

4、知识点

  • 选项/组合 provide/inject
  • @Provide 提供 / @inject注入

(1)、类型

  • provide: Object | () => Object
  • inject: Array |
  • 这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

(2)、示例


// 父级组件提供'foo'
var Provider = {
	provide: {
		foo: 'bar'
	}
}
// 子件注入'foo'
var Child = {
	inject: ['foo'],
	created() {
		console.log(this.f00) // bar
	}
}

(3)、vue-property-decorator

  • npm install --save vue-property-decorator /npm i -S vue-property-decorator

vue-property-decorator提供OO的风格Vue Component方便类型声明

vue-class-component 以class的模式写vue组件


vue class component 是vue官方出的
vue property decorator 是社区出的
其中vue class component 提供了vue component等等
vue property decorator深度依赖了vue class component扩展出了很多操作符@Prop @Emit @Inject等等 可以说是vue class component的一个超集
正常开发的时候 你只需要使用vue property decorator 中提供的操作符即可 不再从vue class component引入vue

二、相同页面点击不同按钮出现内容

新增和修改都是用同一个页面,希望点击各自的按钮跳转到页面时调用各自的接口

  • 效果图

  • 子组件

      <template>
      	<!-- 新增/修改 -->
      	  <div class="role-change table-mask">
      	    <div class="role-body">
      	      <div class="role-main">
      	        <span
      	          class="svg-container table-close"
      	          @click="cancel"
      	        >
      	          <svg-icon icon-class="close" />
      	        </span>
      	        <div class="main-box">
      	          <div class="main-item">
      	            <p><span class="m-start">*</span>角色编码:</p>
      	            <el-input v-model.trim="Code" />
      	          </div>
      	          <div class="main-item">
      	            <p><span class="m-start">*</span>角色名称:</p>
      	            <el-input v-model.trim="Name" />
      	          </div>
      	        </div>
      	        <div class="box-btn-bg add-bg tac">
      	          <el-button
      	            class="f18 box-btn"
      	            @click="cancel"
      	          >取消</el-button>
      	          <el-button
      	            class="f18 box-btn"
      	            @click="addSubmit"
      	          >保存</el-button>
      	        </div>
      	      </div>
      	    </div>
      	  </div>
      	</template>
      	<script lang="ts">
      	  import { Watch, Component, Vue, Emit, Prop } from "vue-class-decorator";
      	  import { addRole, getRoleDetails, getUpdateRole } from "@/api/System/role";
      	
      	  @Component
      	  export default class AddRole extends Vue {
      	    Code = ""; // 角色编码
      	    Name = ""; // 角色名称
      	    @Emit("addRole")
      	    addRole(flag) {}
      	    @Prop({ type: String, default: null })
      	    addId: string;
      	    cancel() {
      	      this.addRole(false);
      	    }
      	    addSubmit() {
      	      if (this.Code === "") {
      	        this.$message({
      	          message: "请输入角色编码",
      	          type: "warning"
      	        });
      	      } else if (this.Name === "") {
      	        this.$message({
      	          message: "请输入角色名称",
      	          type: "warning"
      	        });
      	      } else {
      	        if (this.addId) {
      	          // 修改接口
      				// 调用自定义方法
            			this.addRole(true);
      	        } else {
      	          // 新增接口
            		 this.addRole(true);
      	        }
      	      }
      	    }
      	  }
      	</script>
    
  • 父组件

      <!-- 新增/修改 -->
    	<add-role
      v-if="roleShow"
      :addId="addId"
      @addRole="addRole"
    	></add-role>
    	<script lang="ts">
      	import AddRole from "./components/AddRole.vue";
      	@Component({
      	    components: {
      	      AddRole
      	    }
      	 })
      	 export default class RoleList extends Vue {
      		roleShow = false; // 默认弹框不显示
      		addId = null; // 传给子组件的id
      		// 新增/修改的自定义方法
      		addRole(flag) {
      		  if (flag) {
      		  }
      		  this.addId = null;
      		  this.roleShow = false;
      		}
      		// 点击新增按钮
      		add(){
      			this.roleShow = true;
      		}
      		//点击修改按钮
      		edit(){
      			this.addId = 'newId';
      			this.roleShow = true;
      		}
      	 }
      </script>
    
  • 思路

  • 父子之间传值,点击修改的时候传newId,新增的时候不传默认是null,这样就可以在子组件里区分是新增页面还是修改页面

三、Element 默认勾选表格 toggleRowSelection

element type="selection" 我希望当我点击勾选框后第二次点击是选中的状态;
我只是为了实现内容,实际用到的要走接口

  • 效果图

1、子组件内容

(1)、html

<template>
  <div class="table-mask">
    <div class="table-main">
      <el-table
        ref="multipleTable"
        :data="tableData"
        style="width: 100%"
        border
        row-key="id"
        @selection-change="handleSelectionChange"
        @row-click="clickRow"
      >
        <el-table-column
          type="selection"
          width="50"
          :reserve-selection="true"
          align="center"
        >
        </el-table-column>
        <el-table-column
          label="日期"
          width="100"
          align="center"
        >
          <template slot-scope="scope">{{ scope.row.date }}</template>
        </el-table-column>
        <el-table-column
          prop="name"
          label="姓名"
          width="90"
          align="center"
        >
        </el-table-column>
        <el-table-column
          prop="address"
          align="center"
          label="地址"
        >
        </el-table-column>
      </el-table>
      <div>
        <el-button
          type="info"
          @click.stop="cancel"
        >取消</el-button>
        <el-button
          type="primary"
          @click.stop="submit"
        >保存</el-button>
      </div>
    </div>
  </div>
</template>

(2)、样式内容

less

.table-mask {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0px;
    right: 0px;
    z-index: 9;
    overflow-x: hidden;
    overflow-y: scroll;
    background: rgba(0, 0, 0, 0.5);
    .table-main {
      position: absolute;
      left: 50%;
      top: 50%;
      margin-top: -200px;
      margin-left: -280px;
      width: 560px;
      padding: 20px;
      box-sizing: border-box;
      background: #fff;
    }
  }
	

(3)、js逻辑

ts实现

  import { Watch, Component, Vue, Emit, Prop } from "vue-class-decorator";
  @Component
  export default class ChangeTable extends Vue {
    $refs: {
      multipleTable: any;
    };
    tableData = [
      {
        id: 1,
        date: "2016-05-03",
        name: "王小虎",
        address: "上海市普陀区金沙江路 1518 弄"
      },
      {
        id: 2,
        date: "2016-05-02",
        name: "王小虎",
        address: "上海市普陀区金沙江路 1518 弄"
      },
      {
        id: 3,
        date: "2016-05-04",
        name: "王小虎",
        address: "上海市普陀区金沙江路 1518 弄"
      },
      {
        id: 4,
        date: "2016-05-01",
        name: "王小虎",
        address: "上海市普陀区金沙江路 1518 弄"
      },
      {
        id: 5,
        date: "2016-05-08",
        name: "王小虎",
        address: "上海市普陀区金沙江路 1518 弄"
      },
      {
        id: 6,
        date: "2016-05-06",
        name: "王小虎",
        address: "上海市普陀区金沙江路 1518 弄"
      },
      {
        id: 7,
        date: "2016-05-07",
        name: "王小虎",
        address: "上海市普陀区金沙江路 1518 弄"
      }
    ];
    multipleSelection = [];
    @Emit("ChangeClick")
    ChangeClick(flag) {}
    @Prop({ type: Array, required: true })
    hasArray: any[];
    created() {
      this.InitData();
    }
    // 初始化
    InitData() {
      if (this.hasArray) {
        const indexList = []; // 存储交集的index,用来勾选状态
        this.hasArray.forEach(table => {
          this.tableData.forEach((item, index) => {
            if (table.id === item.id) {
              indexList.push(index);
            }
          });
        });
        this.$nextTick(() => {
          indexList.forEach(e => {
            this.$refs.multipleTable.toggleRowSelection(this.tableData[e], true);
          });
        });
      }
    }
    // 获取选中的值
    handleSelectionChange(val) {
      this.multipleSelection = val;
    }
    // 单击某一行数据时选中对应的复选框
    clickRow(row) {
      this.$refs.multipleTable.toggleRowSelection(row);
    }
    cancel() {
      this.ChangeClick(false);
    }
    submit() {
      this.ChangeClick({ flag: true, checked: this.multipleSelection });
    }
  }
	

2、父组件内容

html

<el-button
@click="handleTable"
type="primary"
>点击弹出表格</el-button>
<my-table
  v-if="isTableShow"
  :hasArray="hasArray"
  @ChangeClick="ChangeClick"
></my-table>

js

 import myTable from "./components/table.vue";

  @Component({
    components: {
      myTable
    }
  })
  export default class ChangePassword extends Vue {
 	isTableShow = false;
    hasArray = [];
    handleTable() {
      this.isTableShow = true;
    }
    ChangeClick(flag) {
      if (flag) {
        this.hasArray = flag.checked;
      }
      this.isTableShow = false;
    }
  }

3、知识点

  • 官网

(1)、toggleRowSelection

  • toggleRowSelection(row,selected)接收两个参数,row传递被勾选行的数据,selected设置是否选中
  • 调用toggleRowSelection这个方法需要获取真实dom所以需要注册ref来引用它。

(2)、row-click 点击行事件


// 单击某一行数据时选中对应的复选框
clickRow(row) {
  this.$refs.multipleTable.toggleRowSelection(row);
}

(3)、element ui tree 获取到选中节点

<el-tree
ref="tree"
:data="dataList"
:props="defaultProps"
node-key="Code"
:default-checked-keys="defaultId"
show-checkbox
@check-change="getChecked"
>
</el-tree>
<!-- default-checked-keys	默认勾选的节点的 key 的数组 -->
  • 方法

      getChecked(){
      	this.$refs.tree.getCheckedNodes();
      }
    

其他

  • reserve-selection

  • 仅对 type=selection 的列有效,类型为 Boolean,为 true 则会在数据更新之后保留之前选中的数据(需指定 row-key)(默认false)

  • row-key

  • 行数据的 Key,用来优化 Table 的渲染;在使用 reserve-selection 功能与显示树形数据时,该属性是必填的。类型为 String 时,支持多层访问:user.info.id,但不支持 user.info[0].id,此种情况请使用 Function。

四、导出excel(下载excel)

  • 也要根据后端写的接口来,不一定适用所有的下载excel

  // 提取导出文件的文件扩展名(类型)
  const [, extName] = /filename=".*(\..*)";/.exec(
    res.headers["content-disposition"]
  );
  // 构造下载文件名的名字
  const fileName = new Date().getTime().toString() + (extName || "");


  // #region 进行下载
  const link = document.createElement("a");
  link.href = window.URL.createObjectURL(res.data);
  link.download = fileName;
  // 此写法兼容可火狐浏览器
  document.body.appendChild(link);
  const evt = document.createEvent("MouseEvents");
  evt.initEvent("click", false, false);
  link.dispatchEvent(evt);
  document.body.removeChild(link);
  // #endregion

五、数组中多条对象去重

数组去重
 
 const list1 = [
    {
      id: 1,
      name: "张三"
    },
    {
      id: 2,
      name: "李四"
    }
  ];
  const list2 = [
    {
      id: 1,
      name: "张三"
    },
    {
      id: 3,
      name: "王麻子"
    }
  ];
  const oldArray = [...list1, ...list2];
  console.log(oldArray);
  const newArray = [];
  for (let i = 0; i < oldArray.length; i++) {
    let flag = true;
    for (let j = 0; j < newArray.length; j++) {
      if (oldArray[i].id === newArray[j].id) {
        flag = false;
      }
    }
    if (flag) {
      newArray.push(oldArray[i]);
    }
  }
  console.log(newArray);
  
  • 打印效果

vue store存储commit和dispatch

  • this.$store.commit("toShowLoginDialog",true)
  • this.$store.dispatch('toShowLoginDialog',false)
  • 主要区别是
  • dispatch:含有异步操作,例如向后台提交数据,写法:this.$store.dispatch('mutations方法名',值)
  • commit:同步操作,写法:this.$store.commit('mutataions方法名',值)
posted @ 2019-05-16 11:36  不完美的完美  阅读(449)  评论(0编辑  收藏  举报