项目七遇到的知识点

1、vue3.0写法

  • 此次项目使用vue3.0来写,写的过程当中忽然发现差异挺大的,感受不会写vue了,因此总结总结。。。html

  • This is an 官网地址:vue

    一、安装vue-cli 3.0

  • npm i @vue/cli -gnode

二、运行

  • npm run serve

三、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
      }
    }
  });

四、知识点

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

(1)、类型

  • provide: Object | () => Object
  • inject: Array | { [key: string]: string | Symbol | Object }
  • 这对选项须要一块儿使用,以容许一个祖先组件向其全部子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

(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方便类型声明git

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

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

2、相同页面点击不一样按钮出现内容

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

  • 效果图
    typescript

  • 子组件npm

    <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>
  • 父组件element-ui

    <!-- 新增/修改 -->
      <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,这样就能够在子组件里区分是新增页面仍是修改页面后端

3、Element 默认勾选表格 toggleRowSelection

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

  • 效果图

一、子组件内容

(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 });
    }
  }

二、父组件内容

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;
    }
  }

三、知识点

  • 官网

(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。

4、导出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

5、数组中多条对象去重

数组去重
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方法名',值)
相关文章
相关标签/搜索