易、轻、快!超牛逼纯JS前端框架——MithrilJS

--> -->

这里面是纯原生,没有使用webpack之类的打包,所以引用了很多组件js,当然你也可以写到一个里面,但是那实在不好看也不好拓展。

使用了less,为了偷懒,你让我在工程里面使用原生CSS,臣妾真的做不到了。


less

less的内容就不做过多展示,这个有兴趣在下方去源码里面看吧,这里略过了。


js

大头来了,我这里会直接贴出代码,然后在路由那里说一下,为什么我不多说呢,因为MithrilJS真的太简单了(我会告诉你我懒得说么)。。。

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。

说到这里,刚好顺带过一下MithrilJS的声明周期,如下:

用法与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路径等。

第二:路由的简单配置。

注意,MithrilJS没有类似Vue的router-view这种组件,它还是建议把组件配到大组件里面,这个缺点就是如果业务的路由组件非常深入,就相对麻烦,但是优点还是简单!

这里配置根路径地址就是Homepage组件,当路由切换到share时候,就是Share组件显示了。

同样的,MithrilJS的路由标记像这样:#!/share,默认是使用#!,当然,你可以通过类似m.route.prefix("#")来修改路由标记,但是个人觉得意义不大。起码别人逛你网站的时候,懂行的一眼就看出来你用的是MithrilJS写的页面,恩,厉害!


到最后,index.html解析所有的内容后,就渲染出文章开头的页面了,点击切换时候还有淡入淡出的效果(上面的链接看不到,因为Vue版本我还没加路……)。


OK,简单,快速,小巧的一个牛逼纯JS框架MithrilJS,带你们走了一遍简单的。

MithrilJS当然也是支持ES6,以及JSX的,本人不是很喜欢JSX的写法,所以采用了原生的,而要用以上两个,都需要去配置下webpack,这里不做过多介绍了。

如果想看源码,请到下面的GitHub源码里面,找到mi分支即可,默认master分支是Vue版本哦。


项目源码:Github:https://github.com/ZweiZhao/WBRoom


喜欢我的文章,请关注一波啊,定期更新技术文章,满满的都是干货!


分享到:


相關文章: