<div id="counter"></div>
<div id="get-toggle"></div>
<div id="set-toggle"></div>
@import url("https://fonts.googleapis.com/css2?family=Montserrat&display=swap");
html {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-family: "Montserrat", sans-serif;
}
.component {
border: 1px solid lightgray;
box-shadow: 5px 5px #ddd;
display: flex;
flex-direction: column;
justify-content: center;
height: 70px;
margin: 20px;
padding: 15px 20px;
position: relative;
width: 200px;
}
.component::before {
content: "Independent Vue Component";
color: gray;
font-size: 0.5em;
position: absolute;
top: 10px;
}
.component::after {
content: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='17' height='20' stroke='gray' stroke-width='1' fill='white'><rect x='5' y='0' width='12' height='20' /><rect x='0' y='4' width='8' height='4'/><rect x='0' y='12' width='8' height='4'/></svg>");
position: absolute;
right: 10px;
top: 10px;
}
localStorage.setItem("toggle", true);
localStorage.setItem("counter", 0);
// A map between localStorage item keys and a list of Vue instances that depend on it
const storeItemSubscribers = {};
// The Vue instance that is currently being initialised
let target = undefined;
const getItem = window.localStorage.getItem;
localStorage.getItem = (key) => {
console.info("Getting", key);
// Collect dependent Vue instance
if (!storeItemSubscribers[key]) storeItemSubscribers[key] = [];
if (target) storeItemSubscribers[key].push(target);
// Call the original function
return getItem.call(localStorage, key);
};
const setItem = window.localStorage.setItem;
localStorage.setItem = (key, value) => {
console.info("Setting", key, value);
// Update the value in the dependent Vue instances
if (storeItemSubscribers[key]) {
storeItemSubscribers[key].forEach((dep) => {
if (dep.hasOwnProperty(key)) dep[key] = value;
});
}
// Call the original function
setItem.call(localStorage, key, value);
};
Vue.mixin({
beforeCreate() {
console.log("beforeCreate", this._uid);
target = this;
},
created() {
console.log("created", this._uid);
target = undefined;
}
});
new Vue({
el: "#counter",
data: () => ({
counter: localStorage.getItem("counter")
}),
computed: {
even() {
return this.counter % 2 == 0;
}
},
template: `<div class="component">
<div>Counter: {{ counter }}</div>
<div>Counter is {{ even ? 'even' : 'odd' }}</div>
</div>`
});
new Vue({
el: "#get-toggle",
data: () => ({
toggle: localStorage.getItem("toggle")
}),
template: `<div class="component">
<div>Toggle: {{ toggle }}</div>
</div>`
});
new Vue({
el: "#set-toggle",
data: () => ({
toggle: localStorage.getItem("toggle")
}),
beforeCreate() {
console.log("Component specific beforeCreate");
},
created() {
console.log("Component specific created");
},
methods: {
click() {
localStorage.setItem("toggle", !!this.toggle ? false : true);
}
},
template: `<div class="component">
<div>
<button @click="click">Toggle</button>
</div>
</div>`
});
const intervalID = setInterval(() => {
const counter = +localStorage.getItem("counter");
localStorage.setItem("counter", counter + 1);
}, 1000);
window.onbeforeunload = function () {
window.clearInterval(intervalID);
};
This Pen doesn't use any external CSS resources.