目的
使用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
選擇自定義欺旧,然后通過空格
選中/取消選中
荚斯,Babel必須的,用于編譯JSX文件芝硬。其中router和vuex其實不需要,但是我這里也選中了轧房。
class-style是vue2喜歡用的一種編寫方式拌阴,但是vue3已經(jīng)不需要這種寫法,所以這里選擇n奶镶。
是否在ts的基礎(chǔ)上使用babel迟赃,這是需要的 , 選擇y厂镇。
這里用歷史路由纤壁,并用node-sass
為了更好的學(xué)習(xí),這里選擇Perttier捺信,個人其實更喜歡使用standard config酌媒。
這里選擇Jest使用。
單獨寫在各自的文件里面。
完成后秒咨,打開項目喇辽,終端運行
npm run serve
Prettier
代碼格式化工具,并在保存的時候會自動格式化雨席,保持風(fēng)格一致菩咨。
首先需要安裝插件
創(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)沒有變化,這是需要我們配置一下這個文件:
這里我們需要設(shè)置工作區(qū)罢低,所以在
工作區(qū)
打鉤Format On Save
。關(guān)閉這個設(shè)置頁面胖笛,會發(fā)現(xiàn)項目下多出來一個.vscode文件夾里面保存vscode針對這一個項目的各種配置网持。
然后去掉``,再打開
src/main.ts
,保存就會發(fā)現(xiàn)被規(guī)則修改:vscode還有一個推薦的setting配置:
當(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
值阱佛,如下代碼是正常的:
但如果像下面這樣寫帖汞,還是允許出現(xiàn)
undefined
值:<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>
這時候需要如下約束:
<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>
這是放在外面,因為在聲明的時候凑术,vue并不知道它要使用的用途翩蘸,如果放在里面就不會出現(xiàn)這個問題:
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')
這里圖片不顯示是因為如果是正常寫的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')
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>
)
}
},
})
運行:
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ù)。
包括傳字符串也會報錯:
所以用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>
)
}
},
})