「[email protected]正式發(fā)布與做open source的一些感受」從90%到100%...
前言
在介紹Strve.js新版本之前呢!我們先來看下尤雨溪同學(xué)近期的兩段分享。
- 當(dāng)時(shí)你還有day job時(shí)候,怎么保持做open source的, how you balance between them?
可能我比較幸運(yùn)點(diǎn)吧!因?yàn)樵诿绹@邊大家對(duì)工作平衡比較注意,像谷歌的話就比較舒服的了。雖然我們剛進(jìn)去也年輕,偶爾也加加班,但是整體而言,在谷歌的話,你任務(wù)完成了想什么時(shí)候走都可以。所以在國內(nèi)確實(shí)會(huì)難一些,業(yè)務(wù)壓力會(huì)大的話。所以如果你真的覺得業(yè)務(wù)壓力就更大,工作就很忙。那我建議就可能不要逼自己,如果真覺得太累,就不要逼自己。 這個(gè)開源本身也其實(shí)就是說,這個(gè)大家做開源其實(shí)都有一個(gè)階段,就是你剛開始有一個(gè)想法想把它做出來,剛開始是一種快樂的一種狀態(tài),就是把一個(gè)想法從零到一那種快感,就是做技術(shù)人員都有這種創(chuàng)造一種東西的想法。但是開源在另一個(gè)過程完成之后立刻進(jìn)入一種,就是從90%到100%這個(gè)過程其實(shí)是很困難的,你就會(huì)發(fā)現(xiàn)把一個(gè)玩具做成真的能用的東西就需要投入很多,當(dāng)你把它做得真的能用,真的有人用的時(shí)候,這些人就會(huì)繼續(xù)給你提不停的要求。這就說,哎呀!我得去回應(yīng)這些人的期待,這又是一種心理壓力。 其實(shí)說就是很多時(shí)候,大家都是剛開始做開源的時(shí)候,這種創(chuàng)造一種東西的快感所吸引。沒有意識(shí)到你以后會(huì)有很多的commit。我對(duì)很多想要做開源的朋友的建議是,想清楚你做開源想要做什么,如果你就只是想寫一個(gè)庫覺得很爽,但是我后期不想去做讓它耗費(fèi)我很多精力去維護(hù)它,也沒有問題,其實(shí)就跟大家明確這個(gè)想法。但是如果說你想做一個(gè)項(xiàng)目想做大做好,想跟React競(jìng)爭(zhēng)的項(xiàng)目,那這個(gè)東西需要極大的投入的。如果你工作本質(zhì)就很煩忙,那么大概率你就沒有可能做這個(gè)。所以確實(shí)說,想好你的想要什么吧!如果你沒有真的條件,如果真的很拼很拼,我就是996,我也要做開源,那你要做好心理準(zhǔn)備。我有一段時(shí)間把自己搞成996這種狀態(tài),就是上完班回來搞Vue,其實(shí)這樣精神壓力是挺大的。我現(xiàn)在可能站著說話不腰疼,我現(xiàn)在還是覺得平衡一點(diǎn)的好。
2 . 在設(shè)計(jì)vue這樣的框架時(shí),你會(huì)考慮哪些東西?
其實(shí)考慮的問題就是說,首先,這個(gè)比較大了,當(dāng)然這個(gè)考慮問題也不是一開始就完全想好,Vue也是從一個(gè)小項(xiàng)目慢慢發(fā)展起來的。那我們就是說你對(duì)自己的框架有一個(gè)定位,Vue的定位就是說我們保證要對(duì)新手友好,容易上手。這個(gè)就是一個(gè)定位,有些框架就說了,我就不是設(shè)計(jì)給新手用的,我就不考慮這個(gè)問題。這也是合理的,這不是好或不好,這就是一個(gè)設(shè)計(jì)上的決定,我就是要對(duì)新手友好的框架,或者說我在其他情況付出一些代價(jià),比如說我的一個(gè)API設(shè)計(jì)的難以理解。但是就是有的時(shí)候你過度追求新手友好,你可能會(huì)被限制在高端或者追求性能的一些場(chǎng)景,那你就在這里面做權(quán)衡。那反過來有些框架我不考慮新手用戶,我就考慮理論上的優(yōu)美,就比如說小眾的函數(shù)式框架,它可能說是針對(duì)某些論文寫出的非常優(yōu)雅,非常完美的模式。但是,如果是一個(gè)新手,你可能看不懂我在干什么。其實(shí)這就是取舍,對(duì)吧。所以,最先要明確你的框架的定位。在這前提下,你還要考慮就是說其實(shí)你到后面你會(huì)發(fā)現(xiàn)一到具體工程問題。到處都是取舍。 就比如說你一個(gè)API,你可以選擇這樣設(shè)計(jì)變的更簡(jiǎn)潔優(yōu)美,但是這會(huì)導(dǎo)致某個(gè)地方很難優(yōu)化。那么反過來我為了追求極致性能,我可能API設(shè)計(jì)的稍微那么難受一點(diǎn)。還有就是社區(qū)的需求,你自己做出的決定未必是社區(qū)想要的。就需要去跟社區(qū)溝通吧,還要公開討論過程。Vue做一些大的改動(dòng)的話,更多的就是拋一個(gè)想法出來,社區(qū)進(jìn)行討論。變成了一個(gè)多少共同設(shè)計(jì)的過程,不再像初期,初期的話,你更多就是不需要考慮那么多用戶,你一拍腦袋,你就把它做出來。所以說,初期階段跟后期跟你設(shè)計(jì)的流程完全就不一樣了。
大家可以看到對(duì)于開源框架,尤大也給出了很不錯(cuò)的建議。其實(shí)之前我打算寫Strve.js,就是想看自己也能不能開發(fā)出起碼不是很差的庫或者框架。結(jié)果也不錯(cuò),總算搞出來了。下面是之前自己獨(dú)立開發(fā)Strve.js的一些感想。
從2021年9月份的時(shí)候,就想自己開發(fā)一個(gè)庫,從而提高一下自己的能力。慶幸的是在年前就開發(fā)出來了,并且生態(tài)也初步建成。這里提到的生態(tài)包括:Create Strve App、Strve Router以及其他輔助Strve.js開發(fā)的工具。
說實(shí)話,這段時(shí)間是挺難熬的,這也算是今年給自己一個(gè)禮物吧!
我開發(fā)Strve.js的初衷是之前接觸過JSX語法,一直覺的JSX語法非常酷,可以在JS中寫HTML標(biāo)簽,于是就想開發(fā)一款類似JSX語法的庫。剛開始也開發(fā)了一段時(shí)間,搭配Babel可以簡(jiǎn)單實(shí)現(xiàn)JSX語法。但是到后來覺得并不是那么完美,還要解決一些類似修改數(shù)據(jù)更新視圖的一些問題。熬了幾天夜,也沒有完美的解決。最后,還是放棄了這種方案。
我當(dāng)時(shí)在想,如果我僅僅想在JS中寫HTML標(biāo)簽,那么使用JS中的模板字符串就已經(jīng)具備在字符串內(nèi)寫HTML標(biāo)簽的能力了,為什么不換一下思路,研究一下在模板字符串中寫HTML標(biāo)簽這種更加方便直接的方案呢?剛開始我就是從基礎(chǔ)著手,寫一串字符串,然后怎么想辦法將字符串掛載到頁面中。借鑒了React、Vue這些框架的思想,在頁面指定一個(gè)掛載元素。這就簡(jiǎn)單實(shí)現(xiàn)了在模板字符串內(nèi)開發(fā)HTML,但是隨之而來的是不能做到數(shù)據(jù)變頁面變,從更加專業(yè)的角度上講就是數(shù)據(jù)驅(qū)動(dòng)頁面。并且更新頁面后盡可能的少修改DOM元素,減少重排帶來的性能上的影響。這從最初的簡(jiǎn)單的在JS寫HTML又上升到一個(gè)層面上,怎么實(shí)現(xiàn)一個(gè)MVVM框架。
市面上知名的MVVM框架有Vue、React、Angular,既然自己想設(shè)計(jì)一個(gè)MVVM框架,那么可以借鑒一下它們的思想。首先,非常喜歡Vue的漸進(jìn)式設(shè)計(jì)思想,只要你是一個(gè)前端小白就可以立馬上手,這是非常值得借鑒的。另外又借鑒了React框架中的“All in JS”以及異步更新數(shù)據(jù)的思想。最后,它們兩個(gè)框架都使用了虛擬DOM來提升性能,那么我們也可以引入虛擬DOM機(jī)制。
之前,聽過尤老師的幾期中文分享,談到框架的話題說,框架的設(shè)計(jì)就是不斷的取舍。這其中肯定還會(huì)復(fù)雜很多,我上面也就是簡(jiǎn)單的概括了一下。能不能實(shí)現(xiàn)我所預(yù)期的那樣,當(dāng)時(shí)我也不知道,當(dāng)時(shí)就想把東西做出來。前面一個(gè)多月是非常痛苦的,幾乎是閉門造車。主要的難點(diǎn)是怎么將模板字符串轉(zhuǎn)化成虛擬DOM結(jié)構(gòu),并且代碼量控制在最小。然后將轉(zhuǎn)化的虛擬DOM進(jìn)行Diff算法,更有效的更新DOM。
最終,功夫不負(fù)有心人,我終于如愿以償?shù)耐瓿闪薙trve.js的開發(fā)。這個(gè)小型庫,也算不上是框架吧!設(shè)計(jì)的初衷上面也說了就是自己想練練手,看自己也能不能開發(fā)出起碼不是很差的庫或者框架。
在2021年12月的時(shí)候,我發(fā)布了第一個(gè)版本1.2.2,這個(gè)版本相對(duì)比較簡(jiǎn)陋。但是,周圍生態(tài)也已經(jīng)初步建成。發(fā)布之后,我自己試用了一下,自己試著敲了幾個(gè)小項(xiàng)目。比如大家都會(huì)做得TodoList。怎么說呢!對(duì)于我自己來說,只能說還可以。很容易上手,大多都是利用原生JavaScript的能力,所以只要熟悉JavaScript的朋友都可以上手,并且利用聲明式API對(duì)一些DOM進(jìn)行操作,沒有了JQuery那種命令式API對(duì)DOM拿來就是干。并且符合了MVVM框架的思想,更容易開發(fā)項(xiàng)目。
我很認(rèn)同尤大說的一句話,就是從90%到100%這個(gè)過程其實(shí)是很困難的,你就會(huì)發(fā)現(xiàn)把一個(gè)玩具做成真的能用的東西就需要投入很多。我在想既然我已經(jīng)決定了開發(fā)一個(gè)庫,雖然比不上Vue、React這些大框架,但是為什么不想簡(jiǎn)單一點(diǎn),就單純地自己開發(fā)維護(hù)一個(gè)項(xiàng)目呢!所以,我必須繼續(xù)優(yōu)化維護(hù)下去。在2022年1月份,我決定要優(yōu)化一些代碼,使Strve.js變得更好。框架設(shè)計(jì)正如尤大所說的到后面你會(huì)發(fā)現(xiàn)一到具體工程問題。到處都是取舍。在這段時(shí)間我覺得比剛開發(fā)Strve.js的時(shí)候更難受,因?yàn)槟阆氚岩粋€(gè)做出來的東西再做到更完美實(shí)在是難。終于體會(huì)到了尤大說的那些話,我覺得這也是成長,起碼我在用Vue的時(shí)候,不會(huì)只會(huì)簡(jiǎn)單用它的API。經(jīng)過1個(gè)月的調(diào)研與各種測(cè)試,終于可以發(fā)布第二個(gè)版本2.1.0,之前還有一個(gè)版本2.0.0。我覺得這就是突破,我也完成了。
所以,最后,我想告訴有一些做開源的朋友們,其實(shí)不要想的那么復(fù)雜,做好每一步就可以了。
[email protected]發(fā)布
源代碼地址:
https://github.com/maomincoding/strve/
2.0.0 (2022-01-23)
向鏈表頭部插入數(shù)據(jù)需要綁定useFkey字段,避免DOM節(jié)點(diǎn)重復(fù)渲染;
渲染后隱藏“DOM”節(jié)點(diǎn)事件方法;
綁定Style樣式(對(duì)象);
綁定屬性統(tǒng)一使用${}符號(hào)綁定;
支持 HTML 模板字符串高亮(VSCode 編輯器需要安裝 comment-tagged-templates 插件);
支持父子組件互相傳值;
適配Bootstrap5、Tailwindcss UI框架;
2.1.0 (2022-01-25)
- 修復(fù)DOM屬性property無法賦值的問題;
- 完善字符串轉(zhuǎn)換為虛擬DOM邏輯問題;
新文檔更新
中文文檔地址:
https://maomincoding.github.io/strvejs-doc/zh/
更新內(nèi)容
- 整體UI優(yōu)化;
- 側(cè)邊欄默認(rèn)收起;
- 代碼主題優(yōu)化;
- 搜索功能優(yōu)化;
- 加入主題切換(白天/黑夜);
- 加入支持UI框架菜單項(xiàng);
- 加入更新日志菜單項(xiàng);
- 更新API的使用細(xì)節(jié)說明;
效果圖預(yù)覽

圖1

圖2

圖3
實(shí)戰(zhàn)第一個(gè)Strve項(xiàng)目
我們下面要做的項(xiàng)目是TodoList,相信大家都做過,也挺實(shí)用。我們這里先不注重樣式,主要是實(shí)現(xiàn)簡(jiǎn)單的增刪改的功能。
下面是全部代碼,大約51行。

圖4
下面是頁面效果。

圖5
我們來跑下分吧!

文檔一覽
介紹
Strve.js的讀音/str'vi/,是字符串(String)與視圖(View)的拼接。Strve.js是一個(gè)可以將字符串轉(zhuǎn)換為視圖的JS庫。這里的字符串指的是模板字符串,所以你僅需要在JavaScript中開發(fā)視圖。這里的視圖指的就是我們平時(shí)寫的HTML頁面,也就是視圖層。
Strve.js不僅易于上手,還便于靈活拆裝不同的代碼塊。使用模板字符串開發(fā)視圖主要是利用了原生JavaScript的能力,可以更加靈活地分離代碼塊,你僅僅只關(guān)注JavaScript文件。
Strve.js又是一款輕量級(jí)的MVVM框架,你只需要關(guān)心數(shù)據(jù)以及如何操作它,其他工作交給Strve.js內(nèi)部處理。Strve.js首先會(huì)將模板字符串轉(zhuǎn)化為虛擬DOM,然后進(jìn)行Diff算法通過比較前后兩次的狀態(tài)差異更新真實(shí)DOM。這也是很多框架為了提升瀏覽器性能采用的方案,但是Strve.js更加輕量。
如果你想上手項(xiàng)目,那么請(qǐng)看下面怎么安裝它吧!
安裝
CDN
如果你使用原生 ES Modules。
<script?type="module">
??import?{?Strve,?render}?from?'https://cdn.jsdelivr.net/npm/strvejs/dist/strve.esm.min.js';
script>
NPM
npm?i?strvejs
命令行工具
create-strve-app
一套快速搭建Strve.js項(xiàng)目的命令行工具。與早期的腳手架 Create Strve 相比,Create Strve App 更勝一籌,可直接輸入命令快速創(chuàng)建Strve項(xiàng)目。Create Strve App是用Vite來構(gòu)建的,它是一種新型前端構(gòu)建工具,能夠顯著提升前端開發(fā)體驗(yàn)。
npm
npm?init?strve-app@latest
yarn
yarn?create?strve-app
pnpm
pnpm?create?strve-app
create-strve
Create Strve 是基于Strve.js的項(xiàng)目構(gòu)建工具,您可以使用它更方便靈活地搭建頁面。
全局安裝
npm?install?create-strve?-g
查看版本
create-strve?-v
初始化項(xiàng)目
create-strve?init?
快速上手
嘗試 Strve.js 最簡(jiǎn)單的方法是使用直接引入CDN鏈接。你可以在瀏覽器打開它,跟著例子學(xué)習(xí)一些基礎(chǔ)用法。
html>
<html?lang="en">
<head>
????<meta?charset="UTF-8">
????<title>Strve.jstitle>
????<style>
????????.inner?{
????????????width:?900px;
????????????margin:?40px?auto;
????????????text-align:?center;
????????????padding:?40px;
????????????box-shadow:?0?0?20px?#ccc;
????????}
????????button?{
????????????margin:?10px;
????????}
????style>
head>
<body>
????<div?id="app">div>
????<script?type="module">
????????import?{?Strve,?updateView,?render,?emitEvent?}?from?'https://cdn.jsdelivr.net/npm/strvejs/dist/strve.esm.js';
????????const?state?=?{
????????????arr:?[{
????????????????id:?'1',
????????????????txt:?'1'
????????????},?{
????????????????id:?'2',
????????????????txt:?'2'
????????????},?{
????????????????id:?'3',
????????????????txt:?'3'
????????????},?{
????????????????id:?'4',
????????????????txt:?'4'
????????????}],
????????????msg:?'hello',
????????????a:?2,
????????????style:?{
????????????????color:?'red',
????????????????fontSize:?"40px"
????????????},
????????????obj:?{
????????????????a:?{
????????????????????b:?{
????????????????????????c:?1
????????????????????}
????????????????}
????????????}
????????};
????????function?Component1(v)?{
????????????return?render/*?html?*/`
????????????????????${emitData}
>${v}
????????????????????
????????????????????????${state.arr.map((todo)?=>?render/*?html?*/`- ${todo.txt}
`)}
????????????????????
????????????`
????????}
????????function?emitData()?{
????????????emitEvent('getTit',?{
????????????????detail:?{?title:?'This?is?title!'?},
????????????},?'.component1')
????????}
????????function?App()?{
????????????return?render/*?html?*/`
??????????????
??????????????????${state.style}">{state.obj.a.b.c}
??????????????????${state.obj.a.b.c}/>
??????????????????${state.msg}
??????????????????${state.a?+?state.a}
??????????????????
??????????????????
??????????????????${getTit}?class="component1">
????????????????????${Component1(state.msg)}
??????????????????
??????????????
??????????`;
????????}
????????function?getTit(event)?{
????????????updateView(()?=>?{
????????????????state.msg?=?event.detail.title;
????????????})
????????}
????????function?useChange()?{
????????????updateView(()?=>?{
????????????????state.arr.splice(1,?1,?{
????????????????????id:?'0',
????????????????????txt:?'0'
????????????????});
????????????})
????????}
????????let?count?=?5;
????????function?usePush()?{
????????????updateView(()?=>?{
????????????????//?state.obj.a.b.c?=?3;
????????????????//?state.style.color?=?'blue';
????????????????//?state.arr.length?=?2;
????????????????//?state.arr[1]?=?{
????????????????//?????id:?'4',
????????????????//?????txt:?'4'
????????????????//?}
????????????????//?state.msg?=?'world';
????????????????let?a?=?count++;
????????????????state.arr.push({
????????????????????id:?a,
????????????????????txt:?a
????????????????})
????????????????//?state.arr.pop();
????????????????//?state.arr.unshift({
????????????????//?????id:?a,
????????????????//?????txt:?a
????????????????//?});
????????????????//?state.arr.shift();
????????????});
????????????//?'useFkey'
????????}
????????Strve('#app',?{
????????????data:?{?state?},
????????????template:?App
????????});
????script>
body>
html>
如果你還想深入學(xué)習(xí)其他關(guān)于 Strve.js 的內(nèi)容,你可以繼續(xù)往下閱讀。
使用
API
Strve
參數(shù):
stringobject
詳細(xì):
初始化Strve.js。第一個(gè)參數(shù)傳入需要掛載到HTML頁面的節(jié)點(diǎn)選擇器名稱。第二個(gè)參數(shù)傳入一個(gè)對(duì)象,第一個(gè)屬性data表示的意思是狀態(tài)對(duì)象,第二個(gè)屬性template表示模板函數(shù)。
Strve('#app',?{
????data:?{?state?},
????template:?App
});
render
- 類型:
function - 詳細(xì):
render`` 是一個(gè)標(biāo)簽函數(shù),標(biāo)簽函數(shù)的語法是函數(shù)名后面直接帶一個(gè)模板字符串,并從模板字符串中的插值表達(dá)式中獲取參數(shù)。比如說,你可以在模板字符串中直接可以寫HTML標(biāo)簽。
function?App()?{
????return?render`
????????
????????????Hello
????????
????`;
}
如果你使用的是VSCode編輯器,你可以去商店里下載comment-tagged-templates插件,然后,在render`` 中間加上/*html*/ 。
就像這樣,它可以使HTML標(biāo)簽字符高亮顯示。
function?App()?{
????return?render/*html*/`
????????
????????????Hello
????????
????`;
}
updateView
- 參數(shù):
functionstring(可選)
- 詳細(xì):
第一個(gè)參數(shù)是一個(gè)函數(shù)。函數(shù)體中需要執(zhí)行將改變頁面狀態(tài)的值,例如以下示例中的state.msg。
const?state?=?{
????msg:'1'
};
function?App()?{
????return?render`
????????
????????????
????????????{state.msg}
????????
????`;
}
function?useChange()?{
????updateView(()?=>?{
????????state.msg?=?'2';
????});
}
第二個(gè)參數(shù)是字符串類型,在當(dāng)你使用列表渲染頁面時(shí),在列表頭部插入數(shù)據(jù)需要綁定useFkey字段,以避免DOM節(jié)點(diǎn)重復(fù)渲染。
const?state?=?{
????arr:?[1,?2]
};
function?Home()?{
????return?render`
????????
????????????
????????????
????????????????${state.arr.map((item)?=>?render`- ${item}
`)}
????????????
????????
????`
}
function?useUnshift()?{
????updateView(()?=>?{
????????state.arr.unshift('2');
????},?'useFkey')
}
emitEvent
參數(shù):
stringdictionarystring
詳細(xì):
自定義事件,一般是用于子組件數(shù)據(jù)傳入父組件。第一個(gè)參數(shù)是表示 event 名字的字符串。第二個(gè)參數(shù)一個(gè)字典類型參數(shù)。
- "detail",可選的默認(rèn)值是 null 的任意類型數(shù)據(jù),是一個(gè)與 event 相關(guān)的值。
- bubbles 一個(gè)布爾值,表示該事件能否冒泡。來自 EventInit。注意:測(cè)試chrome默認(rèn)為不冒泡。
- cancelable 一個(gè)布爾值,表示該事件是否可以取消。
第三個(gè)參數(shù)是一個(gè)字符串類型,主要是節(jié)點(diǎn)選擇器的名稱,這里的節(jié)點(diǎn)指的是子組件在父組件中外層包裹的DOM節(jié)點(diǎn)。
例如:
function?Component1(v)?{
????return?render`
????????${emitData}
>${v}
????`
}
function?emitData()?{
????emitEvent('getTit',?{
????????detail:?{?title:?'This?is?title!'?},
????},?'.component1')
}
function?App()?{
????return?render`
????????
????????????${getTit}?class="component1">
????????????${Component1(state.msg)}
????????????
????????
????`;
}
function?getTit(event)?{
????updateView(()?=>?{
????????console.log(event.detail.title);
????????state.msg?=?event.detail.title;
????})
}
插值
Strve.js 使用了基于 JavaScript 的模板字符串語法,允許開發(fā)者聲明式地將 DOM 綁定至底層實(shí)例的數(shù)據(jù)。所有 Strve.js 的模板字符串都是合法的 HTML,所以能被遵循規(guī)范的瀏覽器和 HTML 解析器解析。
在底層的實(shí)現(xiàn)上,Strve.js 將模板字符串編譯成虛擬 DOM 渲染函數(shù),并把 DOM 操作次數(shù)減到最少。
在Strve.js中,你可以盡情的使用JavaScript 的模板字符串,感受它獨(dú)特的魅力吧!
文本
數(shù)據(jù)綁定最常見的形式就是使用符號(hào)${}的文本插值:
const?state?=?{
????msg:?'hello'
};
function?App()?{
????return?render`
????????
????????????${state.msg}
????????
????`;
}
另外你還可以使用更簡(jiǎn)便的方法符號(hào){},同樣可以達(dá)到預(yù)想的效果。
const?state?=?{
????msg:?'hello'
};
function?App()?{
????return?render`
????????
????????????{state.msg}world
????????
????`;
}
但是,使用這種符號(hào){}需要注意的是,它只適用于標(biāo)簽內(nèi)的文本插值。例如如下這種情況,它是不起作用的,不過你可以使用強(qiáng)大的符號(hào)${}。
//?Bad
function?App()?{
????return?render`
????????
????????????
????????
????`;
}
//?Good
function?App()?{
????return?render`
????????
????????????${state.msg}/>
????????
????`;
}
表達(dá)式
目前僅支持在符號(hào)${}中使用表達(dá)式。
例如:
const?state?=?{
????a:?1,
????b:?2
};
function?App()?{
????return?render`
????????
????????????${state.a?+?state.b}
????????
????`;
}
屬性綁定
前面,我們可以看到使用符號(hào)${}可以與屬性value綁定值。
function?App()?{
????return?render`
????????
????????????${state.msg}/>
????????
????`;
}
另外,你還可以綁定其他屬性,例如class。
const?state?=?{
????isRed:?true
};
function?App()?{
????return?render`
????
????????${state.isRed???'red'?:?''}>Strve.js
????
`;
}
如果你想綁定style屬性,同樣也可以。
const?state?=?{
????msg:?'hello',
????style:?{
????????color:?'red',
????????fontSize:?"40px"
????}
};
function?App()?{
????return?render`
????????
????????????${state.style}">{state.msg}
????????
????`;
}
條件渲染
我們也可以使用符號(hào)${},這塊內(nèi)容只會(huì)在指令的表達(dá)式返回 true 值的時(shí)候被渲染。
const?state?=?{
????isShow:?false
};
function?App()?{
????return?render`
????????
????????????
????????????${state.isShow???render`Strve.js
`?:?''
????????}
????????
????`;
}
function?useShow()?{
????updateView(()?=>?{
????????state.isShow?=?!state.isShow;
????});
}
列表渲染
我們可以用符號(hào)${}基于一個(gè)數(shù)組來渲染一個(gè)列表。比如我們使用數(shù)組的map方法來渲染列表,并且可以動(dòng)態(tài)添加數(shù)組項(xiàng)。
const?state?=?{
????arr:?['1',?'2']
};
function?App()?{
????return?render`
????????
????????????
????????????
????????????${state.arr.map((todo)?=>?render`- ${todo}
`)}
????????????
????????}
????????
????`;
}
function?usePush()?{
????updateView(()?=>?{
????????state.arr.push('3');
????});
}
上面我們提到updateView()可以傳入第二個(gè)參數(shù),它是字符串類型,在使用列表渲染頁面時(shí),如果在列表頭部插入數(shù)據(jù)則需要綁定useFkey字段,以避免DOM節(jié)點(diǎn)重復(fù)渲染,這是必須要做的。任何在列表頭部操作的動(dòng)作,如unshift、pop數(shù)組方法都需要加上這個(gè)useFkey字段。其他操作則不需要這樣,內(nèi)部已經(jīng)進(jìn)行了優(yōu)化。
const?state?=?{
????arr:?[1,?2]
};
function?Home()?{
????return?render`
????????
????????????
????????????
????????????????${state.arr.map((item)?=>?render`- ${item}
`)}
????????????
????????
????`
}
function?useUnshift()?{
????updateView(()?=>?{
????????state.arr.unshift('2');
????},?'useFkey')
}
事件處理
我們可以使用on指令來監(jiān)聽 DOM 事件,并在觸發(fā)事件時(shí)執(zhí)行一些 JavaScript。我們推薦使用這種onClick駝峰式命名方法,當(dāng)然,直接使用onclick這種全小寫方式也可以。
需要使用符號(hào)${}來綁定事件。
function?App()?{
????return?render`
????????
????????????
????????}
????????
????`;
}
function?useClick()?{
????console.log('hello');
}
與Vue.js搭配
Strve.js不僅可以單獨(dú)使用,也可以與Vue.js搭配使用。你需要在Vue實(shí)例掛載完成后被調(diào)用Strve()注冊(cè)方法,并且第一個(gè)參數(shù)已經(jīng)在template標(biāo)簽中存在。
App.vue
<template>
??<div?id="container">
????<HelloWorld/>
??div>
template>
<script>
import?HelloWorld?,{hello}?from?'./components/HelloWorld.vue';
import?{?about,state?}?from?'./components/About.vue';
import?{?render,?Strve?}?from?"strvejs";
const?AppTm?=?()?=>?render`
??????
????????${hello()}
????????${about()}
??????
`;
export?default?{
??name:?"App",
??components:{
????HelloWorld
??},
??mounted()?{
????Strve("#container",?{
??????data:?{state},
??????template:?AppTm,
????});
??},
};
script>
如果需要與Vue共享一個(gè)方法,推薦在setup方法中使用。
HelloWorld.vue
<template>
??<div>
????<img?src="../assets/logo.png"?alt=""?@click="useCliimg">
??div>
template>
<script>
import?{?render?}?from?"strvejs";
import?styles?from?'../assets/hello/hello.module.css';
export?const?hello?=?()=>render`
${styles.color}
"?onClick=${useCliimg}>hello
`
function?useCliimg(){
????console.log(1);
}
export?default?{
??name:'HelloWorld',
??setup(){
????return?{
??????useCliimg
????}
??}
}
script>
如果,你想在Vue組件中完全使用Strve.js,當(dāng)然也可以。不過最后,推薦使用export default導(dǎo)出組件名。
About.vue
<script>
import?{?render,?updateView?}?from?"strvejs";
import?styles?from?'../assets/about/about.module.css';
export?const?about?=?()=>render`
????{state.msg}
???${styles.color}"?onClick=${useClick}>about
`
export?const?state?=?{
????msg:"hello"
}
function?useClick()?{
????updateView(()=>{
????????state.msg?=?'world';
????})
}
export?default?{
????name:"About"
}
script>
與React.js搭配
Strve.js與Vue.js搭配相比,與React.js搭配使用更為靈活。同樣需要在組件第一次渲染完成后調(diào)用Strve()方法注冊(cè)方法。
App.js
import?{useEffect}?from?'react'
import?{Strve,render,updateView}?from?'strvejs';
import?'./App.css';
const?state?=?{
??msg:"Hello"
}
function?Home(){
??return?render`${useClick}
>{state.msg}`
}
function?useClick(){
??updateView(()=>{
????state.msg?=?"World";
??})
}
function?App()?{
??useEffect(()=>{
????Strve(".App",{
??????data:{state},
??????template:?Home
????})
??})
??return?(<div?className="App">div>);
}
export?default?App;
工具
create-strve-app
一套快速搭建Strve.js項(xiàng)目的命令行工具。與早期的腳手架 Create Strve 相比,Create Strve App 更勝一籌,可直接輸入命令快速創(chuàng)建Strve項(xiàng)目。Create Strve App是用Vite來構(gòu)建的,它是一種新型前端構(gòu)建工具,能夠顯著提升前端開發(fā)體驗(yàn)。
搭建你的第一個(gè) Strve 項(xiàng)目
npm
npm?init?strve-app@latest
yarn
yarn?create?strve-app
pnpm
pnpm?create?strve-app
選擇模板
你可以根據(jù)自己的需要選擇對(duì)應(yīng)的模板。
- strve
只包含Strve.js基本使用的功能。此模板適用于項(xiàng)目中僅僅單頁面,沒有跳轉(zhuǎn)其他頁面的應(yīng)用。
- strve-apps
不僅包含了Strve.js的基本使用的功能,而且還包含了Strve Router,適用于跳轉(zhuǎn)多頁面以及稍微復(fù)雜的應(yīng)用。
create-strve
在前面我們也簡(jiǎn)單介紹過,Create Strve是基于Strve.js的項(xiàng)目構(gòu)建工具,您可以使用它更方便靈活地搭建頁面。Create Strve同樣是用Vite來構(gòu)建的。
不過,在這里推薦使用Create Strve App,它相對(duì)安裝更加靈活以及快速。
安裝
全局安裝
npm?install?create-strve?-g
查看版本
create-strve?-v
初始化項(xiàng)目
create-strve?init?
strve-router
Strve Router 是 Strve.js 的官方路由管理器。它與 Strve.js 的核心深度集成,可以輕松構(gòu)建單頁應(yīng)用程序。
目前只支持Hash模式。
開始
嘗試 Strve Router 最簡(jiǎn)單的方法是使用直接導(dǎo)入 CDN 鏈接。您可以在瀏覽器中打開它并按照示例學(xué)習(xí)一些基本用法。
html>
<html?lang="en">
<head>
????<meta?charset="UTF-8">
????<title>StrveRoutertitle>
head>
<body>
????<div?id="app">div>
????<script?type="module">
????????import?{?Strve,?render,?updateView?}?from?'https://cdn.jsdelivr.net/npm/strvejs/dist/strve.esm.js';
????????import?StrveRouter?from?'https://cdn.jsdelivr.net/npm/strve-router/dist/strve-router.esm.js';
????????const?state?=?{
????????????msg:?'Hello!'
????????};
????????const?strveRouter?=?new?StrveRouter([{
????????????path:?'/',
????????????template:?Home
????????},?{
????????????path:?'/about',
????????????template:?About
????????}]);
????????strveRouter.routerHashUpdate(updateView,?()?=>?{
????????????console.log(strveRouter.param2Obj());
????????});
????????function?Home()?{
????????????return?render`
????????????????
????????????????????
????????????????????Home
????????????????
????????????`
????????}
????????function?About()?{
????????????return?render`
????????????????
????????????????????
????????????????????
????????????????????About
????????????????
????????????`
????????}
????????function?App()?{
????????????return?render`
??????????????
????????????????{state.msg}
????????????????${strveRouter.routerView()}
??????????????
??????????`;
????????}
????????function?goback()?{
????????????strveRouter.back();
????????}
????????function?goAbout()?{
????????????console.log('goAbout');
????????????strveRouter.routerLink({
????????????????path:?'/about',
????????????????query:?{
????????????????????id:?1,
????????????????????name:?"maomin"
????????????????}
????????????});
????????}
????????function?goHome()?{
????????????console.log('goHome');
????????????strveRouter.routerLink('/');
????????}
????????Strve('#app',?{
????????????data:?{?state?},
????????????template:?App
????????});
????script>
body>
html>
安裝
npm
npm?install?strve-router
yarn
yarn?add?strve-router
pnpm
pnpm?add?strve-router
使用
如果在一個(gè)模塊化工程中使用它,可以引入StrveRouter對(duì)象,然后實(shí)例化。參數(shù)是需要注冊(cè)的路由組件,path屬性代表路徑,template屬性代表引入的組件。
匹配到相應(yīng)的路徑頁面會(huì)相應(yīng)的更新,所以這里必須注冊(cè)一個(gè)routerHashUpdate()方法,然后第一個(gè)參數(shù)傳入updateViewAPI,第二個(gè)參數(shù)則是一個(gè)自定義方法。最后導(dǎo)出strveRouter實(shí)例。
比如這里在一個(gè)router文件夾下創(chuàng)建一個(gè)index.js文件。
import?StrveRouter?from?'strve-router';
import?{updateView}?from?'strvejs';
import?Home?from?'../template/homepage.js';
import?About?from?'../template/aboutpage.js';
const?strveRouter?=?new?StrveRouter([{
????path:?'/',
????template:?Home
},?{
????path:?'/about',
????template:?About
}]);
strveRouter.routerHashUpdate(updateView,()=>{
????console.log('router');
});
export?default?strveRouter
路由匹配到的組件將渲染到routerView()方法所在的地方,一般會(huì)放在主頁面入口文件下(例如App.js)。
import?{?render?}?from?'strvejs';
import?strveRouter?from?'./router/index';
function?template()?{
??return?render`
????????
????????${strveRouter.routerView()}
????????
????`;
}
export?default?template;
如果需要跳轉(zhuǎn)到對(duì)應(yīng)頁面,使用strveRouter.routerLink()方法,可以傳對(duì)應(yīng)的路徑和需要傳的參數(shù),也可以直接傳一個(gè)路徑字符串。
import?{?render?}?from?'strvejs'
import?strveRouter?from?'../router/index.js'
function?Home(){
????return?render`
????????
????????????
????????????Home
????????
????`
}
function?goAbout(){
????strveRouter.routerLink({
????????path:?'/about',
????????query:?{
????????????id:?1,
????????????name:?"maomin"
????????}
????});
}
export?default?Home
如果你需要實(shí)現(xiàn)后退、前進(jìn)跳轉(zhuǎn)頁面這樣操作時(shí),同樣提供了幾個(gè)方法。
strveRouter.forward(): 向前跳轉(zhuǎn)1個(gè)頁面strveRouter.back(): 向后跳轉(zhuǎn)1個(gè)頁面strveRouter.go(n): 向前跳轉(zhuǎn)n個(gè)頁面
另外,如果你執(zhí)行了路由傳參的操作,想獲取參數(shù)對(duì)象。直接執(zhí)行strveRouter.param2Obj()方法就可以獲取對(duì)象信息。
最后,我們已經(jīng)給你預(yù)裝了項(xiàng)目配置,你可以使用Create Strve App選擇strve-apps模板即可。
其它
IDE支持
Visual Studio Code
- 模板字符串自動(dòng)補(bǔ)全標(biāo)簽
打開設(shè)置下的settings.json,加入如下代碼:
"emmet.triggerExpansionOnTab":?true,
"emmet.showAbbreviationSuggestions":?true,
"emmet.showExpandedAbbreviation":?"always",
"emmet.includeLanguages":?{
????"javascript":?"html"
}
- 支持HTML模板字符串高亮顯示
下載comment-tagged-templates插件。在render``方法中間加上/* html */。
function?App()?{
????return?render/*?html?*/`
????????
????????????${state.msg}
????????
????`;
}
UI框架
- Bootstrap5
https://v5.bootcss.com/
- Tailwindcss
https://www.tailwindcss.cn/
更新日志
v2.1.0
- 修復(fù)DOM屬性property無法賦值的問題;
- 完善字符串轉(zhuǎn)換為虛擬DOM邏輯問題;
v2.0.0
向鏈表頭部插入數(shù)據(jù)需要綁定
useFkey字段,避免DOM節(jié)點(diǎn)重復(fù)渲染;渲染后隱藏“DOM”節(jié)點(diǎn)事件方法;
綁定
Style樣式(對(duì)象);綁定屬性統(tǒng)一使用
${}符號(hào)綁定;支持 HTML 模板字符串高亮(VSCode 編輯器需要安裝
comment-tagged-templates插件);支持父子組件互相傳值;
適配Bootstrap5、Tailwindcss UI框架;
關(guān)于作者
- 英文名:Vam
- 昵稱ID:maomincoding
- Github:https://github.com/maomincoding
- Twitter:https://twitter.com/maomincoding
- 微信公眾號(hào):前端歷劫之路
結(jié)語
因?yàn)槠脑颍疫@里先介紹這么多吧!有感興趣的朋友可以打開官方文檔去了解一下Strve.js,做幾個(gè)小項(xiàng)目玩一下。
https://github.com/maomincoding/strve/
https://maomincoding.github.io/strvejs-doc/zh/
還有如果有交流學(xué)習(xí)的朋友可以在下面留言或者關(guān)注我,我們一起加油!
這一篇也是2021年最后一篇了,感謝大家對(duì)我的支持,祝大家在新的一年里身體健康,萬事如意。
點(diǎn)此卡片,即可關(guān)注我
