sparkle
sparkle

Reputation: 7400

Vue.js inside Chrome extension Content script

I am trying to use Vue.js 3 inside a content script of a chrome extension.

Here I create the element on the rendered webpage (eg. google.com):

content-script.js

let element = document.querySelector('h1#title')
element.insertAdjacentHTML('afterend', '<div id="counter">COUNTER: {{counter}}</div>');

Here I create the Vue app:

import { createApp } from 'vue'

const CounterApp = {
    data() {
      return {
        counter: 0
      }
    },
    mounted() {
      setInterval(() => {
        this.counter++
      }, 1000)
    }
}
  
createApp(CounterApp).mount('#counter')
console.log(CounterApp)

but in the webpage it displays COUNTER: {{counter}} without actually filling the content.

In the console:

{template: "↵ Counter: {{ counter }}↵
", __props: Array(0), __emits: null, data: ƒ, mounted: ƒ}

Upvotes: 2

Views: 2288

Answers (1)

Dick Fox
Dick Fox

Reputation: 2994

I can't test this in a chrome app context but I think this should solve your problem of getting the Vue variable to render.

The template needs to be with the Vue code, rather than with the content script code. By the time it is inserted into the DOM it is too late for Vue to interpolate your this.counter value.

content-script.js

In the content script just append the empty #counter div

let element = document.querySelector('h1#title')
element.insertAdjacentHTML('afterend', '<div id="counter"></div>');

Vue app

Then in the app code add a .render() function to interpolate the value into your string (and turn it into a VNode with h())

render () { 
  return h(tag, props, stuffToRender)
}

So if you wanted to render a <p> tag with your interpolated string template COUNTER: {{ this.counter }} in it, try:

import { createApp, h } from 'vue' // <-- don't forget to import h

// If you have local import failure, try import via CDN url, like:
//import { createApp, h  } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'

const CounterApp = {
  data() {
    return {
      counter: 0
    }
  },
  mounted() {
    setInterval(() => {
      this.counter++
    }, 1000)
  },
  render() {
    return h('p', {}, `COUNTER: ${this.counter}`)
  }
}
  
createApp(CounterApp).mount('#counter')

More information on the render() function: vuejs.org

Upvotes: 3

Related Questions