SFC是vue提出来的一种组件代码组织形式,在后缀.vue的文件中将一个组件的模板、脚本和样式写在一起进行管理,有助于集中组织单一组件的所有内容。那你有没有想过,在jQuery的系统中,也可以实现SFC呢?本文就带你领略一番SFC在jQuery中的实践。
引入框架
首先,你需要在原有的jQuery系统中,引入一个框架jqvm,它是一个jquery插件,引入方式和其他插件一模一样。
<script src="https://unpkg.com/jqvm/dist/jqvm.min.js"></script>
这样,就有了支撑SFC运行的基本环境。
撰写SFC
接下来,撰写一个.htm文件作为jQuery的SFC:
<template hoist>
<div class="my-component">
<div class="my-component__title">{{title}}</div>
<div class="my-component__cotnent">{{content}}</div>
</div>
</template>
<style>
.my-component {
padding: 10px;
}
.my-component__title {
font-size: 1.4em;
}
</style>
<script>
export default ($template, $) => $template
.vm(() => {
return {
title: 'Default Title',
content: 'Default Content',
}
})
.on('$init', (state) => {
// 实例化的时候,拉取数据,填充
$.get('/api/data').then((data) => {
const { title, content } = data
state.title = title
state.content = content
})
})
</script>
这样就写好了一个SCF,它由三部分组成,其中<template hoist>
中的hosit
指使用组件将会直接被div
替换。等下你就能看到效果。
编译
接下来,你需要使用jqvm-loader对这个SFC进行编译。如果结合webpack,你可以这样配置:
// 前提先执行 npm i jqvm
{
module: {
rules: [
{
test: /\.html$/,
resourceQuery: /jqvm/, // 可选的,当你使用这个规则,那么只有 import .. from './some.html?jqvm' 才走jqvm/loader编译
use: [
{
loader: 'babel-loader', // 这个loader的功能很简单,就是把一个html文件解析出来之后,编译为一个ESModule,这个ESModule就是一个jqvm的组件,再交给babel去进行编译。
},
// 必须放在babel-loader下面
{
loader: 'jqvm/loader', // jqvm-loader的位置在jqvm包下面
options: {
$: true, // 可选,如果$为true,那么生成的组件代码中,不会引入jquery和jqvm,直接使用全局的$对象,如果传入一个字符串,比如'jQuery',那么会用这个字符串作为全局变量赋值给$作为jquery的引用
},
},
],
}
]
}
}
但是大多数情况下,以前的jquery系统都是直接引入,没有使用编译系统,此时应该这么办呢?你可以使用jqvm-loader暴露出来的编译接口,使用nodejs直接对SFC进行编译。
// compile.js
const { compile } = require('jqvm/loader')
const fs = require('fs')
const content = compile(fs.readFileSync(__dirname + '/my-component.htm').toString(), { $: true })
fs.writeFileSync(__dirname + '/my-component.js', content)
然后用nodejs运行这个编译文件
node compile.js
就可以生成一个my-component.js文件,你可以打开看看它的结果,它是一个ES模块,如果你需要在ES5环境中运行,你还需要用babel转译一次,如果你需要直接在浏览器中引入,还需要再用umd包裹一层,毕竟它只是一个ES模块。
如果想要按照传统的方式使用该组件,你可以使用webpack编译该组件。例如:
// my-component.bundle.js <- 用webpack打包成它
window['my-component'] = require('./my-component.js').default
使用带babel的webpack打包上面这个文件之后,就可以在window上挂载一个'my-component'属性。
使用组件
得到my-component.js之后(未经babel编译和umd包裹,还是一个ES模块),我们就可以使用这个组件了。接下来我们这样使用:
<my-component id="some"></my-component> <!-- 这个标签可以随便用,只要id对应好即可 -->
<script type="module">
import myComponent from './my-component.js'
myComponent.mount('#some')
</script>
这里使用了ES的语法import,因为我们直接把编译好的my-component.js拿来用,它又是一个ES模块,当前还只能通过这种方式加载。
经过上面这个操作,界面上就会在template#some下面渲染出SFC组件的结果。
使用type="module"只支持高级浏览器,以前老的jquery系统中很少这样用。你也可以自己经过处理之后,直接引入,以符合我们传统的编程直觉。利用前面编译得到的my-component.bundle.js,上面的脚本就可以重新这么写:
<script src="./my-component.bundle.js"></script> <!-- 加载这个组件,组件实例被挂在window上 -->
<script>
const myComponent = window['my-component']
myComponent.mount('#some')
</script>
这种写法和我们传统写jquery应用的写法一致。只不过中间的编译过程比较麻烦。
结束
哈哈,本文只是向你展示了一种在传统jquery中,也能实施一些新的理念的方式,至于你真的要在老的jquery系统中去实施,肯定还是会遇到一些坑,有不懂的地方,可以在下方留言,或者关注我的个人微信公众号 wwwtangshuangnet 一起讨论。最后,如果你觉得这个项目不错,到github给个star,上帝都会感谢你🙏