diff --git a/src/js/anot-touch.js b/src/js/anot-touch.js index cab09ad..2121f60 100644 --- a/src/js/anot-touch.js +++ b/src/js/anot-touch.js @@ -1745,10 +1745,14 @@ const _Anot = (function() { v.$fire && v.$fire.apply(v, [ee, a]) } // component! 这是一个特殊的标识,可以直接修改子组件的state值 + // 且只针对指定子组件有效 } else if (path.indexOf('component!') === 0) { - var ee = path.slice(10) + var ee = path.slice(10).split('!') for (var i in $vmodel.$children) { - $vmodel.$children[i][ee] = a + if ($vmodel.$children[i].$id === ee[0]) { + $vmodel.$children[i][ee[1]] = a + break + } } } else { $emit.call($vmodel, path, [a]) @@ -1772,7 +1776,14 @@ const _Anot = (function() { if (watches) { delete watches.props for (var key in watches) { - $watch.call($vmodel, key, watches[key]) + if (Array.isArray(watches[key])) { + var tmp + while ((tmp = watches[key].pop())) { + $watch.call($vmodel, key, tmp) + } + } else { + $watch.call($vmodel, key, watches[key]) + } } } @@ -3346,7 +3357,8 @@ const _Anot = (function() { var rnoCollect = /^(:\S+|data-\S+|on[a-z]+|id|style|class)$/ var ronattr = '__fn__' - var specifiedVars = [':disabled', ':loading'] + var specifiedVars = [':disabled', ':loading', ':value'] + var filterTypes = ['html', 'text', 'attr', 'data'] function getOptionsFromTag(elem, vmodels) { var attributes = aslice.call(elem.attributes, 0) var ret = {} @@ -3420,7 +3432,7 @@ const _Anot = (function() { (directives[type].priority || type.charCodeAt(0) * 10) + (Number(param.replace(/\D/g, '')) || 0) } - if (type === 'html' || type === 'text' || type === 'attr') { + if (filterTypes.includes(type)) { var filters = getToken(value).filters binding.expr = binding.expr.replace(filters, '') binding.filters = filters @@ -3784,6 +3796,7 @@ const _Anot = (function() { //如果还没有解析完,就延迟一下 #1155 return } + hooks.watch = hooks.watch || {} var parentVm = host.vmodels[0] var state = {} var props = getOptionsFromTag(elem, host.vmodels) @@ -3800,19 +3813,34 @@ const _Anot = (function() { var disabledKey = props[':disabled'] state.disabled = parentVm[disabledKey] parentVm.$watch(disabledKey, function(val) { - parentVm.$fire('component!disabled', val) + parentVm.$fire('component!' + $id + '!disabled', val) }) + delete props[':disabled'] } if (props.hasOwnProperty(':loading')) { var loadingKey = props[':loading'] state.loading = parentVm[loadingKey] parentVm.$watch(loadingKey, function(val) { - parentVm.$fire('component!loading', val) + parentVm.$fire('component!' + $id + '!loading', val) }) delete props[':loading'] } + // :value可实现双向同步值 + if (props.hasOwnProperty(':value')) { + var valueKey = props[':value'] + state.value = parentVm[valueKey] + parentVm.$watch(valueKey, function(val) { + parentVm.$fire('component!' + $id + '!value', val) + }) + hooks.watch.value = hooks.watch.value ? [hooks.watch.value] : [] + hooks.watch.value.push(function(val) { + parentVm[valueKey] = val + }) + delete props[':value'] + } + delete props.uuid delete props.name @@ -4143,11 +4171,6 @@ const _Anot = (function() { } }) - //这几个指令都可以使用插值表达式,如:src="aaa/{{b}}/{{c}}.html" - 'css,include,data'.replace(rword, function(name) { - directives[name] = attrDir - }) - //类名定义, :class="xx:yy" :class="{xx: yy}" :class="xx" :class="{{xx}}" Anot.directive('class', { init: function(binding) { @@ -4262,6 +4285,7 @@ const _Anot = (function() { //兼容2种写法 :data-xx="yy", :data="{xx: yy}" Anot.directive('data', { priority: 100, + init: directives.attr.init, update: function(val) { var obj = val if (typeof obj === 'object' && obj !== null) { diff --git a/src/js/anot-touch.shim.js b/src/js/anot-touch.shim.js index 074d11e..398ea32 100644 --- a/src/js/anot-touch.shim.js +++ b/src/js/anot-touch.shim.js @@ -1760,10 +1760,14 @@ v.$fire && v.$fire.apply(v, [ee, a]) } // component! 这是一个特殊的标识,可以直接修改子组件的state值 + // 且只针对指定子组件有效 } else if (path.indexOf('component!') === 0) { - var ee = path.slice(10) + var ee = path.slice(10).split('!') for (var i in $vmodel.$children) { - $vmodel.$children[i][ee] = a + if ($vmodel.$children[i].$id === ee[0]) { + $vmodel.$children[i][ee[1]] = a + break + } } } else { $emit.call($vmodel, path, [a]) @@ -1787,7 +1791,14 @@ if (watches) { delete watches.props for (var key in watches) { - $watch.call($vmodel, key, watches[key]) + if (Array.isArray(watches[key])) { + var tmp + while ((tmp = watches[key].pop())) { + $watch.call($vmodel, key, tmp) + } + } else { + $watch.call($vmodel, key, watches[key]) + } } } @@ -3361,7 +3372,8 @@ var rnoCollect = /^(:\S+|data-\S+|on[a-z]+|id|style|class)$/ var ronattr = '__fn__' - var specifiedVars = [':disabled', ':loading'] + var specifiedVars = [':disabled', ':loading', ':value'] + var filterTypes = ['html', 'text', 'attr', 'data'] function getOptionsFromTag(elem, vmodels) { var attributes = aslice.call(elem.attributes, 0) var ret = {} @@ -3435,7 +3447,7 @@ (directives[type].priority || type.charCodeAt(0) * 10) + (Number(param.replace(/\D/g, '')) || 0) } - if (type === 'html' || type === 'text' || type === 'attr') { + if (filterTypes.includes(type)) { var filters = getToken(value).filters binding.expr = binding.expr.replace(filters, '') binding.filters = filters @@ -3799,6 +3811,7 @@ //如果还没有解析完,就延迟一下 #1155 return } + hooks.watch = hooks.watch || {} var parentVm = host.vmodels[0] var state = {} var props = getOptionsFromTag(elem, host.vmodels) @@ -3815,19 +3828,34 @@ var disabledKey = props[':disabled'] state.disabled = parentVm[disabledKey] parentVm.$watch(disabledKey, function(val) { - parentVm.$fire('component!disabled', val) + parentVm.$fire('component!' + $id + '!disabled', val) }) + delete props[':disabled'] } if (props.hasOwnProperty(':loading')) { var loadingKey = props[':loading'] state.loading = parentVm[loadingKey] parentVm.$watch(loadingKey, function(val) { - parentVm.$fire('component!loading', val) + parentVm.$fire('component!' + $id + '!loading', val) }) delete props[':loading'] } + // :value可实现双向同步值 + if (props.hasOwnProperty(':value')) { + var valueKey = props[':value'] + state.value = parentVm[valueKey] + parentVm.$watch(valueKey, function(val) { + parentVm.$fire('component!' + $id + '!value', val) + }) + hooks.watch.value = hooks.watch.value ? [hooks.watch.value] : [] + hooks.watch.value.push(function(val) { + parentVm[valueKey] = val + }) + delete props[':value'] + } + delete props.uuid delete props.name @@ -4158,11 +4186,6 @@ } }) - //这几个指令都可以使用插值表达式,如:src="aaa/{{b}}/{{c}}.html" - 'css,include,data'.replace(rword, function(name) { - directives[name] = attrDir - }) - //类名定义, :class="xx:yy" :class="{xx: yy}" :class="xx" :class="{{xx}}" Anot.directive('class', { init: function(binding) { @@ -4277,6 +4300,7 @@ //兼容2种写法 :data-xx="yy", :data="{xx: yy}" Anot.directive('data', { priority: 100, + init: directives.attr.init, update: function(val) { var obj = val if (typeof obj === 'object' && obj !== null) { diff --git a/src/js/anot.js b/src/js/anot.js index aaec705..f5bbf38 100644 --- a/src/js/anot.js +++ b/src/js/anot.js @@ -1745,10 +1745,14 @@ const _Anot = (function() { v.$fire && v.$fire.apply(v, [ee, a]) } // component! 这是一个特殊的标识,可以直接修改子组件的state值 + // 且只针对指定子组件有效 } else if (path.indexOf('component!') === 0) { - var ee = path.slice(10) + var ee = path.slice(10).split('!') for (var i in $vmodel.$children) { - $vmodel.$children[i][ee] = a + if ($vmodel.$children[i].$id === ee[0]) { + $vmodel.$children[i][ee[1]] = a + break + } } } else { $emit.call($vmodel, path, [a]) @@ -1772,7 +1776,14 @@ const _Anot = (function() { if (watches) { delete watches.props for (var key in watches) { - $watch.call($vmodel, key, watches[key]) + if (Array.isArray(watches[key])) { + var tmp + while ((tmp = watches[key].pop())) { + $watch.call($vmodel, key, tmp) + } + } else { + $watch.call($vmodel, key, watches[key]) + } } } @@ -3346,7 +3357,8 @@ const _Anot = (function() { var rnoCollect = /^(:\S+|data-\S+|on[a-z]+|id|style|class)$/ var ronattr = '__fn__' - var specifiedVars = [':disabled', ':loading'] + var specifiedVars = [':disabled', ':loading', ':value'] + var filterTypes = ['html', 'text', 'attr', 'data'] function getOptionsFromTag(elem, vmodels) { var attributes = aslice.call(elem.attributes, 0) var ret = {} @@ -3420,7 +3432,7 @@ const _Anot = (function() { (directives[type].priority || type.charCodeAt(0) * 10) + (Number(param.replace(/\D/g, '')) || 0) } - if (type === 'html' || type === 'text' || type === 'attr') { + if (filterTypes.includes(type)) { var filters = getToken(value).filters binding.expr = binding.expr.replace(filters, '') binding.filters = filters @@ -3784,6 +3796,7 @@ const _Anot = (function() { //如果还没有解析完,就延迟一下 #1155 return } + hooks.watch = hooks.watch || {} var parentVm = host.vmodels[0] var state = {} var props = getOptionsFromTag(elem, host.vmodels) @@ -3800,19 +3813,34 @@ const _Anot = (function() { var disabledKey = props[':disabled'] state.disabled = parentVm[disabledKey] parentVm.$watch(disabledKey, function(val) { - parentVm.$fire('component!disabled', val) + parentVm.$fire('component!' + $id + '!disabled', val) }) + delete props[':disabled'] } if (props.hasOwnProperty(':loading')) { var loadingKey = props[':loading'] state.loading = parentVm[loadingKey] parentVm.$watch(loadingKey, function(val) { - parentVm.$fire('component!loading', val) + parentVm.$fire('component!' + $id + '!loading', val) }) delete props[':loading'] } + // :value可实现双向同步值 + if (props.hasOwnProperty(':value')) { + var valueKey = props[':value'] + state.value = parentVm[valueKey] + parentVm.$watch(valueKey, function(val) { + parentVm.$fire('component!' + $id + '!value', val) + }) + hooks.watch.value = hooks.watch.value ? [hooks.watch.value] : [] + hooks.watch.value.push(function(val) { + parentVm[valueKey] = val + }) + delete props[':value'] + } + delete props.uuid delete props.name @@ -4143,11 +4171,6 @@ const _Anot = (function() { } }) - //这几个指令都可以使用插值表达式,如:src="aaa/{{b}}/{{c}}.html" - 'css,include,data'.replace(rword, function(name) { - directives[name] = attrDir - }) - //类名定义, :class="xx:yy" :class="{xx: yy}" :class="xx" :class="{{xx}}" Anot.directive('class', { init: function(binding) { @@ -4262,6 +4285,7 @@ const _Anot = (function() { //兼容2种写法 :data-xx="yy", :data="{xx: yy}" Anot.directive('data', { priority: 100, + init: directives.attr.init, update: function(val) { var obj = val if (typeof obj === 'object' && obj !== null) { diff --git a/src/js/anot.shim.js b/src/js/anot.shim.js index 37030ed..bb9c582 100644 --- a/src/js/anot.shim.js +++ b/src/js/anot.shim.js @@ -1760,10 +1760,14 @@ v.$fire && v.$fire.apply(v, [ee, a]) } // component! 这是一个特殊的标识,可以直接修改子组件的state值 + // 且只针对指定子组件有效 } else if (path.indexOf('component!') === 0) { - var ee = path.slice(10) + var ee = path.slice(10).split('!') for (var i in $vmodel.$children) { - $vmodel.$children[i][ee] = a + if ($vmodel.$children[i].$id === ee[0]) { + $vmodel.$children[i][ee[1]] = a + break + } } } else { $emit.call($vmodel, path, [a]) @@ -1787,7 +1791,14 @@ if (watches) { delete watches.props for (var key in watches) { - $watch.call($vmodel, key, watches[key]) + if (Array.isArray(watches[key])) { + var tmp + while ((tmp = watches[key].pop())) { + $watch.call($vmodel, key, tmp) + } + } else { + $watch.call($vmodel, key, watches[key]) + } } } @@ -3361,7 +3372,8 @@ var rnoCollect = /^(:\S+|data-\S+|on[a-z]+|id|style|class)$/ var ronattr = '__fn__' - var specifiedVars = [':disabled', ':loading'] + var specifiedVars = [':disabled', ':loading', ':value'] + var filterTypes = ['html', 'text', 'attr', 'data'] function getOptionsFromTag(elem, vmodels) { var attributes = aslice.call(elem.attributes, 0) var ret = {} @@ -3435,7 +3447,7 @@ (directives[type].priority || type.charCodeAt(0) * 10) + (Number(param.replace(/\D/g, '')) || 0) } - if (type === 'html' || type === 'text' || type === 'attr') { + if (filterTypes.includes(type)) { var filters = getToken(value).filters binding.expr = binding.expr.replace(filters, '') binding.filters = filters @@ -3799,6 +3811,7 @@ //如果还没有解析完,就延迟一下 #1155 return } + hooks.watch = hooks.watch || {} var parentVm = host.vmodels[0] var state = {} var props = getOptionsFromTag(elem, host.vmodels) @@ -3815,19 +3828,34 @@ var disabledKey = props[':disabled'] state.disabled = parentVm[disabledKey] parentVm.$watch(disabledKey, function(val) { - parentVm.$fire('component!disabled', val) + parentVm.$fire('component!' + $id + '!disabled', val) }) + delete props[':disabled'] } if (props.hasOwnProperty(':loading')) { var loadingKey = props[':loading'] state.loading = parentVm[loadingKey] parentVm.$watch(loadingKey, function(val) { - parentVm.$fire('component!loading', val) + parentVm.$fire('component!' + $id + '!loading', val) }) delete props[':loading'] } + // :value可实现双向同步值 + if (props.hasOwnProperty(':value')) { + var valueKey = props[':value'] + state.value = parentVm[valueKey] + parentVm.$watch(valueKey, function(val) { + parentVm.$fire('component!' + $id + '!value', val) + }) + hooks.watch.value = hooks.watch.value ? [hooks.watch.value] : [] + hooks.watch.value.push(function(val) { + parentVm[valueKey] = val + }) + delete props[':value'] + } + delete props.uuid delete props.name @@ -4158,11 +4186,6 @@ } }) - //这几个指令都可以使用插值表达式,如:src="aaa/{{b}}/{{c}}.html" - 'css,include,data'.replace(rword, function(name) { - directives[name] = attrDir - }) - //类名定义, :class="xx:yy" :class="{xx: yy}" :class="xx" :class="{{xx}}" Anot.directive('class', { init: function(binding) { @@ -4277,6 +4300,7 @@ //兼容2种写法 :data-xx="yy", :data="{xx: yy}" Anot.directive('data', { priority: 100, + init: directives.attr.init, update: function(val) { var obj = val if (typeof obj === 'object' && obj !== null) { diff --git a/src/js/form/index.js b/src/js/form/index.js index 1465262..0ca9382 100644 --- a/src/js/form/index.js +++ b/src/js/form/index.js @@ -8,14 +8,28 @@ import './style.scss' const log = console.log -export default Anot.component('button', { +Anot.ui.form = '0.1.0' +// 按钮 +Anot.component('button', { construct(props, state) { - log(props) state.text = this.textContent state.style = { 'border-radius': props.radius } this.classList.add('do-fn-noselect') this.classList.add('do-button') this.setAttribute(':click', 'onClick') + this.setAttribute(':class', '{disabled: disabled}') + this.setAttribute(':css', 'style') + + this.classList.add(props.color || 'grey') + if (props.size) { + this.classList.add(props.size) + } + if (props.hasOwnProperty('disabled')) { + state.disabled = true + } + delete props.disabled + delete props.color + delete props.size }, render() { let icon = '' @@ -25,26 +39,113 @@ export default Anot.component('button', { return `${icon}` }, state: { - state: '', + text: '', disabled: false, - foo: true, style: {} }, props: { click: Anot.PropsTypes.isFunction() }, skip: ['style'], - componentDidMount() { - Anot(this.$elem).css(this.style) - }, + watch: {}, methods: { onClick() { - // log(this) if (this.disabled) { return } - log('hello world, button') + if (typeof this.props.click === 'function') { + this.props.click() + } } } }) + +// 单选按钮 +Anot.component('radio', { + construct(props, state) { + state.text = this.textContent + state.checked = state.value === props.label + if (props.hasOwnProperty('disabled')) { + state.disabled = true + } + this.classList.add('do-radio') + this.classList.add('do-fn-noselect') + + if (!state.disabled) { + this.classList.add(props.color || 'grey') + } + this.setAttribute(':class', '{disabled: disabled, checked: checked}') + this.setAttribute(':click', 'onClick') + + delete props.disabled + delete props.color + }, + render() { + return ` + + + ` + }, + state: { + value: null, + text: '', + checked: false, + disabled: false + }, + watch: { + value(val) { + this.checked = this.props.label === val + } + }, + methods: { + onClick() { + if (this.disabled) { + return + } + if (!this.checked) { + this.checked = true + this.value = this.props.label + } + } + } +}) + +// 开关 +Anot.component('switch', { + construct(props, state) { + if (props.hasOwnProperty('disabled')) { + state.disabled = true + } + + this.classList.add('do-switch') + this.classList.add('do-fn-noselect') + if (!state.disabled) { + this.classList.add(props.color || 'grey') + } + this.setAttribute(':class', '{disabled: disabled, checked: value}') + this.setAttribute(':click', 'onClick') + + delete props.disabled + delete props.color + }, + render() { + return ` + + ` + }, + state: { + value: false, + disabled: false + }, + methods: { + onClick() { + if (this.disabled) { + return + } + this.value = !this.value + } + } +}) + +export default Anot diff --git a/src/js/form/style.scss b/src/js/form/style.scss index ab392d7..fb6bdbb 100644 --- a/src/js/form/style.scss +++ b/src/js/form/style.scss @@ -9,14 +9,156 @@ @import "var.scss"; -.do-button {overflow:hidden;position:relative;display:inline-block;width:auto;min-width:60px;height:30px;margin-left:5px;padding:0 10px;color:nth($ct, 1);text-align:center;cursor:pointer; +.do-button {overflow:hidden;position:relative;display:inline-block;width:auto;height:30px;padding:0 10px;line-height:30px;text-align:center;cursor:pointer;font-size:14px; &::before {position:absolute;left:-50%;top:-50%;display:block;width:200%;height:200%;border-radius:50%;background:nth($cp, 2); content:"";opacity:0;transform: scale(0, .0); transition:opacity 1.3s cubic-bezier(0.23, 1, 0.32, 1),transform 1.3s cubic-bezier(0.23, 1, 0.32, 1);} &:hover { &::before {opacity:1;transform:scale(1, .8);} } - &:active {background:nth($cp, 1)} + &:active { + &::before {background:rgba(0,0,0,.1);} + } &__text,&__icon {position:relative;display:inline-block;} + &__icon {font-size:20px;vertical-align:top;} + + &.small {height:20px;padding:0 5px;line-height:20px;font-size:12px; + + i {font-size:16px;} + } + &.medium {min-width:100px;height:35px;line-height:35px;font-size:16px; + + i {padding-right:5px;font-size:24px;} + } + &.large {min-width:150px;height:50px;padding:0 13px;line-height:50px;font-size:18px; + + i {padding-right:10px;font-size:28px;} + } + + + &.teal {color:nth($ct, 1);} + &.green {color:nth($cg, 1);} + &.blue {color:nth($cb, 1);} + &.purple {color:nth($cpp, 1);} + &.red {color:nth($cr, 1);} + &.orange {color:nth($co, 1);} + &.plain {color:nth($cp, 3);} + &.grey {color:nth($cgr, 1);} + + &.disabled {color:nth($cp, 1);cursor:not-allowed; + + &::before {display:none;} + } +} + + +.do-radio {position:relative;display:inline-block;width:auto;height:30px;padding:0 10px;line-height:30px;text-align:center;cursor:default;font-size:14px; + + &.disabled {cursor:not-allowed;} + + &__box {float:left;width:20px;height:20px;margin:5px;border:1px solid nth($cgr, 1);border-radius:50%; + + } + &.checked &__box::after {display:block;width:14px;height:14px;margin:2px;border-radius:50%;content:""} + + &__text {color:nth($cgr, 1);} + + + &.teal &__box {border-color:nth($ct, 1); + &::after {background:nth($ct, 1);} + } + &.teal &__text {color:nth($ct, 1);} + + &.green &__box {border-color:nth($cg, 1); + &::after {background:nth($cg, 1);} + } + &.green &__text {color:nth($cg, 1);} + + &.blue &__box {border-color:nth($cb, 1); + &::after {background:nth($cb, 1);} + } + &.blue &__text {color:nth($cb, 1);} + + &.purple &__box {border-color:nth($cpp, 1); + &::after {background:nth($cpp, 1);} + } + &.purple &__text {color:nth($cpp, 1);} + + &.red &__box {border-color:nth($cr, 1); + &::after {background:nth($cr, 1);} + } + &.red &__text {color:nth($cr, 1);} + + &.orange &__box {border-color:nth($co, 1); + &::after {background:nth($co, 1);} + } + &.orange &__text {color:nth($co, 1);} + + &.plain &__box {border-color:nth($cp, 3); + &::after {background:nth($cp, 3);} + } + &.plain &__text {color:nth($cp, 3);} + + &.grey &__box {border-color:nth($cgr, 1); + &::after {background:nth($cgr, 1);} + } + &.grey &__text {color:nth($cgr, 1);} + + + &.disabled &__box {border-color:nth($cp, 1); + &::after {background:nth($cp, 1);} + } + &.disabled &__text {color:nth($cp, 1);} + &.disabled.checked &__text {color:nth($cgr, 1);} + + + +} + + + +.do-switch {position:relative;display:inline-block;width:40px;height:30px;cursor:default; + + &__label {position:relative;display:inline-block;width:100%;height:16px;margin:7px 0;background:nth($cp, 3);border-radius:12px;} + + &__dot {position:absolute;left:0;top:-2px;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.3);} + + &:hover &__dot {transform:scale(1.1);} + &.disabled {cursor:not-allowed;} + &.disabled:hover &__dot {transform:scale(1);} + + &.checked &__dot {left:auto;right:0;} + + &.teal.checked &__dot {background:nth($ct, 1);} + &.teal.checked &__label {background:nth($ct, 2) + a0;} + + &.green.checked &__dot {background:nth($cg, 1);} + &.green.checked &__label {background:nth($cg, 2) + a0;} + + &.blue.checked &__dot {background:nth($cb, 1);} + &.blue.checked &__label {background:nth($cb, 2) + a0;} + + &.purple.checked &__dot {background:nth($cpp, 1);} + &.purple.checked &__label {background:nth($cpp, 2) + a0;} + + &.red.checked &__dot {background:nth($cr, 1);} + &.red.checked &__label {background:nth($cr, 2) + a0;} + + &.orange.checked &__dot {background:nth($co, 1);} + &.orange.checked &__label {background:nth($co, 2) + a0;} + + &.plain.checked &__dot {background:nth($cp, 3);} + &.plain.checked &__label {background:nth($cp, 2);} + + &.grey.checked &__dot {background:nth($cgr, 1);} + &.grey.checked &__label {background:nth($cgr, 2) + a0;} + + &.disabled.checked &__dot {background:#fff;} + &.disabled &__label, &.disabled.checked &__label {background:nth($cp, 2); + + &::before {display:block;position:absolute;top:6px;width:8px;height:4px;border-radius:2px;background:#fff;content:"";} + } + &.disabled &__label::before {right:7px;} + &.disabled.checked &__label::before {left:7px;} } \ No newline at end of file