[ scss | webpack ] 实现页面主题思路(2)

5 篇文章 0 订阅
5 篇文章 0 订阅

本文介绍了另一种实现主题功能的思路,是前一篇([ scss | webpack ] 实现页面主题思路)的扩展。

Demo源代码

此方法通过切换style的外部样式表链接实现。

效果图

 

Demo项目结构

|____src
| |____styles           # 页面样式
| | |____core.scss      
| |____themes           # 主题变量
| | |____default.scss
| | |____dark.scss
| | |____blue.scss
| |____entry.js         # 打包入口
|____remove-theme-js-plugin.js
|____webpack.config.js
|____package.json

 页面样式与主题变量

/* src/styles/core.scss */
body {
  background-color: $primary;
}
.text {
  color: $text-color;
  border: 2px solid $border-color;
}
 
 
/* src/themes/default.scss */
$primary: #17a2b8 !default;
$text-color: #212529 !default;
$border-color: #6c757d !default;
 
 
/* src/themes/blue.scss */
$primary: #007bff;
 
 
/* src/themes/default.scss */
$primary: #343a40;
$text-color: #f8f9fa;
$border-color: #e9ecef;

入口文件

const styleLink = document.createElement('link')
styleLink.rel = 'stylesheet'
styleLink.href = 'theme/default.css'
document.body.appendChild(styleLink)

const span = document.createElement('span')
span.classList.add('text')
span.innerHTML = '文字'
document.body.appendChild(span)

const themeNames = ['', 'blue', 'dark']
const themeSwitchDiv = document.createElement('div')
themeNames.forEach(name => {
  name = name || 'default'
  const btn = document.createElement('button')
  btn.innerHTML = name
  btn.addEventListener('click', () => {
    styleLink.href = `theme/${name}.css`
  })
  themeSwitchDiv.appendChild(btn)
})
document.body.appendChild(themeSwitchDiv)

remove-theme-js-plugin.js

// 移除把scss当做入口而产生的js文件
class RemoveThemeJsPlugin {
  apply(compiler) {
    compiler.hooks.emit.tap('RemoveThemeJsPlugin', compilation => {
      Object.keys(compilation.assets)
        .filter(file => /^theme\/.+\.js/.test(file))
        .forEach(file => {
          console.log(file)
          delete compilation.assets[file]
        })
    })
  }
}

module.exports = RemoveThemeJsPlugin

webpack打包配置

const RemoveThemeJsPlugin = require('./remove-theme-js-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const fs = require('fs')
const path = require('path')
const themePath = path.resolve(__dirname, 'src/themes')
const styleCorePath = path.join('src', 'styles', 'core.scss')

const getFilename = filepath => path.parse(filepath).name

// 获取主题入口
const getThemeEntry = () => {
  const files = fs.readdirSync(themePath)
  entries = {}
  files.forEach(name => {
    const filename = getFilename(name)
    entries['theme/' + filename] = path.join(themePath, name)
  })
  return entries
}
const themeEntry = getThemeEntry()

module.exports = {
  mode: 'production',
  entry: { main: path.resolve(__dirname, 'src/entry.js'), ...themeEntry },
  output: { path: path.resolve(__dirname, 'dist') },
  plugins: [
    // 打包时清理输出文件夹
    new CleanWebpackPlugin(),
    // 样式提取到 .css 文件中
    new MiniCssExtractPlugin(),
    // 创建 HTML 文件,使用excludeChunks排除入口
    new HtmlWebpackPlugin({
      title: '主题风格',
      excludeChunks: Object.keys(themeEntry)
    }),
    new RemoveThemeJsPlugin()
  ],
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          { loader: MiniCssExtractPlugin.loader },
          'css-loader',
          {
            loader: 'sass-loader',
            options: {
              additionalData: (content, loaderContext) => {
                const { resourcePath, rootContext } = loaderContext
                const relativePath = path.relative(rootContext, resourcePath)
                if (relativePath.includes(path.join('src', 'themes'))) {
                  // 在尾部引入样式
                  content += '@import "../styles/core.scss";'
                }
                return content
              }
            }
          }
        ]
      }
    ]
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值