Svelte是最近新出的前端框架,和react的vdom不一樣,Svelte使用靜態分析在構建時建立DOM更新代碼,搭配官網一目瞭然的新手教程,給人直觀的使用體驗,上手會很快。在業務實踐中我上手採坑並總結了一下內容,經實踐能夠直接上生產。javascript
一般在react項目裏咱們會用ts提升業務邏輯開發效率,style module用來避免css命名重疊。在react中多是這麼寫css
// index.tsx ... <ul className={styles.mylist} ref={this.myRef} onScroll={this.scrollHandler}> {this.props.data.length>0 ?this.props.data.map((v,i)=> <Item key={i}>{v}</Item> ) :<li>empty</li> } </ul> ...
在svelte直接單文件組件html
// index.svelte <script lang="ts"> ... import type {IData} from "./types.ts" import Item from "./item.svelte" export let data:IData=[] export let myRef; scrollHandler=()=>{} </script> <style> ... </style> <ul class="mylist" bind:this={myRef} on:scroll={scrollHandler}> {# if data.length>0} <li>empty</li> {:else} {#each data as v,i} <Item>{v}</Item> {/each} {/if} </ul>
須要注意:
1.凡是svelte組件import的名稱必須首字母大寫,否則編譯不認它是個svelte組件。前端
2.import ts類型聲明必須是 import type ... 也是爲了更好的區分.vue
export let/const
變量 做爲相似props的語法,目前語法檢查還不完善,有時會出現警告組件內的狀態沒什麼好說的,臨時變量一把梭就行了。本文只討論store的用法。爲了讓svelte狀態管理有redux的味道,我實踐中用如下的寫法,不喜勿噴:java
//store.ts import { writable } from 'svelte/store'; //聲明初始state let initState={ loading:false, readed:0, } const state = writable(initState); const { subscribe, set, update } = state; //可能用獲得的reset const reset = () => set(initState); //mounted方法會在組件的onMount時調用 const mounted = async () => { updateLoadStart(); const {data,error}=await server.getPageData(); !error && await updateReaded(data); updateLoadEnd(); } updateLoadStart=()=>update((prevState)=>{ return { ...prevState, loading:true } }) ...
在組件裏即可以這麼引入使用:react
<script lang="ts"> import {state,mounted, onBtnClick} from "./store"; onMount(mounted); </script> <button on:click={onBtnClick}>{$state.readed}</button>
實踐中你能夠大膽的拆分和命名 好比類vue的命名 mounted method compute的數據管理,又好比類rematch的 select loading.effects 組合,具體看以前框架的習慣過分一下~json
須要注意:redux
我看到 https://css-tricks.com/lazy-l... 一步步教學寫個圖片懶加載的組件。着實不錯,改一下兼容問題能夠上生產。segmentfault
其次官方文檔的motion/transition/animate 我試過能夠很方便實現一些常見動畫功能,好比動畫摺疊展開、輪播的滾動,這裏就不貼代碼了,跟着文檔走一遍基本沒難度。
注意的點:
1.on:click 這種直接透傳事件的貌似只在組件的根元素起做用,在子元素裏仍是得用on:click={() => dispatch('click')} 的方式向上emit
2.html標籤校驗居然認爲 href="javascript:" 不是合法的連接,必需要在上一行註釋<!-- svelte-ignore a11y-invalid-attribute -->才行
3.樣式寫法習慣上class="" style=""更接近vue,而不是react的 className="" style={}
4.bind過的ref記得onDestory時銷燬
官方給的rollup打包配置過於簡單了,也不兼容es5。網上看到有其餘同窗從新編譯svelte到es5的,也是厲害。其實魔改一下官方的rollup配置就行。我實踐中能夠愉快的把ts編譯成es5。
簡單講一下幾個要點,最後會放出配置文件給你們參考,少走彎路少採坑。
1.打包資源加hash
... output:{ ... entryFileNames: "bundle.[hash].js" }
"> 1%, not dead" 爲了兼容連箭頭語法都不支持的瀏覽器,選擇個,文件體積會加倍,一個頁面差很少200k gzip 60k
"> 5%, not dead" 這個就小了好多 100k+ gzip 30k+
3.用"rollup-plugin-serve"換掉官方手寫的serve
!production && serve({ contentBase: "dist", port: 5000 })
css: (css) => { const hash = crypto.createHash("md5").update("bundle" + css.code).digest("hex"); css.write("bundle." + hash.slice(0, 8) + ".css", !production); }
固然若是想postcss autofixer進一步處理的網上也有其餘答案
5.用@rollup/plugin-html 根據模板替換hash的文件並生成manifest
html({ dest: "dist", fileName: "index.html", template: async ({ bundle }) => { let bundleFileNames = Object.keys(bundle); fs.writeFile('dist/asset-manifest.json', JSON.stringify( bundleFileNames.reduce((assetMap,fileName) => { assetMap[fileName.replace(/\.\w+\./, '.')] = fileName; return assetMap }, {}),null,"\t"),"utf8"); return bundleFileNames.reduce( (code, fileName) => code.replace(fileName.replace(/\.\w+\./, '.'), fileName), await fs.readFile("public/index.html", "utf8") ); }, })
感受svelte體驗上模板語法和單位件組件的思路更接近vue,但又不徹底遵循指令規範(好比循環判斷)加入了精簡但又實用的 動畫 和 狀態管理。其次性能方面比react好一點點,打包體積小是有很大優點。指望將來在開發體驗好比工具鏈上有新的突破。
https://medium.com/@d_kzlv/yeah-holy-wars-i-like-that-1406eb291331 發現medium你們意見不一,看看就好