在vue-cli中独立构建主题
2019-09-25 本文已影响0人
bigfacewo
前言
一般主题功能都会归类到一系列css
中,通过文件名区分。这篇文章将手把手教你如何做一个属于你的主题功能,并且可以支持一定程度的热重载。理论上不需要和vue-cli
或者webpack
绑定。
动态加载主题
这一步很简单,当我切换主题的时候,移除旧的主题样式标签,然后添加新的主题样式标签即可。
首先,data
中定义:
data(){
return {
theme:'theme1',
linkId:'theme'
}
}
methods
中加入以下方法:
applyTheme() {
this.removeStyle()
this.addStyle()
},
removeStyle() {
const style = document.getElementById(this.linkId)
if (style) {
style.remove()
}
},
addStyle() {
const link = document.createElement('link')
link.href = `你的静态资源目录/${this.theme}.css`
link.setAttribute('rel', 'stylesheet')
link.setAttribute('media', 'all')
link.setAttribute('type', 'text/css')
link.id = this.linkId
const head = document.getElementsByTagName('head')[0]
head.appendChild(link)
}
监听到theme
变化之后调用applyTheme
方法。
主题开发
主题采用less
进行开发,当然你使用sass
或者stylus
都可以,但是不会直接使用css
,这样效率会高一些。
开发构建脚本
理论上应该编写一个webpack
插件来进行这项工作,但是由于我们的主题源码并未在项目中通过import
或者require
引入,所以修改主题不会触发重新编译。我没有在webpack
上找到有效的解决办法,如果有,麻烦分享给我。
新建build.js
放入主题源码目录下,脚本代码:
var fs = require('fs')
const _ = require('lodash')
const less = require('less')
var pathName = '主题源码目录'
var writePath = '编译后的主题css资源目录'
fs.readdir(pathName, async function(err, files) {
if (err) {
console.log(err)
return
}
_.remove(files, function(o) {
return o === 'build.js'
})
console.log(files)
const csses = []
for (var name of files) {
var filePath = pathName + '/' + name
var data = fs.readFileSync(filePath, 'utf-8')
try {
const r = await less.render(data, {})
csses.push({
name: name.split('.')[0],
css: r.css
})
} catch (e) {
console.log(e)
}
}
for (var css of csses) {
write(css)
}
console.log('写入CSS成功!')
})
function write(css) {
const f = fs.writeFileSync(writePath + '/' + css.name + '.css', css.css)
console.log(f)
}
在package-json
的scripts
中加入一行"build:theme":"node 主题源码路径/build.js"
。接着运行npm run build:theme
,就可以将源码编译为css
。
自动构建
直到上一步,主题功能就算是完成了,但是有一个问题,每次修改主题后需要主动运行npm run build:theme
将主题编译成css
,开发效率很受影响。所以考虑写一个监听文件改变的脚本和vue-cli
结合起来。最先想到的是gulp
,gulp
可以方便地监听单个文件的改变,但是不是很想为这个功能引入gulp
,于是使用fs.watch
自己写,在vue.config.js
顶部合适位置加入以下代码:
var fs = require('fs')
function resolve(dir) {
return path.join(__dirname, dir)
}
const { exec } = require('child_process')
// 监听主题文件的修改
fs.watch(resolve('主题源码目录'),(event,trigger)=>{
// 修改后重新执行构建主题
exec('npm run build:theme', (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`)
return
}
})
})
接着重新把项目跑起来,修改主题文件,可以看到浏览器会重新加载页面,已经应用的主题会相应地被修改。