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你们意见不一,看看就好