子应用html引入本地js文件,文件中的全局变量is not defined
原因:子应用中var定义的变量不在是全局变量。
解决:
- 将变量挂在到window上,window.xxx = xxx
- 将js文件放到主应用
子应用项目点击后,再点击其它路由变404,刷新也是404
解决:主子应用的vue-router版本要一致
在子应用页面退出登录,重新登录后页面404
解决:先加载微应用,再生成主应用路由
修改主题颜色问题
原理:element-ui theme-picker组件修改主题色是将所有组件之前的色值全部换成新的,生成一个style文件,追加到head中
问题:若主子应用间开启了样式隔离,会把子应用所有样式前增加前缀div[data-qiankun=“”]
所以在同步修改子应用主题色的时候,要将生成的style文件所有选择器前加上此前缀,同时将style追加到< qiankun-head >中
主应用修改主题色
子应用接收传值
在app.vue中监听theme值变化
子应用theme-picker代码
<template>
<el-color-picker
v-model="theme"
:predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</template>
<script>
const version = require('element-ui/package.json').version // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF' // default color
export default {
data() {
return {
chalk: '', // content of theme-chalk css
theme: ''
}
},
computed: {
defaultTheme() {
return this.$store.state.settings.theme
}
},
watch: {
defaultTheme: {
handler: function(val, oldVal) {
this.theme = val
},
immediate: true
},
async theme(val) {
await this.setTheme(val)
}
},
created() {
if(this.defaultTheme !== ORIGINAL_THEME) {
this.setTheme(this.defaultTheme)
}
},
methods: {
async setTheme(val) {
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
if (typeof val !== 'string') return
const themeCluster = this.getThemeCluster(val.replace('#', ''))
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
const getHandler = (variable, id) => {
return () => {
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
var newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
let styleTag = document.getElementById(id)
if (!styleTag) {
styleTag = document.createElement('style')
styleTag.setAttribute('id', id)
// qiankun环境修改主题色
console.log(window.__POWERED_BY_QIANKUN__)
if(window.__POWERED_BY_QIANKUN__){
document.getElementsByTagName('qiankun-head')[0].appendChild(styleTag)
}else{
document.head.appendChild(styleTag)
}
}
if(window.__POWERED_BY_QIANKUN__){
// 获取qiankun的名字name值
let name = document.querySelectorAll("[id^='__qiankun_microapp_wrapper_for']")[0].dataset.name
newStyle = this.prefixCssSelectors(newStyle,'div[data-qiankun="'+name+'"]')
}
styleTag.innerText = newStyle
}
}
if (!this.chalk) {
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
await this.getCSSString(url, 'chalk')
}
if(window.__POWERED_BY_QIANKUN__){
var chalkHandler = getHandler('chalk', 'chalk-style-qiankun')
}else{
var chalkHandler = getHandler('chalk', 'chalk-style')
}
chalkHandler()
const styles = [].slice.call(document.querySelectorAll('style'))
.filter(style => {
const text = style.innerText
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
})
styles.forEach(style => {
const { innerText } = style
if (typeof innerText !== 'string') return
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
})
this.$emit('change', val)
},
updateStyle(style, oldCluster, newCluster) {
let newStyle = style
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
})
return newStyle
},
getCSSString(url, variable) {
return new Promise(resolve => {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
resolve()
}
}
xhr.open('GET', url)
xhr.send()
})
},
getThemeCluster(theme) {
const tintColor = (color, tint) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
if (tint === 0) { // when primary color is in its rgb space
return [red, green, blue].join(',')
} else {
red += Math.round(tint * (255 - red))
green += Math.round(tint * (255 - green))
blue += Math.round(tint * (255 - blue))
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
}
const shadeColor = (color, shade) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
red = Math.round((1 - shade) * red)
green = Math.round((1 - shade) * green)
blue = Math.round((1 - shade) * blue)
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
const clusters = [theme]
for (let i = 0; i <= 9; i++) {
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
}
clusters.push(shadeColor(theme, 0.1))
return clusters
},
// 给子应用加上样式前缀
prefixCssSelectors(rules, className) {
var classLen = className.length,
char, nextChar, isAt, isIn;
// makes sure the className will not concatenate the selector
className += ' ';
// removes comments
rules = rules.replace( /\/\*(?:(?!\*\/)[\s\S])*\*\/|[\r\n\t]+/g, '' );
// makes sure nextChar will not target a space
rules = rules.replace( /}(\s*)@/g, '}@' );
rules = rules.replace( /}(\s*)}/g, '}}' );
for (var i = 0; i < rules.length-2; i++) {
char = rules[i];
nextChar = rules[i+1];
if (char === '@' && nextChar !== 'f') isAt = true;
if (!isAt && char === '{') isIn = true;
if (isIn && char === '}') isIn = false;
if (
!isIn &&
nextChar !== '@' &&
nextChar !== '}' &&
(
char === '}' ||
char === ',' ||
((char === '{' || char === ';') && isAt)
)
) {
rules = rules.slice(0, i+1) + className + rules.slice(i+1);
i += classLen;
isAt = false;
}
};
// prefix the first select if it is not `@media` and if it is not yet prefixed
if (rules.indexOf(className) !== 0 && rules.indexOf('@') !== 0) rules = className+rules;
return rules;
}
}
}
</script>
<style>
.theme-message,
.theme-picker-dropdown {
z-index: 99999 !important;
}
.theme-picker .el-color-picker__trigger {
height: 26px !important;
width: 26px !important;
padding: 2px;
}
.theme-picker-dropdown .el-color-dropdown__link-btn {
display: none;
}
</style>
主应用刷新主题色恢复问题,app.vue引入theme-picker区间隐藏,刷新会默认执行修改组件颜色事件