The following example gives the error "Uncaught TypeError: Cannot read properties of undefined (reading 'count1')".
File: button.html
<!DOCTYPE html>
<html>
<head>
<title>Button Counter</title>
<script src="/js2/vue-global-min-3.3.4.js"></script>
<script src="button.js"></script>
<script>
const vm = Vue.reactive
(
{
count1: { count: 0 },
count2: { count: 0 },
count3: { count: 0 }
}
);
initButton();
</script>
</head>
<body>
<div id="app">
<button-counter id="b1" :count="vm.count1"></button-counter>
<button-counter id="b2" :count="vm.count2"></button-counter>
<button-counter id="b3" :count="vm.count3"></button-counter>
<div id="r1">{{ vm.count1.count }}</div>
</div>
</body>
</html>
File: button.js
var initButton = function ()
{
const ButtonCounter =
{
props: ['count'],
emits: ['update:count'],
template: `
<button @click="incrementCount">
You clicked me {{ count }} times.
</button>
`,
setup (props)
{
const incrementCount = () =>
{
this.$emit ('update:count', { ...props.count, count: props.count + 1 });
};
return { incrementCount };
},
};
function registerTag ()
{
const app = Vue.createApp ({});
app.component ('button-counter', ButtonCounter);
app.mount ('#app');
}
document.addEventListener('DOMContentLoaded', registerTag);
};
I was expecting to see three buttons and the div text. I got the error mentioned above. I checked the expression "vm.count1.count" and it is a Vue reference with the value 0.
vm
is defined in the global scope, but Vue needs it declared in the corresponding component, which in your case is the root component. A quick fix is to return it from a setup function:
function registerTag ()
{
const app = Vue.createApp ({
setup(){ // <------ add a setup() function which returns vm
return {
vm
}
}
});
app.component ('button-counter', ButtonCounter);
app.mount ('#app');
}
Or move the declaration into the setup block completely, which would get you closer to a typical Vue setup, as you can explore in the Vue 3 sandbox.