@huantv/vue
Version:
Hippy Vue for TV
250 lines (212 loc) • 7.16 kB
JavaScript
/* eslint-disable import/no-unresolved */
/* eslint-disable no-underscore-dangle */
/* eslint-disable no-param-reassign */
import Vue from 'core/index';
import { defineComputed, proxy } from 'core/instance/state';
import { ASSET_TYPES } from 'shared/constants';
import { mountComponent } from 'core/instance/lifecycle';
import { compileToFunctions } from 'web/compiler/index';
import {
warn,
isPlainObject,
mergeOptions,
extend,
} from 'core/util/index';
import { patch } from './patch';
import {
registerBuiltinElements,
registerElement,
getElementMap,
mustUseProp,
isReservedTag,
isUnknownElement,
} from '../elements';
import {
getApp,
setApp,
isFunction,
trace,
setBeforeLoadStyle,
} from '../util';
import DocumentNode from '../renderer/document-node';
import { Event } from '../renderer/native/event';
import Native, { HippyRegister } from './native';
import * as iPhone from './iphone';
import * as platformDirectives from './directives';
const componentName = ['%c[Hippy-Vue process.env.HIPPY_VUE_VERSION]%c', 'color: #4fc08d; font-weight: bold', 'color: auto; font-weight: auto'];
// Install document
const documentNode = new DocumentNode();
Vue.$document = documentNode;
Vue.prototype.$document = documentNode;
// Install document and event classes
Vue.$Document = DocumentNode;
Vue.$Event = Event;
// Install platform specific utils
Vue.config.mustUseProp = mustUseProp;
Vue.config.isReservedTag = isReservedTag;
Vue.config.isUnknownElement = isUnknownElement;
Vue.compile = compileToFunctions;
Vue.registerElement = registerElement;
// Install platform runtime directives & components
extend(Vue.options.directives, platformDirectives);
// install platform patch function
Vue.prototype.__patch__ = patch;
// Override $mount for attend the compiler.
Vue.prototype.$mount = function $mount(el, hydrating) {
const options = this.$options;
// resolve template/el and convert to render function
if (!options.render) {
const { template } = options;
if (template && typeof template !== 'string') {
warn(`invalid template option: ${template}`, this);
return this;
}
if (template) {
const { render, staticRenderFns } = compileToFunctions(
template,
{
delimiters: options.delimiters,
comments: options.comments,
},
this,
);
options.render = render;
options.staticRenderFns = staticRenderFns;
}
}
return mountComponent(this, el, hydrating);
};
/**
* Register the Hippy-Vue app to Native.
*
* @param {function} callback - Callback after register completed.
*/
Vue.prototype.$start = function $start(afterCallback, beforeCallback) {
setApp(this);
// beforeLoadStyle is a hidden option for pre-process
// the style declaration globally.
if (isFunction(this.$options.beforeLoadStyle)) {
setBeforeLoadStyle(this.$options.beforeLoadStyle);
}
// register native components into Vue.
getElementMap().forEach((entry) => {
Vue.component(entry.meta.component.name, entry.meta.component);
});
// Register the entry point into Hippy
// The callback will be exectue when Native trigger loadInstance
// or runApplication event.
HippyRegister.regist(this.$options.appName, (superProps) => {
const { __instanceId__: rootViewId } = superProps;
this.$options.$superProps = superProps;
this.$options.rootViewId = rootViewId;
trace(...componentName, 'Start', this.$options.appName, 'with rootViewId', rootViewId, superProps);
// Destroy the old instance and set the new one when restart the app
if (this.$el) {
this.$destroy();
const AppConstructor = Vue.extend(this.$options);
const newApp = new AppConstructor(this.$options);
setApp(newApp);
}
// Call the callback before $mount
if (isFunction(beforeCallback)) {
beforeCallback(this, superProps);
}
// Draw the app.
this.$mount();
// Draw the iPhone status bar background.
// It should execute after $mount, otherwise this.$el will be undefined.
if (Native.Platform === 'ios') {
const statusBar = iPhone.drawStatusBar(this.$options);
if (statusBar) {
if (!this.$el.childNodes.length) {
this.$el.appendChild(statusBar);
} else {
this.$el.insertBefore(statusBar, this.$el.childNodes[0]);
}
}
}
// Call the callback after $mount
if (isFunction(afterCallback)) {
afterCallback(this, superProps);
}
});
};
// Override component and extend of avoid built-in component warning.
let cid = 1;
function initProps(Comp) {
const { props } = Comp.options;
Object.keys(props).forEach(key => proxy(Comp.prototype, '_props', key));
}
function initComputed(Comp) {
const { computed } = Comp.options;
Object.keys(computed).forEach(key => defineComputed(Comp.prototype, key, computed[key]));
}
// Override component for avoid built-in component warning.
Vue.component = function component(id, definition) {
if (!definition) {
return this.options.components[id];
}
if (isPlainObject(definition)) {
definition.name = definition.name || id;
definition = this.options._base.extend(definition);
}
this.options.components[id] = definition;
return definition;
};
// Override extend for avoid built-in component warning.
Vue.extend = function hippyExtend(extendOptions) {
extendOptions = extendOptions || {};
const Super = this;
const SuperId = Super.cid;
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {});
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId];
}
const name = extendOptions.name || Super.options.name;
const Sub = function VueComponent(options) {
this._init(options);
};
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
cid += 1;
Sub.cid = cid;
Sub.options = mergeOptions(Super.options, extendOptions);
Sub.super = Super;
// For props and computed properties, we define the proxy getters on
// the Vue instances at extension time, on the extended prototype. This
// avoids Object.defineProperty calls for each instance created.
if (Sub.options.props) {
initProps(Sub);
}
if (Sub.options.computed) {
initComputed(Sub);
}
// allow further extension/mixin/plugin usage
Sub.extend = Super.extend;
Sub.mixin = Super.mixin;
Sub.use = Super.use;
// create asset registers, so extended classes
// can have their private assets too.
ASSET_TYPES.forEach((type) => {
Sub[type] = Super[type];
});
// enable recursive self-lookup
if (name) {
Sub.options.components[name] = Sub;
}
// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub.superOptions = Super.options;
Sub.extendOptions = extendOptions;
Sub.sealedOptions = extend({}, Sub.options);
// cache constructor
cachedCtors[SuperId] = Sub;
return Sub;
};
// Binding Native Properties
Vue.Native = Native;
Vue.getApp = getApp;
// Register the built-in elements
Vue.use(registerBuiltinElements);
export default Vue;