提交 64f5dddc 编写于 作者: Q qiang

Merge branch 'feat-web-components' into dev

......@@ -2,6 +2,15 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"uni-shared": [
"./src/shared/index.js"
],
"uni-helpers/*": [
"./src/core/helpers/*"
],
"uni-mixins/*": [
"./src/core/view/mixins/*"
],
"uni-core/*": [
"./src/core/*"
],
......
......@@ -4,8 +4,17 @@ const {
const tags = require('@dcloudio/uni-cli-shared/lib/tags')
// web components
const elements = ['uni-view']
// 仅限 view 层
module.exports = function parseTag (el) {
const tag = el.tag
const element = elements.find(element => tag === element || 'uni-' + tag === element)
if (element) {
el.tag = element
return
}
if (el.tag.indexOf('v-uni-') !== 0 && hasOwn(tags, el.tag)) {
el.tag = 'v-uni-' + el.tag
}
......
......@@ -210,7 +210,7 @@ function isComponent (tagName) {
return false
}
}
return !hasOwn(tags, getTagName(tagName.replace('v-uni-', '')))
return !hasOwn(tags, getTagName(tagName.replace(/^(v-)?uni-/, '')))
}
function makeMap (str, expectsLowerCase) {
......
/**
* customElements.define
*/
(function () {
const defineProperty = Object.defineProperty
const createElement = document.createElement
const classes = new Map()
const registry = new Map()
if ('customElements' in window && customElements && customElements.define) {
return
}
function HTMLBuiltIn () {
const constructor = this.constructor
if (!classes.has(constructor)) {
throw new TypeError('Illegal constructor')
}
const is = classes.get(constructor)
const element = createElement.call(document, is)
return Object.setPrototypeOf(element, constructor.prototype)
}
defineProperty(HTMLBuiltIn.prototype = HTMLElement.prototype, 'constructor', {
value: HTMLBuiltIn
})
defineProperty(window, 'HTMLElement', {
configurable: true,
value: HTMLBuiltIn
})
defineProperty(document, 'createElement', {
configurable: true,
value: function value (name, options) {
const is = options && options.is
const Class = is ? registry.get(is) : registry.get(name)
return Class ? new Class() : createElement.call(document, name)
}
})
defineProperty(window, 'customElements', {
configurable: true,
value: {
define: function define (is, Class) {
if (registry.has(is)) {
throw new Error('the name "'.concat(is, '" has already been used with this registry'))
}
classes.set(Class, is)
registry.set(is, Class)
}
}
})
})()
......@@ -63,7 +63,7 @@ export function getTargetDataset (target) {
$parent = $parent.$parent
}
} else {
dataset = target.dataset || {}
dataset = Object.assign({}, target.dataset, target.__uniDataset)
}
return normalizeDataset(dataset)
}
......
......@@ -9,6 +9,19 @@ const requireComponents = [
require.context('../../../platforms/' + __PLATFORM__ + '/view/components', true, /index\.vue$/)
]
let elements = {}
if (__PLATFORM__ === 'app-plus') {
// TODO use full polyfill
require('uni-core/helpers/custom-elements-define')
const module = require('../../../platforms/app-plus/view/elements/index.js')
elements = module.default || module
for (const key in elements) {
// TODO use kebabCase
customElements.define(`uni-${key.toLowerCase()}`, elements[key])
}
}
requireComponents.forEach((components, index) => {
components.keys().forEach(fileName => {
// 获取组件配置
......@@ -18,7 +31,9 @@ requireComponents.forEach((components, index) => {
componentConfig.mixins = componentConfig.mixins ? [].concat(baseMixin, componentConfig.mixins) : [baseMixin]
if (!componentConfig.functional) {
componentConfig.mixins.push(animation)
}
componentConfig.name = 'VUni' + componentConfig.name
......
......@@ -51,7 +51,7 @@ function getStyle (action) {
return style
}
function startAnimation (context) {
export function startAnimation (context) {
const animation = context.animation
if (!animation || !animation.actions || !animation.actions.length) {
return
......
<script>
export default {
name: 'View',
functional: true,
render (createElement, context) {
return createElement('uni-view', context.data, context.children)
}
}
</script>
<style>
uni-view {
display: block;
}
uni-view[hidden] {
display: none;
}
</style>
import UniElement from './element'
import { startAnimation } from 'uni-core/view/mixins/animation'
export default class UniAnimationElement extends UniElement {
setAttribute (key, value) {
if (key === 'animation') {
startAnimation({
$el: this,
animation: value
})
}
super.setAttribute(key, value)
}
}
import {
camelize
} from 'uni-shared'
function formatKey (key) {
return camelize(key.substring(5))
}
export default class UniElement extends HTMLElement {
setAttribute (key, value) {
if (key.startsWith('data-')) {
const dataset = this.__uniDataset || (this.__uniDataset = {})
dataset[formatKey(key)] = value
}
super.setAttribute(key, value)
}
removeAttribute (key) {
if (this.__uniDataset && key.startsWith('data-')) {
delete this.__uniDataset[formatKey(key)]
}
super.removeAttribute(key)
}
}
import UniAnimationElement from './animation'
export default class UniHoverElement extends UniAnimationElement {
setAttribute (key, value) {
console.log('setAttribute:', key, value)
if (key === 'hover-class') {
this._updateHoverClass(value)
}
super.setAttribute(key, value)
}
removeAttribute (key) {
if (key === 'hover-class') {
this._updateHoverClass()
}
super.removeAttribute(key)
}
get hovering () {
return this._hovering
}
set hovering (hovering) {
this._hovering = hovering
const hoverClass = this.getAttribute('hover-class')
if (hovering) {
this.classList.add(hoverClass)
} else {
this.classList.remove(hoverClass)
}
}
_updateHoverClass (hoverClass) {
hoverClass = hoverClass || 'none'
if (hoverClass === 'none') {
this._removeEventListener()
} else {
this._addEventListener()
}
}
_addEventListener () {
if (!this.__hoverTouchStart) {
this.addEventListener('touchstart', this.__hoverTouchStart = this._hoverTouchStart.bind(this))
this.addEventListener('touchend', this.__hoverTouchEnd = this._hoverTouchEnd.bind(this))
this.addEventListener('touchcancel', this.__hoverTouchCancel = this._hoverTouchCancel.bind(this))
}
}
_removeEventListener () {
if (this.__hoverTouchStart) {
this.removeEventListener('touchstart', this.__hoverTouchStart)
delete this.__hoverTouchStart
this.removeEventListener('touchend', this.__hoverTouchEnd)
delete this.__hoverTouchEnd
this.removeEventListener('touchcancel', this.__hoverTouchCancel)
delete this.__hoverTouchCancel
}
}
_hoverTouchStart (evt) {
if (evt._hoverPropagationStopped) {
return
}
if (this.disabled) {
return
}
if (evt.touches.length > 1) {
return
}
if (this.getAttribute('hover-stop-propagation')) {
evt._hoverPropagationStopped = true
}
this._hoverTouch = true
const hoverStartTimeDefault = 50
const hoverStartTime = Number(this.getAttribute('hover-start-time') || hoverStartTimeDefault)
this._hoverStartTimer = setTimeout(() => {
this.hovering = true
if (!this._hoverTouch) {
// 防止在hoverStartTime时间内触发了 touchend 或 touchcancel
this._hoverReset()
}
}, isNaN(hoverStartTime) ? hoverStartTimeDefault : hoverStartTime)
}
_hoverTouchEnd () {
this._hoverTouch = false
if (this.hovering) {
this._hoverReset()
}
}
_hoverReset () {
requestAnimationFrame(() => {
clearTimeout(this._hoverStayTimer)
const hoverStayTimeDefault = 400
const hoverStayTime = Number(this.getAttribute('hover-stay-time') || hoverStayTimeDefault)
this._hoverStayTimer = setTimeout(() => {
this.hovering = false
}, isNaN(hoverStayTime) ? hoverStayTimeDefault : hoverStayTime)
})
}
_hoverTouchCancel () {
this._hoverTouch = false
this.hovering = false
clearTimeout(this._hoverStartTimer)
}
}
import View from './view'
export default {
View
}
import UniHoverElement from './hover'
export default class UniView extends UniHoverElement {
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册