【VUE+TS】1.0 Vue3.0+TS打造企業(yè)級組件庫

目的

使用vue單元測試庫保證代碼質(zhì)量
開源項目的開發(fā)發(fā)布流程
設(shè)計合理的設(shè)計廣泛適用的API
如何保證代碼質(zhì)量
vue3的實現(xiàn)原理

表單組件庫

高頻場景
交互復(fù)雜
定制型高
涉及到數(shù)據(jù)(校驗)安全

學(xué)習(xí)優(yōu)點

代碼質(zhì)量高
適應(yīng)場景豐富
開源維護(hù)參與
完善的發(fā)布流程
源碼(響應(yīng)式原理)

核心功能

表單生成
主體系統(tǒng)
插件系統(tǒng)

和其他表單組件庫的區(qū)別

無需編寫代碼:由json負(fù)責(zé)組裝代碼的要求。
開源全棧通用:對于校驗部分可以做到全棧
跨平臺
拖拽實現(xiàn)表單生成露乏。

內(nèi)容結(jié)構(gòu)

項目結(jié)構(gòu)
開發(fā)模式講解:JSX的開發(fā)模式
vue3的TS規(guī)范定義(vue3的源碼全部使用TS編寫的)
單元測試
高泛用性的API
響應(yīng)式原理(vue3的原理)
完善功能開發(fā)(組件開發(fā))
自動化發(fā)布流程

TypeScript

TS最重要的核心就是type(類型)政钟,和js最大的區(qū)別就是把java換成了type,也就是說有類型的js拖刃。

所以使用ts:

1.任何變量都聲明類型;
2.不到萬不得已不要使用any
3.給對象聲明接口

創(chuàng)建項目

win+R

cmd

cd 
F:\work_mysself\company_workspace\vue-json-schema-form_workspace

F:

vue create vue-json-schema-form

image.png

選擇自定義欺旧,然后通過空格選中/取消選中荚斯,Babel必須的,用于編譯JSX文件芝硬。
image.png

其中router和vuex其實不需要,但是我這里也選中了轧房。
image.png

class-style是vue2喜歡用的一種編寫方式拌阴,但是vue3已經(jīng)不需要這種寫法,所以這里選擇n奶镶。

image.png

是否在ts的基礎(chǔ)上使用babel迟赃,這是需要的 , 選擇y厂镇。
這里用歷史路由纤壁,并用node-sass


image.png

為了更好的學(xué)習(xí),這里選擇Perttier捺信,個人其實更喜歡使用standard config酌媒。


image.png

這里選擇Jest使用。
image.png

單獨寫在各自的文件里面。
image.png

image.png

完成后秒咨,打開項目喇辽,終端運行

npm run serve
image.png

image.png

Prettier

代碼格式化工具,并在保存的時候會自動格式化雨席,保持風(fēng)格一致菩咨。
首先需要安裝插件

image.png

創(chuàng)建配置文件.prettierrc,它支持json語法:

{
  "desc-semi": "代碼里面是否需要寫分號:不寫",
  "semi": false,
  "desc-singleQuote": "是否使用單引號:習(xí)慣單引",
  "singleQuote": true,
  "desc-arrowParens": "匿名函數(shù)單個參數(shù)時是否寫括號:習(xí)慣寫",
  "arrowParens": "always",
  "desc-trailingComma": " object屬性一行行寫下去之后,是否在最后加一個逗號",
  "trailingComma": "all"
}

還有很多規(guī)則陡厘,可以去官網(wǎng)學(xué)習(xí)并設(shè)置抽米。
設(shè)置好之后打開src\main.ts,嘗試保存雏亚,或者shift+alt+f格式化缨硝,發(fā)現(xiàn)沒有變化,這是需要我們配置一下這個文件:

image.png

image.png

這里我們需要設(shè)置工作區(qū)罢低,所以在工作區(qū)打鉤Format On Save。關(guān)閉這個設(shè)置頁面胖笛,會發(fā)現(xiàn)項目下多出來一個.vscode文件夾
image.png

里面保存vscode針對這一個項目的各種配置网持。
然后去掉``,再打開src/main.ts,保存就會發(fā)現(xiàn)被規(guī)則修改:
image.png

vscode還有一個推薦的setting配置:


image.png

當(dāng)切換文件、或者關(guān)閉保存长踊、或者vscode突然崩潰的時候功舀,自動保存代碼。

vue3中TS如何去定義組件——Component接口

vue3中提供了一個defineComponent函數(shù)身弊。
函數(shù)的實現(xiàn)直接返回了組件的定義辟汰。

如何定義Props的類型

打開src\views\Home.vue
發(fā)現(xiàn)初始化模板中已經(jīng)實現(xiàn)了defineComponent函數(shù)。

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src

export default defineComponent({
  name: "Home",
  components: {
    HelloWorld,
  },
});
</script>

避免props出現(xiàn) undefined值阱佛,如下代碼是正常的:

image.png

但如果像下面這樣寫帖汞,還是允許出現(xiàn) undefined值:
image.png

<script lang="ts">
import { defineComponent } from 'vue'

const PropsType = {
  msg: String,
  age: { type: Number, required: true },
}
export default defineComponent({
  name: 'HelloWorld',
  props: PropsType,
  mounted() {
    this.age
  },
})
</script>

這時候需要如下約束:


image.png
<script lang="ts">
import { defineComponent } from 'vue'

const PropsType = {
  msg: String,
  age: { type: Number, required: true } as const,
}
export default defineComponent({
  name: 'HelloWorld',
  props: PropsType,
  mounted() {
    this.age
  },
})
</script>
image.png

這是放在外面,因為在聲明的時候凑术,vue并不知道它要使用的用途翩蘸,如果放在里面就不會出現(xiàn)這個問題:


image.png

h函數(shù)

h函數(shù)就是用來創(chuàng)建節(jié)點的。
比如修改src/main.js

import { createApp, defineComponent, h } from 'vue'
// import App from './App.vue'
import router from './router'
import store from './store'
import HelloWorld from './components/HelloWorld.vue'

const App = defineComponent({
  render() {
    return h('div', { id: 'app' }, [
      h('img', { alt: 'Vue logo', src: './assets/logo.png' }),
      h(HelloWorld, {
        msg: '歡迎來到Vue+TS 的應(yīng)用現(xiàn)場',
        age: 12,
      })
    ])
  },
})

createApp(App).use(store).use(router).mount('#app')

image.png

這里圖片不顯示是因為如果是正常寫的html代碼會vue-loader會進(jìn)行自動尋址淮逊。
如果想正常顯示可以這么寫:

import { createApp, defineComponent, h } from 'vue'
// import App from './App.vue'
import router from './router'
import store from './store'
import HelloWorld from './components/HelloWorld.vue'

const img = require('./assets/logo.png') //eslint-disable-line

const App = defineComponent({
  render() {
    return h('div', { id: 'app' }, [
      h('img', { alt: 'Vue logo', src: img }),
      h(HelloWorld, {
        msg: '歡迎來到Vue+TS 的應(yīng)用現(xiàn)場',
        age: 12,
      }),
    ])
  },
})

createApp(App).use(store).use(router).mount('#app')

image.png

setup

setup自帶參數(shù)(props,{slots,attrs,emit})
attrs 和 slots 是有狀態(tài)的對象催首,它們總是會隨組件本身的更新而更新。這意味著你應(yīng)該避免對它們進(jìn)行解構(gòu)泄鹏,并始終以 attrs.x 或 slots.x 的方式引用郎任。

使用JSX開發(fā)vue3組件

JSX目前有2個解決方案,推薦vueComponent/jsx备籽。

聲明使用,需要修改babel.config.js

module.exports = {
  presets: ['@vue/cli-plugin-babel/preset'],
  plugins: ['@vue/babel-plugin-jsx'], //這樣配置jsx就可以用了
}

修改src/main.js:

import { createApp, defineComponent } from 'vue'
// import App from './App.vue'
import router from './router'
import store from './store'
import HelloWorld from './components/HelloWorld.vue'
import App from './App'

createApp(App).use(store).use(router).mount('#app')

新增src\App.tsx:

import { ref, reactive, defineComponent } from 'vue'
const img = require('./assets/logo.png') //eslint-disable-line
export default defineComponent({
  setup() {
    const state = reactive({ name: 'jokcy' })

    const numberRef = ref(1)

    setInterval(() => {
      state.name + -1
      numberRef.value += 1
    }, 1000)

    return () => {
      const number = numberRef.value
      return (
        <div id="app">
          <img src={img} alt="Vue Logo" />
          <p>{state.name + number}</p>
        </div>
      )
    }
  },
})

運行:

image.png

JSX還有一個好處就是在編譯階段就防止一些參數(shù)問題舶治。比如如下代碼:
修改src\components\HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h1>{{ age }}</h1>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'HelloWorld',
  props: {
    msg: String,
    age: { type: Number, required: true },
  },
})
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

修改src\App.tsx

import { ref, reactive, defineComponent } from 'vue'
import HelloWorld from '@/components/HelloWorld.vue'
const img = require('./assets/logo.png') //eslint-disable-line
export default defineComponent({
  setup() {
    const state = reactive({ name: 'jokcy' })

    const numberRef = ref(1)

    setInterval(() => {
      state.name + -1
      numberRef.value += 1
    }, 1000)

    return () => {
      const number = numberRef.value
      return (
        <div id="app">
          <img src={img} alt="Vue Logo" />
          <p>{state.name + number}</p>
          <HelloWorld age={24} />
        </div>
      )
    }
  },
})

如果age缺失,編譯就會提示缺少必備參數(shù)。
包括傳字符串也會報錯:


image.png

所以用TSX文件比vue文件要好的地方歼疮。

還可以復(fù)用很復(fù)雜的業(yè)務(wù)邏輯:

import { ref, reactive, defineComponent } from 'vue'
import HelloWorld from '@/components/HelloWorld.vue'
const img = require('./assets/logo.png') //eslint-disable-line

// function renderHelloWorld(num: number) {
//   return <HelloWorld age={num} />
// }
const renderHelloWorld = (num: number) => {
  return <HelloWorld age={num} />
}

export default defineComponent({
  setup() {
    const state = reactive({ name: 'jokcy' })

    const numberRef = ref(1)

    setInterval(() => {
      state.name + -1
      numberRef.value += 1
    }, 1000)

    return () => {
      const number = numberRef.value
      return (
        <div id="app">
          <img src={img} alt="Vue Logo" />
          <p>{state.name + number}</p>
          {renderHelloWorld(12)}
        </div>
      )
    }
  },
})

2種寫法都可以杂抽。
而且還可以在html代碼中使用v-model等:

import { ref, reactive, defineComponent } from 'vue'
import HelloWorld from '@/components/HelloWorld.vue'
const img = require('./assets/logo.png') //eslint-disable-line

// function renderHelloWorld(num: number) {
//   return <HelloWorld age={num} />
// }
const renderHelloWorld = (num: number) => {
  return <HelloWorld age={num} />
}

export default defineComponent({
  setup() {
    const state = reactive({ name: 'jokcy' })

    const numberRef = ref(1)

    setInterval(() => {
      state.name += 1
      numberRef.value += 1
    }, 1000)

    return () => {
      const number = numberRef.value
      return (
        <div id="app">
          <img src={img} alt="Vue Logo" />
          <p>{state.name + number}</p>
          <input type="text" v-model={state.name} />
          {renderHelloWorld(12)}
        </div>
      )
    }
  },
})

其實我們相當(dāng)于把每個例如div標(biāo)簽看成一個個h函數(shù)即可。
當(dāng)然可以通過input修改上面顯示的值:


export default defineComponent({
  setup() {
    const state = reactive({ name: 'jokcy' })

    const numberRef = ref(1)

    // setInterval(() => {
    //   state.name += 1
    //   numberRef.value += 1
    // }, 1000)

    return () => {
      const number = numberRef.value
      return (
        <div id="app">
          <img src={img} alt="Vue Logo" />
          <p>{state.name + number}</p>
          <input type="text" v-model={state.name} />
          {renderHelloWorld(12)}
        </div>
      )
    }
  },
})
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末韩脏,一起剝皮案震驚了整個濱河市缩麸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赡矢,老刑警劉巖杭朱,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吹散,居然都是意外死亡弧械,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門空民,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刃唐,“玉大人,你說我怎么就攤上這事界轩』ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵浊猾,是天一觀的道長抖甘。 經(jīng)常有香客問我,道長葫慎,這世上最難降的妖魔是什么衔彻? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮偷办,結(jié)果婚禮上艰额,老公的妹妹穿的比我還像新娘。我一直安慰自己爽篷,他們只是感情好悴晰,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逐工,像睡著了一般铡溪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泪喊,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天棕硫,我揣著相機(jī)與錄音,去河邊找鬼袒啼。 笑死哈扮,一個胖子當(dāng)著我的面吹牛纬纪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播滑肉,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼包各,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了靶庙?” 一聲冷哼從身側(cè)響起问畅,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎六荒,沒想到半個月后护姆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡掏击,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年卵皂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砚亭。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡灯变,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钠惩,到底是詐尸還是另有隱情柒凉,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布篓跛,位于F島的核電站,受9級特大地震影響坦刀,放射性物質(zhì)發(fā)生泄漏愧沟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一鲤遥、第九天 我趴在偏房一處隱蔽的房頂上張望沐寺。 院中可真熱鬧,春花似錦盖奈、人聲如沸混坞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽究孕。三九已至,卻和暖如春爹凹,著一層夾襖步出監(jiān)牢的瞬間厨诸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工禾酱, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留微酬,地道東北人绘趋。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像颗管,于是被迫代替她去往敵國和親聊倔。 傳聞我的和親對象是個殘疾皇子椿猎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 前言 2020年初,vue3 發(fā)布了第一個版本,在隨后的時間內(nèi)耻卡,vue-next 一直保持著快速的更新,直到去年的...
    jad_design閱讀 1,343評論 0 0
  • 關(guān)于vue3與jsx(tsx)寫法自己了解哦肋联,也可以看博主之前的博客故爵。 css帶有全局性,當(dāng)我們的項目復(fù)雜到一定程...
    超人鴨閱讀 21,762評論 16 17
  • 表情是什么梗逮,我認(rèn)為表情就是表現(xiàn)出來的情緒项秉。表情可以傳達(dá)很多信息。高興了當(dāng)然就笑了慷彤,難過就哭了娄蔼。兩者是相互影響密不可...
    Persistenc_6aea閱讀 124,209評論 2 7
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險厭惡者,不喜歡去冒險底哗,但是人生放棄了冒險岁诉,也就放棄了無數(shù)的可能。 ...
    yichen大刀閱讀 6,033評論 0 4