diff --git a/src/utils/createVueInstance.js b/src/utils/createVueInstance.js index c6ae63f..08d17f1 100644 --- a/src/utils/createVueInstance.js +++ b/src/utils/createVueInstance.js @@ -1,4 +1,4 @@ -import { getPropsData, reactiveProps } from './props'; +import { getPropsData, reactiveProps, syncProps } from './props'; import { getSlots } from './slots'; import { customEmit } from './customEvent'; @@ -103,6 +103,7 @@ export default function createVueInstance(element, Vue, componentDefinition, pro } reactiveProps(element, props); + syncProps(element, props, options); if (typeof options.beforeCreateVueInstance === 'function') { rootElement = options.beforeCreateVueInstance(rootElement) || rootElement; diff --git a/src/utils/props.js b/src/utils/props.js index 1fc9f82..935094c 100644 --- a/src/utils/props.js +++ b/src/utils/props.js @@ -107,6 +107,35 @@ export function reactiveProps(element, props) { }); } +/** + * When attribute changes we should update Vue instance + * @param element + * @param props + * @param options + */ +export function syncProps(element, props, options) { + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + const attributeName = mutation.attributeName; + const propIndex = props.hyphenate.indexOf(attributeName); + if (mutation.type === "attributes" && propIndex !== -1) { + const oldValue = mutation.oldValue; + const value = element.hasAttribute(attributeName) ? element.getAttribute(attributeName) : undefined; + if (element.__vue_custom_element__ && typeof value !== 'undefined') { + const propNameCamelCase = props.camelCase[propIndex]; + typeof options.attributeChangedCallback === 'function' && options.attributeChangedCallback.call(element, propNameCamelCase, oldValue, value); + const type = props.types[propNameCamelCase]; + element.__vue_custom_element__[propNameCamelCase] = convertAttributeValue(value, type); + } + } + }); + }); + observer.observe(element, { + attributes: true, + attributeOldValue: true + }) +} + /** * In root Vue instance we should initialize props as 'propsData'. * @param instanceOptions diff --git a/src/vue-custom-element.js b/src/vue-custom-element.js index 032fab4..224895a 100644 --- a/src/vue-custom-element.js +++ b/src/vue-custom-element.js @@ -1,7 +1,6 @@ import registerCustomElement from './utils/registerCustomElement'; import createVueInstance from './utils/createVueInstance'; -import { getProps, convertAttributeValue } from './utils/props'; -import { camelize } from './utils/helpers'; +import { getProps } from './utils/props'; function install(Vue) { Vue.customElement = function vueCustomElement(tag, componentDefinition, options = {}) { @@ -60,23 +59,6 @@ function install(Vue) { }, options.destroyTimeout || 3000); }, - /** - * When attribute changes we should update Vue instance - * @param name - * @param oldVal - * @param value - */ - attributeChangedCallback(name, oldValue, value) { - if (this.__vue_custom_element__ && typeof value !== 'undefined') { - const nameCamelCase = camelize(name); - typeof options.attributeChangedCallback === 'function' && options.attributeChangedCallback.call(this, name, oldValue, value); - const type = this.__vue_custom_element_props__.types[nameCamelCase]; - this.__vue_custom_element__[nameCamelCase] = convertAttributeValue(value, type); - } - }, - - observedAttributes: props.hyphenate, - shadow: !!options.shadow && !!HTMLElement.prototype.attachShadow });