yvanui.vm.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /**
  2. * yvanui viewModel 双向绑定
  3. * @author luoyifan
  4. * 2018-12-14 19:10:00
  5. */
  6. "use strict";
  7. (function ($) {
  8. $.fn.power.defaults.afterRender.push(function ($target, opts, context) {
  9. if (opts.hasOwnProperty('onCreateViewModel')) {
  10. //在这里创建 viewModel
  11. if ($.type(opts.onCreateViewModel) === 'function') {
  12. var $jq = $(this);
  13. opts.onCreateViewModel.call($jq, function () {
  14. return function (option) {
  15. return $jq.vm(option);
  16. };
  17. });
  18. } else if ($.type(opts.onCreateViewModel) === 'object') {
  19. $(this).vm(opts.onCreateViewModel);
  20. }
  21. }
  22. });
  23. $.fn.extend({
  24. vm: function (option) {
  25. var jq = this;
  26. if ($.type(option) === 'undefined') {
  27. return jq.data().vm;
  28. }
  29. if (jq.length > 1) {
  30. console.error("viewModel can't create on Multiple elements");
  31. return;
  32. }
  33. if ($.type(Vue) !== 'function') {
  34. console.error("Vue not load!");
  35. return;
  36. }
  37. if (jq.data().hasOwnProperty('vm')) {
  38. //console.error("duplicate bindings!", jq.data().vm);
  39. var $d = jq.data();
  40. $d.vm.$destroy();
  41. delete $d.vm;
  42. }
  43. option = $.extend({}, $.fn.vm.defaults, option);
  44. //================ 计算所有要绑定的属性
  45. var binds = {};
  46. //参数中给出的 binds
  47. if ($.type(option.binds) === 'array') {
  48. for (var i = 0; i < option.binds.length; i++) {
  49. binds[option.binds[i]] = undefined;
  50. }
  51. }
  52. //watch 中给出的属性
  53. if (option.hasOwnProperty('watch')) {
  54. for (var prop in option.watch) {
  55. if (!option.watch.hasOwnProperty(prop)) continue;
  56. binds[prop] = undefined;
  57. }
  58. }
  59. var $textbox = jq.find('[xtype="textbox"],[xtype="numberbox"],[xtype="searchbox"],[xtype="datebox"]');
  60. var $combobox = jq.find('[xtype="combobox"]');
  61. var $hidden = jq.find('[xtype="hidden"]');
  62. var $checkbox = jq.find('[xtype="checkbox"]');
  63. var $radiobutton = jq.find('[xtype="radiobutton"]');
  64. var computed = $.extend({}, option.computed);
  65. //================ 第一次扫描
  66. //扫描 textbox / numberbox / searchbox / datebox
  67. $textbox.each(function () {
  68. var $t = $(this);
  69. var name = $t.attr('itemId');
  70. if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.textbox('options').hasOwnProperty('watch')) {
  71. //如果自动构建属性,或者 binds 中有这个属性,就进行绑定
  72. binds[name] = $(this).val();
  73. }
  74. if ($t.textbox('options').hasOwnProperty('computed')) {
  75. computed[name] = $t.textbox('options').computed;
  76. }
  77. if (option.autoCreateLabel || binds.hasOwnProperty(name + '$label') || $t.textbox('options').hasOwnProperty('watch$label')) {
  78. //如果自动构建 label,或者 binds 中有 name$label ,就绑定 label
  79. binds[name + '$label'] = $t.textbox('options').label;
  80. }
  81. });
  82. //扫描 combobox
  83. $combobox.each(function () {
  84. var $t = $(this);
  85. var name = $t.attr('itemId');
  86. if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.textbox('options').hasOwnProperty('watch')) {
  87. //如果自动构建属性,或者 binds 中有这个属性,就进行绑定
  88. binds[name] = $(this).val();
  89. }
  90. if ($t.textbox('options').hasOwnProperty('computed')) {
  91. computed[name] = $t.textbox('options').computed;
  92. }
  93. if (option.autoCreateLabel || binds.hasOwnProperty(name + '$label') || $t.textbox('options').hasOwnProperty('watch$label')) {
  94. //如果自动构建 label,或者 binds 中有 name$label ,就绑定 label
  95. binds[name + '$label'] = $t.textbox('options').label;
  96. }
  97. if (option.autoCreateText || binds.hasOwnProperty(name + '$text') || $t.textbox('options').hasOwnProperty('watch$text')) {
  98. //如果自动构建 label,或者 binds 中有 name$label ,就绑定 label
  99. binds[name + '$text'] = $t.textbox('getText');
  100. }
  101. });
  102. //扫描 hidden
  103. $hidden.each(function () {
  104. var $t = $(this);
  105. var name = $t.attr('itemId');
  106. if ($t.data('options') && $t.data('options').hasOwnProperty('computed')) {
  107. computed[name] = $t.data('options').computed;
  108. }
  109. if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.data('options').hasOwnProperty('watch')) {
  110. //如果自动构建属性,或者 binds 中有这个属性,就进行绑定
  111. binds[name] = $(this).val();
  112. }
  113. });
  114. //扫描 checkbox
  115. $checkbox.each(function () {
  116. var $t = $(this);
  117. var name = $t.attr('itemId');
  118. if ($t.data('options') && $t.checkbox('options').hasOwnProperty('computed')) {
  119. computed[name] = $t.checkbox('options').computed;
  120. }
  121. if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.data('options').hasOwnProperty('watch')) {
  122. binds[name] = $t.checkbox('isChecked') ? $(this).val() : undefined;
  123. }
  124. });
  125. //扫描 radiobutton
  126. $radiobutton.each(function () {
  127. var $t = $(this);
  128. var name = $t.attr('itemId');
  129. if (!computed.hasOwnProperty(name)) {
  130. if ($t.data('options') && $t.checkbox('options').hasOwnProperty('computed')) {
  131. computed[name] = $t.radiobutton('options').computed;
  132. }
  133. }
  134. if (!binds[name]) {
  135. if (option.autoCreateModel || binds.hasOwnProperty(name) || $t.data('options').hasOwnProperty('watch')) {
  136. //如果自动构建属性,或者 binds 中有这个属性,就进行绑定
  137. binds[name] = $t.radiobutton('isChecked') ? $t.val() : undefined;
  138. }
  139. }
  140. });
  141. //================ 构建 VUE 对象
  142. //移除 computed 属性
  143. for (var prop in computed) {
  144. if (!computed.hasOwnProperty(prop)) continue;
  145. delete binds[prop];
  146. }
  147. var vm = new Vue({
  148. el: $.type(option.previewElement) === 'function' ? option.previewElement.call(this) : option.previewElement,
  149. data: binds,
  150. computed: computed,
  151. watch: option.watch
  152. });
  153. jq.data({ vm: vm });
  154. jq.addClass('YvanVM');
  155. //加入 computed 属性
  156. for (var prop in computed) {
  157. if (!computed.hasOwnProperty(prop)) continue;
  158. binds[prop] = 'readonly';
  159. }
  160. //================ 第二次扫描
  161. //扫描 textbox / numberbox / searchbox / datebox
  162. $textbox.each(function () {
  163. var $t = $(this);
  164. var xtype = $t.attr('xtype');
  165. var name = $t.attr('itemId');
  166. if (binds.hasOwnProperty(name)) {
  167. if (binds[name] === 'readonly') {
  168. //这是计算属性,不用 view->model
  169. $t[xtype]('readonly', true);
  170. } else {
  171. //需要监听 onChange 和 input propertychange
  172. var oldChange = $t[xtype]('options').onChange;
  173. $t[xtype]({
  174. onChange: function (data) {
  175. $.yvan.set(vm, name, $(this).val());
  176. if (oldChange) oldChange.apply(this, arguments);
  177. }
  178. });
  179. //$t[xtype]('textbox').bind('input propertychange', function (event) {
  180. // $.yvan.set(vm, name, $(this).val());
  181. //});
  182. //$t.textbox('textbox').parent().on("change", "input[type=hidden]", function () {
  183. // $.yvan.set(vm, name, $(this).val());
  184. //});
  185. $t.textbox('textbox').parent().on("input propertychange", "input[type=text]", function () {
  186. var $me = $(this);
  187. $.yvan.set(vm, name, $me.val());
  188. });
  189. $t.textbox('textbox').parent().on("change", "input[type=hidden]", function () {
  190. var $me = $(this);
  191. $.yvan.set(vm, name, $me.val());
  192. });
  193. }
  194. vm.$watch(name, function (val) {
  195. $t.textbox('setValue', val);
  196. });
  197. if ($t.textbox('options').hasOwnProperty('watch')) {
  198. vm.$watch(name, $t.textbox('options').watch);
  199. }
  200. }
  201. if (binds.hasOwnProperty(name + '$label')) {
  202. //label 属性换掉,但会造成绑定失效,需要再次绑定
  203. vm.$watch(name + '$label', function (val) {
  204. $t.textbox({ label: val });
  205. //$t[xtype]('textbox').bind('input propertychange', function (event) {
  206. // $.yvan.set(vm, name, $(this).val());
  207. //});
  208. });
  209. if ($t.textbox('options').hasOwnProperty('watch$label')) {
  210. vm.$watch(name + '$label', $t.textbox('options').watch$label);
  211. }
  212. }
  213. });
  214. //扫描 combobox
  215. $combobox.each(function () {
  216. var $t = $(this);
  217. var xtype = $t.attr('xtype');
  218. var name = $t.attr('itemId');
  219. if (binds.hasOwnProperty(name)) {
  220. vm.$watch(name, function (val) {
  221. $t.combobox('setValue', val);
  222. });
  223. if ($t.textbox('options').hasOwnProperty('watch')) {
  224. vm.$watch(name, $t.textbox('options').watch);
  225. }
  226. var oldSelect = $t[xtype]('options').onSelect;
  227. $t[xtype]({
  228. onSelect: function (data) {
  229. var $me = $(this);
  230. if (data) {
  231. vm[name] = data[$me.combobox('options').valueField];
  232. if (binds.hasOwnProperty(name + '$text')) {
  233. vm[name + '$text'] = data[$me.combobox('options').textField];
  234. }
  235. } else {
  236. vm[name] = "";
  237. if (binds.hasOwnProperty(name + '$text')) {
  238. vm[name + '$text'] = "";
  239. }
  240. }
  241. if (oldSelect) oldSelect.apply(this, arguments);
  242. }
  243. });
  244. $t.textbox('textbox').parent().on("change", "input[type=hidden]", function () {
  245. var $me = $(this);
  246. $.yvan.set(vm, name, $me.val());
  247. if (binds.hasOwnProperty(name + '$text')) {
  248. vm[name + '$text'] = $t.textbox('getText');
  249. }
  250. });
  251. }
  252. if (binds.hasOwnProperty(name + '$label')) {
  253. vm.$watch(name + '$label', function (val) {
  254. $t.textbox({ label: val });
  255. });
  256. if ($t.textbox('options').hasOwnProperty('watch$label')) {
  257. vm.$watch(name + '$label', $t.textbox('options').watch$label);
  258. }
  259. }
  260. if (binds.hasOwnProperty(name + '$text')) {
  261. if ($t.textbox('options').hasOwnProperty('watch$text')) {
  262. vm.$watch(name + '$text', $t.textbox('options').watch$text);
  263. }
  264. }
  265. /*
  266. if (binds.hasOwnProperty(name + '$text')) {
  267. var oldChange = $t[xtype]('options').onChange;
  268. $t[xtype]({
  269. onChange: function () {
  270. var $me = $(this);
  271. //vm[name + '$text'] = $me.textbox('getText');
  272. //vm[name] = $me.val();
  273. if (oldChange) oldChange.apply(this, arguments);
  274. }
  275. });
  276. if ($t.textbox('options').hasOwnProperty('watch$text')) {
  277. vm.$watch(name + '$text', $t.textbox('options').watch$text);
  278. }
  279. }
  280. */
  281. });
  282. //扫描 hidden
  283. $hidden.each(function () {
  284. var $t = $(this);
  285. var name = $t.attr('itemId');
  286. if (binds.hasOwnProperty(name)) {
  287. vm.$watch(name, function (val) {
  288. $t.val(val);
  289. });
  290. $t.bind('change', function (event) {
  291. $.yvan.set(vm, name, $(this).val());
  292. });
  293. if ($t.data('options').hasOwnProperty('watch')) {
  294. vm.$watch(name, $t.data('options').watch);
  295. }
  296. }
  297. });
  298. //扫描 checkbox
  299. $checkbox.each(function () {
  300. var $t = $(this);
  301. var name = $t.attr('itemId');
  302. if (binds.hasOwnProperty(name)) {
  303. vm.$watch(name, function (val) {
  304. $t.checkbox((val === $t.val()) ? 'check' : 'uncheck');
  305. });
  306. var oldChange = $t.checkbox('options').onChange;
  307. $t.checkbox({
  308. onChange: function (event) {
  309. $.yvan.set(vm, name, $t.checkbox('isChecked') ? $t.val() : '');
  310. if (oldChange) oldChange.apply(this, arguments);
  311. }
  312. });
  313. if ($t.checkbox('options').hasOwnProperty('watch')) {
  314. vm.$watch(name, $t.checkbox('options').watch);
  315. }
  316. $t.checkbox('checkbox').on("change", "input[type=checkbox]", function () {
  317. var cked = $(this).val() === $t.val();
  318. $.yvan.set(vm, name, cked ? $t.val() : '');
  319. $t.checkbox(cked ? 'check' : 'uncheck');
  320. });
  321. }
  322. });
  323. //扫描 radiobutton
  324. $radiobutton.each(function () {
  325. var $t = $(this);
  326. var name = $t.attr('itemId');
  327. if (binds.hasOwnProperty(name)) {
  328. vm.$watch(name, function (val) {
  329. $t.radiobutton((val === $t.val()) ? 'check' : 'uncheck');
  330. });
  331. var oldChange = $t.radiobutton('options').onChange;
  332. $t.radiobutton({
  333. onChange: function (event) {
  334. $.yvan.set(vm, name, $t.radiobutton('isChecked') ? $t.val() : '');
  335. if (oldChange) oldChange.apply(this, arguments);
  336. }
  337. });
  338. if ($t.radiobutton('options').hasOwnProperty('watch')) {
  339. vm.$watch(name, $t.radiobutton('options').watch);
  340. }
  341. $t.radiobutton('radiobutton').on("change", "input[type=radio]", function () {
  342. var cked = $(this).val() === $t.val();
  343. $.yvan.set(vm, name, cked ? $t.val() : '');
  344. $t.radiobutton(cked ? 'check' : 'uncheck');
  345. });
  346. }
  347. });
  348. //================ 结束返回
  349. return vm;
  350. }
  351. });
  352. $.fn.vm.defaults = {
  353. previewElement: undefined, //预览调试用的,实际情况下不需要设定
  354. autoCreateModel: true, //自动根据内部的组件,构建对应 name 的属性
  355. autoCreateLabel: false, //自动根据内部的组件的Label,创建对应的 name$label 属性
  356. autoCreateText: true, //自动根据内部 combobox 组件的显示值,创建对应的 name$text 属性
  357. binds: [], //如果不使用上面的3个 auto, 就个性化的设定所需要的 binds
  358. //'prodCode$text', //combobox 组件,可以创建 name$text 代表combobox的显示值, combobox 的 value 对应还是 name 属性值
  359. computed: {} //计算属性,凡是计算属性,绑定的控件都会被设置为 readonly
  360. };
  361. })(jQuery);