項目七遇到的知識點

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方法名',值)
相關文章
相關標籤/搜索