「前端騷操作」易、輕、快!超牛逼純JS前端框架Mithril

--> -->


這裡面是純原生,沒有使用 webpack 之類的打包,所以引用了很多組件 js,當然你也可以寫到一個裡面,但是那實在不好看也不好拓展。

使用了 less,為了偷懶,你讓我在工程裡面使用原生 CSS,臣妾真的做不到了。


less

less 的內容就不做過多展示,就是堆頁面,這裡略過了。


js

大頭來了,我這裡會直接貼出代碼,然後在路由那裡說一下,為什麼我不多說呢,因為 Mithril 真的太簡單了(我會告訴你我懶得說麼)。。。

header.js

const Header = (function() {
return {
view(v) {
const titles = ['首頁', '分享', '設計', '繪畫', '攝影']
const hrefs = ['#!/', '#!/share']
const selectedIndex = v.attrs.selectedIndex
return m("header", [
m("h1", "KOOJEE"),
m('section.titles',
titles.map((title, index) => m('a', {class: 'title' + (selectedIndex === index ? ' selected' : ''), href: hrefs[index] || '#'}, titles[index])
)
),
])
}
}
})()

這裡使用了自運行函數,為了是避免變量名汙染。

組件就是個對象,組件 DOM 結構實在 view 這個屬性值下的一個函數返回,函數可攜帶 vnode 對象,用來傳參等等,獲取參數使用v.attrs。

其他就是常規內容,渲染了一個header標籤,裡面包了一個 h1 標籤,包了一個 section.titles 標籤, section.titles 裡面根據titles數組生成了 5 個 a.title 標籤。

這就是 header 了。


footer.js

const Footer = (function() {
return {
view() {
return m(
'footer'
)
}
}
})()

目前沒東西,所以渲染了一個空的 footer 標籤用來佔位。


homepage.js

const Homepage = (function() {
const h2 = '最終選擇了生活……'
const h3 = '寧願向著遠方哭泣,不願望著當下詫異。'

let contentImgs = ['Bitmap1.png', 'Bitmap2.png', 'Bitmap3.png', 'Bitmap4.png']
let arts = [
{
img: 'Bitmap5.png',
main: '經歷',
desc: '我在東方等你,不濟那遠去的夕陽。',
},
{
img: 'Bitmap6.png',
main: '興趣',
desc: '給個遊戲,能躺半年。',
},
{
img: 'Bitmap7.png',
main: '性格',
desc: '熱辣似火,妖嬈弄人?不不不,就是呆萌。',
},
{
img: 'Bitmap8.png',
main: '態度',
desc: '你到底準備用什麼態度和姑奶奶說話?',
},
]
const Content = {
onbeforeremove(v) {
v.dom.classList.add("exit")
return new Promise(function(resolve) {
setTimeout(resolve, 500)
})
},
view() {
return m('main#homepage.fancy',
m('section.content-center', [
m('h2', h2),
m('h3', h3),
contentImgs.map((contentImg, index) => m('img', {class: 'img' + index, src: assetsPath + contentImg, alt: 'content-img'}))
])
)
}
}
return {
view(v) {
return [

m(Header, {selectedIndex: 0}),
m(Content),
m(Footer),
]
}
}
})()

因為將來要使用數據驅動,所以把數據提出去,方便後續服務器請求數據操作。

這裡使用了 m 函數的組件模式,如上例子中的:m(Header, {selectedIndex: 0}),就是 homepage 組件裡面包含了一個 Header 組件,並且給 Header 組件傳參了,這個參數的使用在上面 Header 組件那裡可以看到。

注意這裡有個內部的 Content 組件,這個是用來做動畫的,比如你頁面內路由切換時,為了看起來更舒服,可以做個過渡動畫,Homepage 組件自帶 fancy 類的 CSS,然後 Homepage 的 Content 組件在聲明週期 onbeforeremove 即將要消失的時候添加了一個 exit 類的 CSS,具體兩個 CSS 如下:

.fancy {animation:fade-in 0.5s;}
@keyframes fade-in {
from {opacity:0;}
to {opacity:1;}
}
.exit {animation:fade-out 0.5s;}
@keyframes fade-out {
from {opacity:1;}
to {opacity:0;}
}

瞭解 CSS 的同學就知道是什麼動畫了,對,就是淡入與淡出,分別 0.5s。

說到這裡,剛好順帶過一下 Mithril 的聲明週期,如下:

用法與 view 一樣,放在對象的屬性上,對應值是函數,都可以獲取 vnode。

  1. oninit
  2. 初始化時候,方便放一些準備用的數據,或者用來網絡請求。此時可以拿到 vnode,但是不一定拿得到真實 DOM,所以這裡不推薦進行相關的 DOM 操作,比如:vnode.dom。
  3. oncreate
  4. 創建成功,此時可以拿到真實 DOM 了。
  5. onupdate
  6. DOM 渲染刷新後。業務有刷新變動數據時候使用。
  7. onbeforeremove
  8. DOM 銷燬前。常用,比如我們的離開動畫。
  9. onremove
  10. DOM 銷燬後。一樣不建議進行真實 DOM 操作,用來銷燬垃圾數據可以使用。
  11. onbeforeupdate
  12. DOM 渲染刷新前。業務有刷新變動數據時候使用。

share.js

const Share = (function() {
let bannerSrc = 'https://wbroom-blog.oss-cn-hangzhou.aliyuncs.com/public/assets/share-bannre.png'
const Content = {
onbeforeremove(v) {
v.dom.classList.add("exit")
return new Promise(function(resolve) {
setTimeout(resolve, 500)
})
},
view() {
return m('main#share.fancy', [
m(`img.share-banner[class="lazy" src="//p2.ttnews.xyz/loading.gif" data-original=${bannerSrc}]`),
m('section.arts',
[1,1,1,1,1,1].map((item, index) => m('figure.art', [
m(`img.head[alt=${index}]`, {src: 'https://wbroom-blog.oss-cn-hangzhou.aliyuncs.com/public/assets/Bitmap1.png'}),
m('figcaption.main', '別看,看也沒博文。'),
m('span.time', '耶穌生日的那天'),
m('section.ctrl', [
m('span', '點贊(1000)'),

m('span', '評論(1000)'),
m('span', '瀏覽(100000)')
])
]))
),
m('section.pagination', '頁碼(待處理)'),
])
}
}
return {
view(v) {
return[
m(Header, {selectedIndex: 1}),
m(Content),
m(Footer),
]
}
}
})()

與 homepage 大同小異,只是堆頁面,放置一些圖片,頁碼也還沒做~

注意,一樣要設置進場動畫與離場動畫。


app.js

const rootPath = 'https://wbroom-blog.oss-cn-hangzhou.aliyuncs.com/'
const publicPath = rootPath + "public/"
const assetsPath = publicPath + "assets/"
m.route(document.body, '/', {
"/": Homepage,
'/share': Share,
})

這個就是常說的入口 js 了,由於存在 JS 對象的依賴關係,所以上面的組件不得不先加載,然後最後加載入口js。

第一:做一些全局的數據,比如本項目裡面需要用到的圖片資源 basic 路徑等。

第二:路由的簡單配置。

注意,Mithril 沒有類似 Vue 的 router-view 這種組件,它還是建議把組件配到大組件裡面,這個缺點就是如果業務的路由組件非常深入,就相對麻煩,但是優點還是簡單!

這裡配置根路徑地址就是 Homepage 組件,當路由切換到 share 時候,就是 Share 組件顯示了。

同樣的,MithrilJS的路由標記像這樣:#!/share,默認是使用#!,當然,你可以通過類似m.route.prefix("#")來修改路由標記,但是個人覺得意義不大。起碼別人逛你網站的時候,懂行的一眼就看出來你用的是 Mithril 寫的頁面,恩,厲害!


到最後,index.html 解析所有的內容後,就渲染出文章開頭的頁面了,點擊切換時候還有淡入淡出的效果(上面的鏈接看不到,因為 Vue 版本我還沒加路……)。


OK,簡單,快速,小巧的一個牛逼純 JS 框架 Mithril,帶你們走了一遍簡單的。

Mithril 當然也是支持 ES6,以及 JSX 的,本人不是很喜歡 JSX 的寫法,所以採用了原生的,而要用以上兩個,都需要去配置下 webpack,這裡不做過多介紹了。


歡迎關注,如有需要 Web,App,小程序,請留言聯繫。


分享到:


相關文章: