基於SqlSugar的開發框架循序漸進介紹(11)-- 使用TypeScript和Vue3的Setup語法糖編寫頁面和組件的總結

来源:https://www.cnblogs.com/wuhuacong/archive/2022/07/08/16454236.html
-Advertisement-
Play Games

隨著Vue3和TypeScript的大浪潮不斷襲來,越來越多的Vue項目採用了TypeScript的語法來編寫代碼,而Vue3的JS中的Setup語法糖也越來越廣泛的使用,給我們這些以前用弱類型的JS語法編寫Vue代碼的人不少衝擊,不過隨著大量的學習和代碼編寫,經歷過一段難熬的時間後,逐步適應了這種... ...


隨著Vue3和TypeScript的大浪潮不斷襲來,越來越多的Vue項目採用了TypeScript的語法來編寫代碼,而Vue3的JS中的Setup語法糖也越來越廣泛的使用,給我們這些以前用弱類型的JS語法編寫Vue代碼的人不少衝擊,不過隨著大量的學習和代碼編寫,經歷過一段難熬的時間後,逐步適應了這種和之前差別不小的寫法和衝擊。本篇隨筆介紹總結了Vue3中一些常見的基於TypeScript的Setup語法與組合式 API的處理代碼案例。

TypeScript(簡稱ts)是微軟推出的靜態類型的語言,相比於js,TypeScript擁有強類型、編譯器嚴謹的語法檢查、更加嚴苛的語法,TypeScript 是 JS類型的超集,並支持了泛型、類型、命名空間、枚舉等特性,彌補了 JS 在大型應用開發中的不足。TypeScript 是 JavaScript 的強類型版本,最終在瀏覽器中運行的仍然是 JavaScript,所以 TypeScript 並不依賴於瀏覽器的支持,也並不會帶來相容性問題。

基於TypeScript的Setup語法糖寫法越來越多,熟練使用的話,需要一個學習過程,另外ElementPlus控制項也有了一些不同的變化,而且它的官方案例代碼基本上採用了Setup語法糖的寫法來提供例子代碼。

<script setup lang="ts">  是在單文件組件 (SFC) 中使用組合式 API 的編譯時語法糖。script-setup 弱化了vue模板式編程體驗,也使得代碼更簡潔。

1、定義組件或者頁面名稱

由於組合式API的特殊性,組件裡面的各項內容可以分開進行定義,同時藉助一些輔助函數進行處理。如這裡定義組件或者頁面名稱,通過使用defineOptions進行聲明。

<script setup lang="ts">
import { reactive,  ref,  onMounted,  watch,  computed } from "vue";

defineOptions({ name: "MyDictdata" }); //定義組件或頁面名稱

如果是組件,通過這樣定義後,我們在頁面引入它的時候,就可以import這個名稱就可以了,如下代碼所示。

// 自定義字典控制項
import MyDictdata from "./src/my-dictdata.vue";

這樣我們在頁面中就可以和其他HTML標簽一樣使用這個組件了。

<my-dictdata v-model="editForm.nationality" type-name="民族" />

2、data屬性定義

不管是Vue 頁面還是組件,我們都需要設置一些屬性信息,並提供一些初始化值,以前這些在選項式代碼中的時候,是在data塊中定義的,採用了<script setup lang="ts">語法後,任何在裡面定義的信息,在當前頁面或者組件的模板裡面都是公開,可以訪問的。

我們可以使用ref或者 reactive 來定義不同類型的,ref針對的是簡單類型,reactive 針對的是對象類型,它們底層的實現是一樣的,ref的參數增加了一個value的屬性。

let expandMore = ref(false); //是否展開更多條件
let list = ref([]); // 頁面列表數據
let listSelection = ref([]); // 選中記錄
let loading = ref(true); // 載入狀態
let sorting = ref(""); // 排序條件

// 分頁條件
let pageInfo = reactive({
  pageIndex: 1,
  pageSize: 20,
  totalCount: 0
});

這些信息可以在HTML頁面中直接引用使用即可。

<!--分頁部分 -->
<div class="block" style="height: 70px">
<el-pagination background :current-page="pageInfo.pageIndex" :page-size="pageInfo.pageSize"
  :total="pageInfo.totalCount" :page-sizes="[10, 20, 30, 40]" layout="total, sizes, prev, pager, next,jumper"
  @size-change="sizeChange" @current-change="currentChange" />
</div>

不過記得,如果是在JS裡面引用對象,那麼記得加上.value的屬性,才能設置或者訪問它。

 

3、表單或者組件的ref引用

有時候,需要通過在頁面的ref=“form” 來引用一些表單或者組件的名稱,那麼就需要初始化相關的類型的,如下代碼所示。

const searchRef = ref<FormInstance>(); //表單引用

而這個需要引入對應的類型的。

import { FormInstance, FormRules } from "element-plus";

這樣我們在HTML模板中就可以使用它的名稱了。

 

而對於自定義組件的話,如果需要嚴謹類型的處理,一般也需要約束對應的類型,我們如果需要反射某個特定組件的類型,那麼也可以使用InstanceType的關鍵字來處理,如下代碼所示。

<script lang="ts" setup>
import { ref } from 'vue'
import { ElTree } from 'element-plus'

const treeRef = ref<InstanceType<typeof ElTree>>()

這樣在調用相關介面方法的時候,就有Typescript的只能提示,代碼更加健壯了。

通過InstanceType這樣方式獲得的ref引用,會顯示組件很多公開的屬性和介面方法,如下圖所示。

 

 

我們也可以單獨定義一個類型,用來約束自定義組件的方法或者屬性,如下我們定義一個視圖類型組件,只有一個show方法。

我們在<script setup lang="ts">的頂部export一個介面定義,然後再在下麵使用 defineExpose 暴露組件屬性和方法,這樣就可以在組件的引用的地方調用這些方法了。

<script setup lang="ts">
//組件的介面類型
export interface ExposeViewType {
  show(id?: string | number): Function;
}

//顯示視窗
const show = (id: string | number) => {
  if (!isNullOrUnDef(id)) {
    testuser.Get(id).then(data => {
      Object.assign(viewForm, data);

      isVisible.value = true; //顯示對話框
    });
  }
};

//暴露組件屬性和方法
defineExpose({
  show
});

這樣我們在頁面中定義這個自定義組件的引用的時候,除了使用InstanceType之外,還可以使用自定義的類型聲明瞭。

    <!--查看詳細組件界面-->
    <view-data ref="viewRef" />

在<script setup lang="ts">裡面定義對應引用的類型。

const viewRef = ref<ExposeViewType | null>(); //查看表單引用

這樣我們就可以在代碼中查看它的對外公佈的方法信息了。

  

4、組件prop屬性定義

在我們開發自定義組件的時候,我們往往需要定義很多父傳子的屬性,也叫作prop屬性定義。

prop屬性定義,是通過defineProps函數進行處理的,這個defineProps()巨集函數支持從它的參數中推導類型,定義的代碼如下所示。

<script setup lang="ts">
const props = defineProps<{
    foo: string
    bar?: number
}>()
</script>

 我們也可以將 prop 的類型移入一個單獨的介面中:

<script setup lang="ts">
interface Props {
  foo: string
  bar?: number
}

const props = defineProps<Props>()
</script>

有時候,我們還需要給指定的prop屬性給定預設值,那麼也可以通過函數withDefaults一起進行處理即可。

如下麵是我們指定模塊定義的prop介面信息和defineProps的處理代碼。

<script setup lang="ts">
import {  reactive,  ref,  onMounted,  watch,  computed} from 
 vue";

//定義組件名稱
defineOptions({ name: "MyDictdata" });

//聲明Props的介面類型
interface Props {
  placeholder?: string; // 空白提示
  typeName?: string; // 字典類型方式,從後端字典介面獲取數據
  options?: Array<TreeNodeItem>; // 固定列表方式,直接綁定,項目包括id,label屬性
  modelvalue?: string | number; // 接受外部v-model傳入的值
  clearable?: boolean; // 是否可以清空
  disabled?: boolean; // 是否禁用
  multiple?: boolean; // 是否多選
}

//使用預設值定義Props
const props = withDefaults(defineProps<Props>(), {
  placeholder: "請選擇",
  typeName: "",
  options: () => {
    return [];
  },
  clearable: true,
  disabled: false,
  multiple: false,

  modelValue: "" //對應自定義控制項的v-model的值
});

這樣我們在使用的時候,就可以傳入給組件對應的prop名稱了。

  <el-form-item label="民族" prop="nationality">
    <my-dictdata v-model="editForm.nationality" type-name="民族" />
  </el-form-item>

 

5、Emits事件聲明

在組件裡面,我們拋出事件,通過在Emits中進行聲明,再行使用。

聲明事件在setup語法裡面也是和其他巨集函數一樣,如下代碼所示。

  // 聲明事件
  const emit = defineEmits(['updateName'])

如果為了更強的指定事件的參數和返回值等信息,我們也可以通過定義介面然後在聲明Emits的方式,如下代碼所示。

//聲明控制項事件
interface Emits {
  (e: "update:modelValue", value: string): void;
  (e: "change", value: string): void;
}
//定義控制項事件
const emit = defineEmits<Emits>();

或者直接整合一起聲明。

// 基於類型的聲明
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()

然後在組件的函數中觸發事件,通知父頁面即可。

function change(data) {
  const obj = dictItems.value.find(item => {
    return item.id + "" === data;
  });
  emit("change", obj);
}

這樣我們在頁面使用組件的時候,HTML模板中使用的組件代碼裡面,可以獲得獲得對應的事件處理。

  <el-form-item label="狀態" prop="state">
    <my-dictdata v-model="searchForm.state" :options="Status" @change="change" />
  </el-form-item>

 

6、Computed計算函數的使用

「computed」 是Vue中提供的一個計算屬性。它被混入到Vue實例中,所有的getter和setter的this上下文自動的綁定為Vue實例。

<script setup lang="ts">
  import { computed, ref } from 'vue'

  const count = ref(1)

  // 通過computed獲得doubleCount
  const doubleCount = computed(() => {
    return count.value * 2
  })
  // 獲取
  console.log(doubleCount.value)
</script>

 

7、Watch函數的使用

有時候,子組件需要監控自身某個值的變化,然後進行相關的處理,那麼對值進行監控就需要用到了watch函數。

// 監聽外部對props屬性變更,如通過ResetFields()方法重置值的時候
watch(
  () => props.modelValue,
  newValue => {
    console.log(newValue);
    emit("update:modelValue", newValue + "");
  }
);

watch(
  () => props.options,
  newValue => {
    newValue.forEach(item => {
      dictItems.value.push(item);
    });
  }
);

 

8、onMounted函數的使用

我們一般在 onMounted 的邏輯裡面準備好組件或者頁面顯示的內容,這裡面在頁面組件準備妥當後進行更新顯示。

//頁面初始化載入
onMounted(() => {
  getlist();
});

或者組件裡面

//掛載的時候初始化數據
onMounted(async () => {
  var typeName = props.typeName;
  var options = props.options;
  if (typeName && typeName !== "") {
    // 使用字典類型,從伺服器請求數據
    await dictdata.GetTreeItemByDictType(typeName).then(list => {
      if (list) {
        list.forEach(item => {
          dictItems.value.push({ id: item.id, label: item.label });
        });
      }
    });
  } else if (options && options.length > 0) {
    // 使用固定字典列表
    options.map(item => {
      dictItems.value.push({ id: item.id, label: item.label });
    });
  }

  // 設置預設值
  keyword.value = props.modelValue;
});

9、自定義組件的ModelValue

一般組件在綁定值的時候,一般使用v-Model的屬性來設置它的值。

  <el-form-item label="姓名" prop="name">
    <el-input v-model="editForm.name" />
  </el-form-item>

或者日期組件

  <el-form-item label="出生日期" prop="birthDate">
    <el-date-picker v-model="editForm.birthDate" align="right" type="date" placeholder="選擇日期"
      format="YYYY-MM-DD" />
  </el-form-item>

因此我們自定義開發的組件,也應該採用這樣約定的屬性。這裡面的v-Model對應的prop屬性就是modelValue的,因此我們需要定義這個屬性,並處理Emits事件就可以了。

//聲明Props的介面類型
interface Props {
  modelvalue?: string | number; // 接受外部v-model傳入的值
}
//使用預設值定義Props
const props = withDefaults(defineProps<Props>(), {
  modelValue: "" //對應自定義控制項的v-model的值
});

然後聲明組件的事件,在組件內部合適的地方觸發即可。

//聲明組件事件
interface Emits {
  (e: "update:modelValue", value: string): void;
  (e: "change", value: string): void;
}
//定義組件事件
const emit = defineEmits<Emits>();

併在Watch監控它的變化,觸發組件的自定義事件

watch(
  () => props.modelValue,
  newValue => {
    console.log(newValue);
    emit("update:modelValue", newValue + "");
  }
);

 

10、自定義引入Vue的API和組件

上面所有的setup語法糖代碼裡面,我們在開始的時候,往往都需要引入ref,reactive等API,如下代碼所示。

<script setup lang="ts">
import { reactive,  ref,  onMounted,  watch,  computed } from "vue";

那麼每次引入局的麻煩的話,可以通過使用https://github.com/antfu/unplugin-auto-import 這個插件來實現自動引入這些配置信息,這樣每次就可以省卻一些定義代碼了。

這樣在使用ref,reactive的時候,不用引入就直接使用,如下代碼所示。

const count = ref(0)
const doubled = computed(() => count.value * 2)

安裝組件,直接通過下麵npm 或者pnmp進行安裝即可。

npm i -D unplugin-auto-import

它提供了Vite、WebPack等編譯器的集成,可以參考官網進行修改。

如Vite的配置處理如下所示。

// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({ /* options */ }),
  ],
})

然後對Typescript和ESLint進行修改配置一下就可以一勞永逸了(具體參考官網的說明),希望下個版本的vue能自動不用引入這些API就好了。

以上就是我們在<script setup lang="ts">語法中經常涉及到的一些常用的知識和代碼案例了。

專註於代碼生成工具、.Net/.NetCore 框架架構及軟體開發,以及各種Vue.js的前端技術應用。著有Winform開發框架/混合式開發框架、微信開發框架、Bootstrap開發框架、ABP開發框架、SqlSugar開發框架等框架產品。
  轉載請註明出處:撰寫人:伍華聰  http://www.iqidi.com 
    

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 ElementUI官方沒有提供菜單動態生成的案例的,參考ng-design上的菜單動態生成,寫了一個基於ElementUi的菜單動態生成,支持多級菜單。 思路 基本思路就是迴圈子組件,判斷menu是否有children,有就說明至少有二級菜單,需要迴圈子組件,將menu.children作為參 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家可能經常會聽到 css 動畫比 js動畫性能更好這樣的論斷,或者是“硬體加速”,“層提升” 這樣的字眼;要瞭解這些內容就需要對瀏覽器的渲染流程有個大致的瞭解,本文就是我個人對這些內容的一個總結梳理 需要註意的是: 本文僅個人學習總結梳 ...
  • Sass編譯輸出的CSS格式可以自定義。 有4種輸出格式: - :nested – 嵌套格式 - :expanded – 展開格式 - :compact – 緊湊格式 - :compressed – 壓縮格式 ...
  • 回想當年剛接觸前端,Ajax 真的碰一次就跪一次。當時不懂後端,不知道 api 是什麼東東,也沒有後端小伙伴寫介面給我測試。 本文整理了我用過的幾個 免費的線上api介面,而且不需要處理跨域等問題。 希望能給剛入門的前端小白在學習 Ajax 時提供一點幫助。 本文列舉的線上介面包括:文本 和 圖片。 ...
  • 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 6 <meta name="viewp ...
  • @(公眾號測試號H5授權《前端》) Tips:因為申請公眾號需要 ¥300。 so 我用的是測試號。【白嫖永遠不虧】 需要註意的是 測試號是和個人微信號關聯起來的,不是公眾號主體關聯。。也就是每個人都可以申請,而不是必須有公眾號主題才可以。測試號和公眾號是獨立的。 一、前置準備-註冊配置測試賬號 1 ...
  • CSS進階內容 在學習了CSS基本知識之後,我們需要進一步瞭解CSS,因此寫下了這篇文章 當然如果沒有學習之前的知識,可以到我的主頁中查看之前的文章:秋落雨微涼 - 博客園 CSS三大特性 首先我們先來瞭解CSS的三大特點,以便於我們下麵知識點的講解 CSS三大特性包括: 層疊性 繼承性 優先順序 層 ...
  • 經查,發現我們開發的程式是用webpack打包發佈的,而該頁面在微信小程式打開時,對方註入了幾個微信相關的js腳本,而該腳本也是使用webpack打包生成的。雙方的js代碼導致window.webpackJsonp 被重覆定義。 當兩者的webpack版本不同時,生成的 window.webpack ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...