Open zhaomenghuan opened 6 years ago
Playing around with this awesome wrapper, I'm finding it impossible to attach any style to my registered vue converted webcomponent.
<style module>
makes no difference to adding ANY style.How can I define ANY style on my shadow DOM (from FILE 2) with this wrapper?
File 1:
<template>
<div>
<!-- test row-template outside of zing-grid tag -->
<row-template branch="hello world" username="nardecky" commitId="023741as" runTime="0:27"></row-template>
</div>
</template>
<script>
import RowTemplate from '@/components/row-template'
import wrap from '@vue/web-component-wrapper'
import Vue from 'vue'
// define custom row template immediately as a web component
const CustomElement = wrap(Vue, RowTemplate);
window.customElements.define('row-template', CustomElement);
// define templateing component
export default {
data () {
return {
}
},
}
</script>
<!-- style scoped globally or not, doesn't work for second example -->
<style>
/* works */
row-template {
display: flex;
justify-content: space-between;
background: #eee;
margin-bottom: 1rem;
padding: 1rem;
border-radius: .5rem;
overflow: hidden;
}
/* Doesn't work*/
row-template >>> .customSingleRow{
display: flex;
justify-content: space-between;
background: #eee;
margin-bottom: 1rem;
padding: 1rem;
border-radius: .5rem;
overflow: hidden;
}
</style>
File 2:
<template>
<section class="customSingleRow">
<div class="firstCell">
<div class="buildStatus"></div>
<div>
<h3>{{ branch }}</h3>
<div class="build-contents">
<span>{{ username }}</span>
<span>{{ branch }}</span>
<span>{{ commitId }}</span>
<span>{{ runTime }}</span>
</div>
</div>
</div>
<div>
<select>
<option>Restart Build</option>
<option>Reset Cache</option>
<option>Drill Into Page</option>
</select>
</div>
</section>
</template>
<script>
export default {
name: 'row-template',
props: ['branch', 'username', 'commitId', 'runTime'],
data () {
return {
}
},
mounted: function() {
console.log(this.$style)
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
/* trying to get any selector to work for this component */
:host >>> .customSingleRow,
:host-context(section),
:host,
row-template,
.customSingleRow {
display: flex;
justify-content: space-between;
background: #eee;
margin-bottom: 1rem;
padding: 1rem;
border-radius: .5rem;
overflow: hidden;
}
/* ideally I want to just target .customSingleRow*/
</style>
I found a really hacky solution.
Reasoning: The reasoning for this solution is styles are handled by webpack. They are not accessible on the Vue element itself, thus it can't be solved with this wrapper correct?
Implementation
Create a custom component to render/import style tags since the compiler won't let us
File 1:
<template>
<section>
<custom-styles>
.custom-single-row {
display: flex;
justify-content: space-between;
background: #eee;
margin-bottom: 1rem;
padding: 1rem;
border-radius: .5rem;
overflow: hidden;
}
</custom-styles>
<div class="custom-single-row">
<div class="first-cell">
<div v-bind:class="buildStatus"></div>
<div>
<h3>{{ branch }}</h3>
<div class="build-contents">
<span>{{ username }}</span>
<span>{{ branch }}</span>
<span>{{ commitId }}</span>
<span>{{ runTime }}</span>
</div>
</div>
</div>
<div>
<select>
<option>Restart Build</option>
<option>Reset Cache</option>
<option>Drill Into Page</option>
</select>
</div>
</div>
</section>
</template>
<script>
import CustomStyles from '@/components/styles'
export default {
name: 'row-template',
props: ['status', 'branch', 'username', 'commitId', 'runTime'],
data () {
return {
}
},
mounted: function() {
console.log(this)
},
computed: {
buildStatus: function() {
return `build-status build-${this.status}`;
}
},
components: {
'custom-styles': CustomStyles
}
}
</script>
File two is our <custom-styles>
element:
<template>
<section ref="styles" style="display:none;">
<slot></slot>
</section>
</template>
<script>
export default {
name: 'custom-styles',
props: [],
data () {
return {
}
},
mounted: function() {
console.log(this.$refs.styles)
let styleTag = document.createElement('style');
styleTag.textContent = this.$refs.styles.textContent;
this.$refs.styles.textContent = null;
this.$refs.styles.appendChild(styleTag);
}
}
</script>
This will import our styles into our webcomponent, making them scoped.
I slightly simplified @gnardecky's custom style component like so:
const customStyle = {
name: 'custom-style',
render (createElement) {
return createElement('style', this.$slots.default)
}
}
I was able to enable shadow mode with webpaack v4 and vue-loader 15 (without vue-cli v3), docs
// webpack.config.js
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
exclude: path.resolve(__dirname, 'node_modules'),
options: {
shadowMode: true // vue-loader v15.0.9+
}
},
{
test: /\.css$/,
use: [
{
loader: 'vue-style-loader',
options: {
shadowMode: true
}
},
'css-loader',
// don't use `style-loader`
],
},
]
]
Now i can use vue SFC as normal
<template>
<div class="card">
<!-- add html here -->
</div>
</template>
<script>
// add script
</script>
<style>
/* no need to use CSS Modules or Scoped CSS */
@import "~bootstrap/dist/css/bootstrap.css";
.card {
background: red
}
</style>
You also need to load import *.vue
files like this, (only vue-loader >v15.0.9)
//app.js
import CustomElement from './CustomElement.vue?shadow'
Now vue-loader injects style
tag within shadowRoot not in document head
.
@ankurk91 i tried the solution you told but still goint to head? can you provide more details please?
@ankurk91 yay, i got it... now wondering how to make it with
@victorhramos hi, can you share some details why it wasn't working for you and now it works? I have the same problem you've had probably - styles are not in shadow but in head.
@maciekkus here one working example https://github.com/victorhramos/vuew-shadowdom
@victorhramos thanks. btw. I've managed somehow to get it working. but it seems that for me shadow styles do not work in safari at all, and in firefox global styles leak to webcomponent. Is it just the current state of that technology and browser support state?
is there any good workaround to use properly scoped scss?
Good initiative this project, I was unfortunately unable to use with bootstrap-vue :( Solution from @victorhramos did not really work on my side. Styles are still in the head.
I wonder like @victorhramos why css dosen’t work in case
I tried to use this plugin to write a UI library, but I found that the styles defined in the component did not take effect, and the template tag in the .vue file could not write style in it, and how to handle it more elegantly.