/** * yvanui viewModel 双向绑定 * @author luoyifan * 2018-12-14 19:10:00 */ "use strict"; (function ($) { $.fn.power.defaults.afterRender.push(function ($target, opts, context) { if (opts.hasOwnProperty('onCreateViewModel')) { //在这里创建 viewModel if ($.type(opts.onCreateViewModel) === 'function') { var $jq = $(this); opts.onCreateViewModel.call($jq, function () { return function (option) { return $jq.vm(option); }; }); } else if ($.type(opts.onCreateViewModel) === 'object') { $(this).vm(opts.onCreateViewModel); } } }); $.fn.extend({ vm: function (option) { var jq = this; if ($.type(option) === 'undefined') { return jq.data().vm; } if (jq.length > 1) { console.error("viewModel can't create on Multiple elements"); return; } if ($.type(Vue) !== 'function') { console.error("Vue not load!"); return; } if (jq.data().hasOwnProperty('vm')) { //console.error("duplicate bindings!", jq.data().vm); var $d = jq.data(); $d.vm.$destroy(); delete $d.vm; } option = $.extend({}, $.fn.vm.defaults, option); //================ 计算所有要绑定的属性 var binds = {}; //参数中给出的 binds if ($.type(option.binds) === 'array') { for (var i = 0; i < option.binds.length; i++) { binds[option.binds[i]] = undefined; } } //watch 中给出的属性 if (option.hasOwnProperty('watch')) { for (var prop in option.watch) { if (!option.watch.hasOwnProperty(prop)) continue; binds[prop] = undefined; } } var $textbox = jq.find('[xtype="textbox"],[xtype="numberbox"],[xtype="searchbox"],[xtype="datebox"]'); var $combobox = jq.find('[xtype="combobox"]'); var $hidden = jq.find('[xtype="hidden"]'); var $checkbox = jq.find('[xtype="checkbox"]'); var $radiobutton = jq.find('[xtype="radiobutton"]'); var computed = $.extend({}, option.computed); //================ 第一次扫描 //扫描 textbox / numberbox / searchbox / datebox $textbox.each(function () { var $t = $(this); var name = $t.attr('itemId'); if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.textbox('options').hasOwnProperty('watch')) { //如果自动构建属性,或者 binds 中有这个属性,就进行绑定 binds[name] = $(this).val(); } if ($t.textbox('options').hasOwnProperty('computed')) { computed[name] = $t.textbox('options').computed; } if (option.autoCreateLabel || binds.hasOwnProperty(name + '$label') || $t.textbox('options').hasOwnProperty('watch$label')) { //如果自动构建 label,或者 binds 中有 name$label ,就绑定 label binds[name + '$label'] = $t.textbox('options').label; } }); //扫描 combobox $combobox.each(function () { var $t = $(this); var name = $t.attr('itemId'); if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.textbox('options').hasOwnProperty('watch')) { //如果自动构建属性,或者 binds 中有这个属性,就进行绑定 binds[name] = $(this).val(); } if ($t.textbox('options').hasOwnProperty('computed')) { computed[name] = $t.textbox('options').computed; } if (option.autoCreateLabel || binds.hasOwnProperty(name + '$label') || $t.textbox('options').hasOwnProperty('watch$label')) { //如果自动构建 label,或者 binds 中有 name$label ,就绑定 label binds[name + '$label'] = $t.textbox('options').label; } if (option.autoCreateText || binds.hasOwnProperty(name + '$text') || $t.textbox('options').hasOwnProperty('watch$text')) { //如果自动构建 label,或者 binds 中有 name$label ,就绑定 label binds[name + '$text'] = $t.textbox('getText'); } }); //扫描 hidden $hidden.each(function () { var $t = $(this); var name = $t.attr('itemId'); if ($t.data('options') && $t.data('options').hasOwnProperty('computed')) { computed[name] = $t.data('options').computed; } if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.data('options').hasOwnProperty('watch')) { //如果自动构建属性,或者 binds 中有这个属性,就进行绑定 binds[name] = $(this).val(); } }); //扫描 checkbox $checkbox.each(function () { var $t = $(this); var name = $t.attr('itemId'); if ($t.data('options') && $t.checkbox('options').hasOwnProperty('computed')) { computed[name] = $t.checkbox('options').computed; } if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.data('options').hasOwnProperty('watch')) { binds[name] = $t.checkbox('isChecked') ? $(this).val() : undefined; } }); //扫描 radiobutton $radiobutton.each(function () { var $t = $(this); var name = $t.attr('itemId'); if (!computed.hasOwnProperty(name)) { if ($t.data('options') && $t.checkbox('options').hasOwnProperty('computed')) { computed[name] = $t.radiobutton('options').computed; } } if (!binds[name]) { if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.data('options').hasOwnProperty('watch')) { //如果自动构建属性,或者 binds 中有这个属性,就进行绑定 binds[name] = $t.radiobutton('isChecked') ? $t.val() : undefined; } } }); //================ 构建 VUE 对象 //移除 computed 属性 for (var prop in computed) { if (!computed.hasOwnProperty(prop)) continue; delete binds[prop]; } var vm = new Vue({ el: $.type(option.previewElement) === 'function' ? option.previewElement.call(this) : option.previewElement, data: binds, computed: computed, watch: option.watch }); jq.data({ vm: vm }); jq.addClass('YvanVM'); //加入 computed 属性 for (var prop in computed) { if (!computed.hasOwnProperty(prop)) continue; binds[prop] = 'readonly'; } //================ 第二次扫描 //扫描 textbox / numberbox / searchbox / datebox $textbox.each(function () { var $t = $(this); var xtype = $t.attr('xtype'); var name = $t.attr('itemId'); if (binds.hasOwnProperty(name)) { if (binds[name] === 'readonly') { //这是计算属性,不用 view->model $t[xtype]('readonly', true); } else { //需要监听 onChange 和 input propertychange var oldChange = $t[xtype]('options').onChange; $t[xtype]({ onChange: function (data) { $.yvan.set(vm, name, $(this).val()); if (oldChange) oldChange.apply(this, arguments); } }); //$t[xtype]('textbox').bind('input propertychange', function (event) { // $.yvan.set(vm, name, $(this).val()); //}); //$t.textbox('textbox').parent().on("change", "input[type=hidden]", function () { // $.yvan.set(vm, name, $(this).val()); //}); $t.textbox('textbox').parent().on("input propertychange", "input[type=text]", function () { var $me = $(this); $.yvan.set(vm, name, $me.val()); }); $t.textbox('textbox').parent().on("change", "input[type=hidden]", function () { var $me = $(this); $.yvan.set(vm, name, $me.val()); }); } vm.$watch(name, function (val) { $t.textbox('setValue', val); }); if ($t.textbox('options').hasOwnProperty('watch')) { vm.$watch(name, $t.textbox('options').watch); } } if (binds.hasOwnProperty(name + '$label')) { //label 属性换掉,但会造成绑定失效,需要再次绑定 vm.$watch(name + '$label', function (val) { $t.textbox({ label: val }); //$t[xtype]('textbox').bind('input propertychange', function (event) { // $.yvan.set(vm, name, $(this).val()); //}); }); if ($t.textbox('options').hasOwnProperty('watch$label')) { vm.$watch(name + '$label', $t.textbox('options').watch$label); } } }); //扫描 combobox $combobox.each(function () { var $t = $(this); var xtype = $t.attr('xtype'); var name = $t.attr('itemId'); if (binds.hasOwnProperty(name)) { vm.$watch(name, function (val) { $t.combobox('setValue', val); }); if ($t.textbox('options').hasOwnProperty('watch')) { vm.$watch(name, $t.textbox('options').watch); } var oldSelect = $t[xtype]('options').onSelect; $t[xtype]({ onSelect: function (data) { var $me = $(this); if (data) { vm[name] = data[$me.combobox('options').valueField]; if (binds.hasOwnProperty(name + '$text')) { vm[name + '$text'] = data[$me.combobox('options').textField]; } } else { vm[name] = ""; if (binds.hasOwnProperty(name + '$text')) { vm[name + '$text'] = ""; } } if (oldSelect) oldSelect.apply(this, arguments); } }); $t.textbox('textbox').parent().on("change", "input[type=hidden]", function () { var $me = $(this); $.yvan.set(vm, name, $me.val()); if (binds.hasOwnProperty(name + '$text')) { vm[name + '$text'] = $t.textbox('getText'); } }); } if (binds.hasOwnProperty(name + '$label')) { vm.$watch(name + '$label', function (val) { $t.textbox({ label: val }); }); if ($t.textbox('options').hasOwnProperty('watch$label')) { vm.$watch(name + '$label', $t.textbox('options').watch$label); } } if (binds.hasOwnProperty(name + '$text')) { if ($t.textbox('options').hasOwnProperty('watch$text')) { vm.$watch(name + '$text', $t.textbox('options').watch$text); } } /* if (binds.hasOwnProperty(name + '$text')) { var oldChange = $t[xtype]('options').onChange; $t[xtype]({ onChange: function () { var $me = $(this); //vm[name + '$text'] = $me.textbox('getText'); //vm[name] = $me.val(); if (oldChange) oldChange.apply(this, arguments); } }); if ($t.textbox('options').hasOwnProperty('watch$text')) { vm.$watch(name + '$text', $t.textbox('options').watch$text); } } */ }); //扫描 hidden $hidden.each(function () { var $t = $(this); var name = $t.attr('itemId'); if (binds.hasOwnProperty(name)) { vm.$watch(name, function (val) { $t.val(val); }); $t.bind('change', function (event) { $.yvan.set(vm, name, $(this).val()); }); if ($t.data('options').hasOwnProperty('watch')) { vm.$watch(name, $t.data('options').watch); } } }); //扫描 checkbox $checkbox.each(function () { var $t = $(this); var name = $t.attr('itemId'); if (binds.hasOwnProperty(name)) { vm.$watch(name, function (val) { $t.checkbox((val === $t.val()) ? 'check' : 'uncheck'); }); var oldChange = $t.checkbox('options').onChange; $t.checkbox({ onChange: function (event) { $.yvan.set(vm, name, $t.checkbox('isChecked') ? $t.val() : ''); if (oldChange) oldChange.apply(this, arguments); } }); if ($t.checkbox('options').hasOwnProperty('watch')) { vm.$watch(name, $t.checkbox('options').watch); } $t.checkbox('checkbox').on("change", "input[type=checkbox]", function () { var cked = $(this).val() === $t.val(); $.yvan.set(vm, name, cked ? $t.val() : ''); $t.checkbox(cked ? 'check' : 'uncheck'); }); } }); //扫描 radiobutton $radiobutton.each(function () { var $t = $(this); var name = $t.attr('itemId'); if (binds.hasOwnProperty(name)) { vm.$watch(name, function (val) { $t.radiobutton((val === $t.val()) ? 'check' : 'uncheck'); }); var oldChange = $t.radiobutton('options').onChange; $t.radiobutton({ onChange: function (event) { $.yvan.set(vm, name, $t.radiobutton('isChecked') ? $t.val() : ''); if (oldChange) oldChange.apply(this, arguments); } }); if ($t.radiobutton('options').hasOwnProperty('watch')) { vm.$watch(name, $t.radiobutton('options').watch); } $t.radiobutton('radiobutton').on("change", "input[type=radio]", function () { var cked = $(this).val() === $t.val(); $.yvan.set(vm, name, cked ? $t.val() : ''); $t.radiobutton(cked ? 'check' : 'uncheck'); }); } }); //================ 结束返回 return vm; } }); $.fn.vm.defaults = { previewElement: undefined, //预览调试用的,实际情况下不需要设定 autoCreateModel: true, //自动根据内部的组件,构建对应 name 的属性 autoCreateLabel: false, //自动根据内部的组件的Label,创建对应的 name$label 属性 autoCreateText: true, //自动根据内部 combobox 组件的显示值,创建对应的 name$text 属性 binds: [], //如果不使用上面的3个 auto, 就个性化的设定所需要的 binds //'prodCode$text', //combobox 组件,可以创建 name$text 代表combobox的显示值, combobox 的 value 对应还是 name 属性值 computed: {} //计算属性,凡是计算属性,绑定的控件都会被设置为 readonly }; })(jQuery);