Ext Js 6+ 动态切换皮肤
在这里以ext js 6.2.1版本为例(注:需要安装Sencha Cmd,以及下载对应的sdk)
1.创建空白项目
在命令行中输入sencha -sdk D:\Code\ext-6.2.1 generate app app D:\Code\Test
D:\ASPX\ext-6.2.1 是指sdk目录
generate app app 是创建应用,这个应用的包名是app
D:\ASPX\Test 就是所创建项目的目录了
运行一下项目,效果是这样的
2.修改app.json
1 { 2 //使用sencha -sdk sdk地址 generate app app 目标项目地址命令生成项目 3 //修改app.json后依次执行以下命令即可使用 4 //::重新生成开发环境sencha app build development 5 //::打包sencha app build -c 6 "name": "app", 7 "namespace": "app", 8 "version": "1.0.0.0", 9 "framework": "ext", 10 11 /** 12 * The list of required packages (with optional versions; default is "latest"). 13 * 14 * For example, 15 * 16 * "requires": [ 17 * "charts" 18 * ] 19 */ 20 "requires": [ 21 "font-awesome" 22 ], 23 24 /** 25 * The relative path to the application's markup file (html, jsp, asp, etc.). 26 */ 27 "indexHtmlPath": "index.html", 28 29 /** 30 * Comma-separated string with the paths of directories or files to search. Any classes 31 * declared in these locations will be available in your class "requires" or in calls 32 * to "Ext.require". The "app.dir" variable below is expanded to the path where the 33 * application resides (the same folder in which this file is located). 34 */ 35 "classpath": [ 36 "app", 37 "${toolkit.name}/src" 38 ], 39 40 /** 41 * Comma-separated string with the paths of directories or files to search. Any classes 42 * declared in these locations will be automatically required and included in the build. 43 * If any file defines an Ext JS override (using Ext.define with an "override" property), 44 * that override will in fact only be included in the build if the target class specified 45 * in the "override" property is also included. 46 */ 47 "overrides": [ 48 "overrides", 49 "${toolkit.name}/overrides" 50 ], 51 52 /** 53 * Fashion build configuration properties. 54 */ 55 "fashion": { 56 57 "inliner": { 58 /** 59 * Disable resource inliner. Production builds enable this by default. 60 */ 61 "enable": false 62 } 63 }, 64 65 /** 66 * Sass configuration properties. 67 */ 68 "sass": { 69 /** 70 * The root namespace to use when mapping *.scss files to classes in the 71 * sass/src and sass/var directories. For example, "app.view.Foo" would 72 * map to "sass/src/view/Foo.scss". If we changed this to "app.view" then 73 * it would map to "sass/src/Foo.scss". To style classes outside the app's 74 * root namespace, change this to "". Doing so would change the mapping of 75 * "app.view.Foo" to "sass/src/app/view/Foo.scss". 76 */ 77 "namespace": "app", 78 79 /** 80 * Generated sass source settings 81 * 82 * "generated": { 83 * // The file used to save sass variables edited via Sencha Inspector and Sencha Themer. 84 * // This file will automatically be applied to the end of the scss build. 85 * "var": "sass/save.scss", 86 * 87 * // The directory used to save generated sass sources. 88 * // This directory will automatically be applied to the end of the scss build. 89 * "src": "sass/save" 90 * } 91 * 92 */ 93 94 /** 95 * Comma-separated list of files or folders containing extra Sass. These 96 * files are automatically included in the Sass compilation. By default this 97 * is just "etc/all.scss" to allow import directives to control the order 98 * other files are included. 99 * 100 * All "etc" files are included at the top of the Sass compilation in their 101 * dependency order: 102 * 103 * +-------+---------+ 104 * | | base | 105 * | theme +---------+ 106 * | | derived | 107 * +-------+---------+ 108 * | packages | (in package dependency order) 109 * +-----------------+ 110 * | application | 111 * +-----------------+ 112 */ 113 "etc": [ 114 "sass/etc/all.scss", 115 "${toolkit.name}/sass/etc/all.scss" 116 ], 117 118 /** 119 * Comma-separated list of folders containing Sass variable definitions 120 * files. These file can also define Sass mixins for use by components. 121 * 122 * All "var" files are included after "etc" files in the Sass compilation in 123 * dependency order: 124 * 125 * +-------+---------+ 126 * | | base | 127 * | theme +---------+ 128 * | | derived | 129 * +-------+---------+ 130 * | packages | (in package dependency order) 131 * +-----------------+ 132 * | application | 133 * +-----------------+ 134 * 135 * The "sass/var/all.scss" file is always included at the start of the var 136 * block before any files associated with JavaScript classes. 137 */ 138 "var": [ 139 "sass/var/all.scss", 140 "sass/var", 141 "${toolkit.name}/sass/var/all.scss", 142 "${toolkit.name}/sass/var" 143 ], 144 145 /** 146 * Comma-separated list of folders containing Sass rule files. 147 * 148 * All "src" files are included after "var" files in the Sass compilation in 149 * dependency order (the same order as "etc"): 150 * 151 * +-------+---------+ 152 * | | base | 153 * | theme +---------+ 154 * | | derived | 155 * +-------+---------+ 156 * | packages | (in package dependency order) 157 * +-----------------+ 158 * | application | 159 * +-----------------+ 160 */ 161 "src": [ 162 "sass/src", 163 "${toolkit.name}/sass/src" 164 ] 165 }, 166 167 /** 168 * List of all JavaScript assets in the right execution order. 169 * 170 * Each item is an object with the following format: 171 * 172 * { 173 * // Path to file. If the file is local this must be a relative path from 174 * // this app.json file. 175 * // 176 * "path": "path/to/script.js", // REQUIRED 177 * 178 * // Set to true on one file to indicate that it should become the container 179 * // for the concatenated classes. 180 * // 181 * "bundle": false, // OPTIONAL 182 * 183 * // Set to true to include this file in the concatenated classes. 184 * // 185 * "includeInBundle": false, // OPTIONAL 186 * 187 * // Specify as true if this file is remote and should not be copied into the 188 * // build folder. Defaults to false for a local file which will be copied. 189 * // 190 * "remote": false, // OPTIONAL 191 * 192 * // If not specified, this file will only be loaded once, and cached inside 193 * // localStorage until this value is changed. You can specify: 194 * // 195 * // - "delta" to enable over-the-air delta update for this file 196 * // - "full" means full update will be made when this file changes 197 * // 198 * "update": "", // OPTIONAL 199 * 200 * // A value of true indicates that is a development mode only dependency. 201 * // These files will not be copied into the build directory or referenced 202 * // in the generate app.json manifest for the micro loader. 203 * // 204 * "bootstrap": false // OPTIONAL 205 * } 206 * 207 */ 208 "js": [{ 209 "path": "app.js", 210 "bundle": true 211 }], 212 //对应每个皮肤模块需要加载引入的js,因为这里都是classic版本,所以直接屏蔽掉 213 214 /** 215 * Settings specific to classic toolkit builds. 216 */ 217 // "classic": { 218 // "js": [ 219 // // Remove this entry to individually load sources from the framework. 220 // { 221 // "path": "${framework.dir}/build/ext-all-rtl-debug.js" 222 // } 223 // ] 224 // }, 225 226 /** 227 * Settings specific to modern toolkit builds. 228 */ 229 // "modern": { 230 // "js": [ 231 // // Remove this entry to individually load sources from the framework. 232 // { 233 // "path": "${framework.dir}/build/ext-modern-all-debug.js" 234 // } 235 // ] 236 // }, 237 238 /** 239 * List of all CSS assets in the right inclusion order. 240 * 241 * Each item is an object with the following format: 242 * 243 * { 244 * // Path to file. If the file is local this must be a relative path from 245 * // this app.json file. 246 * // 247 * "path": "path/to/stylesheet.css", // REQUIRED 248 * 249 * // Specify as true if this file is remote and should not be copied into the 250 * // build folder. Defaults to false for a local file which will be copied. 251 * // 252 * "remote": false, // OPTIONAL 253 * 254 * // If not specified, this file will only be loaded once, and cached inside 255 * // localStorage until this value is changed. You can specify: 256 * // 257 * // - "delta" to enable over-the-air delta update for this file 258 * // - "full" means full update will be made when this file changes 259 * // 260 * "update": "" // OPTIONAL 261 * } 262 */ 263 "css": [{ 264 // this entry uses an ant variable that is the calculated 265 // value of the generated output css file for the app, 266 // defined in .sencha/app/defaults.properties 267 "path": "${build.out.css.path}", 268 "bundle": true, 269 "exclude": ["fashion"] 270 }], 271 272 /** 273 * This option is used to configure the dynamic loader. At present these options 274 * are supported. 275 * 276 */ 277 "loader": { 278 // This property controls how the loader manages caching for requests: 279 // 280 // - true: allows requests to receive cached responses 281 // - false: disable cached responses by adding a random "cache buster" 282 // - other: a string (such as the build.timestamp shown here) to allow 283 // requests to be cached for this build. 284 // 285 "cache": false, 286 287 // When "cache" is not true, this value is the request parameter used 288 // to control caching. 289 // 290 "cacheParam": "_dc" 291 }, 292 293 /** 294 * Settings specific to production builds. 295 */ 296 "production": { 297 "output": { 298 "appCache": { 299 "enable": true, 300 "path": "cache.appcache" 301 } 302 }, 303 "loader": { 304 "cache": "${build.timestamp}" 305 }, 306 "cache": { 307 "enable": true 308 }, 309 "compressor": { 310 "type": "yui" 311 } 312 }, 313 314 /** 315 * Settings specific to testing builds. 316 */ 317 "testing": {}, 318 319 /** 320 * Settings specific to development builds. 321 */ 322 "development": { 323 "watch": { 324 "delay": 250 325 } 326 }, 327 328 /** 329 * Controls the output structure of development-mode (bootstrap) artifacts. May 330 * be specified by a string: 331 * 332 * "bootstrap": "${app.dir}" 333 * 334 * This will adjust the base path for all bootstrap objects, or expanded into object 335 * form: 336 * 337 * "bootstrap": { 338 * "base": "${app.dir}", 339 * "manifest": "bootstrap.json", 340 * "microloader": "bootstrap.js", 341 * "css": "bootstrap.css" 342 * } 343 * 344 * You can optionally exclude entries from the manifest. For example, to exclude 345 * the "loadOrder" (to help development load approximate a build) you can add: 346 * 347 * "bootstrap": { 348 * "manifest": { 349 * "path": "bootstrap.json", 350 * "exclude": "loadOrder" 351 * } 352 * } 353 * 354 */ 355 "bootstrap": { 356 "base": "${app.dir}", 357 358 "manifest": "${build.id}.json", 359 360 "microloader": "bootstrap.js", 361 "css": "bootstrap.css" 362 }, 363 364 /** 365 * Controls the output directory for build resources. May be set with 366 * either a string: 367 * 368 * "${workspace.build.dir}/${build.environment}/${app.name}" 369 * 370 * or an object containing values for various types of build artifacts: 371 * 372 * { 373 * "base": "${workspace.build.dir}/${build.environment}/${app.name}", 374 * "page": { 375 * "path": "../index.html", 376 * "enable": false 377 * }, 378 * "css": "${app.output.resources}/${app.name}-all.css", 379 * "js": { 380 * "path": "app.js", 381 * // This setting constrols the output language level. Set to 'ES6' to 382 * // disable the transpiler 383 * "version": "ES5" 384 * }, 385 * "microloader": { 386 * "path": "microloader.js", 387 * "embed": true, 388 * "enable": true 389 * }, 390 * "manifest": { 391 * "path": "app.json", 392 * "embed": false, 393 * "enable": "${app.output.microloader.enable}" 394 * }, 395 * "resources": "resources", 396 * "slicer": { 397 * "path": "${app.output.resources}/images", 398 * "enable": false 399 * }, 400 * // Setting the "enable" property of this object to a Truthy value will cause a Application Cache 401 * // manifest file to be generated based on this files appCache object. This file will then be injected 402 * // into the index.html file of the built application 403 * "appCache":{ 404 * "enable": false" 405 * } 406 * } 407 * 408 */ 409 410 "output": { 411 // "base": "${workspace.build.dir}/${build.environment}/${app.name}", 412 //编译后输出路径 413 "base": "../webApp", 414 "page": "index.html", 415 "manifest": "${build.id}.json", 416 // "js": "${build.id}/app.js", 417 //因为示例都是classic版本,没有必要单独生成app.js可以合用一个,你可以根据实际情况去配置 418 "js": "app.js", 419 "appCache": { 420 "enable": false 421 }, 422 "resources": { 423 "path": "${build.id}/resources", 424 "shared": "resources" 425 } 426 }, 427 428 /** 429 * Controls for localStorage caching 430 * "cache": { 431 * // This property controls whether localStorage caching of this manifest file is on or off. 432 * // if disabled no deltas will be generated during a build and full updates will be disabled 433 * "enable": false, 434 * 435 * // This property allows for global toggle of deltas. 436 * // If set to a string the value will be used as the path to where deltas will be generated relative to you build. 437 * // If set to a Truthy Value the default path ok "deltas" will be used 438 * // If set to a Falsey value or if this property is not present deltas will be disabled and not generated. 439 * 440 * "deltas": "deltas" 441 * } 442 */ 443 444 "cache": { 445 "enable": false, 446 "deltas": "${build.id}/deltas" 447 }, 448 449 /** 450 * Used to automatically generate cache.manifest (HTML 5 application cache manifest) 451 * file when you build. 452 */ 453 "appCache": { 454 /** 455 * List of items in the CACHE MANIFEST section 456 */ 457 "cache": [ 458 "index.html" 459 ], 460 /** 461 * List of items in the NETWORK section 462 */ 463 "network": [ 464 "*" 465 ], 466 /** 467 * List of items in the FALLBACK section 468 */ 469 "fallback": [] 470 }, 471 472 /** 473 * Extra resources to be copied into the resource folder as specified in the "resources" 474 * property of the "output" object. Folders specified in this list will be deeply copied. 475 */ 476 "resources": [{ 477 "path": "resources", 478 "output": "shared" 479 }, 480 { 481 "path": "${toolkit.name}/resources" 482 }, 483 { 484 "path": "${build.id}/resources" 485 } 486 ], 487 488 /** 489 * Directory path to store all previous production builds. Note that the content 490 * generated inside this directory must be kept intact for proper generation of 491 * deltas between updates. 492 */ 493 494 "archivePath": "archive/${build.id}", 495 496 /** 497 * Build Profiles. This object's properties are each a "build profile". You can 498 * add as many as you need to produce optimized builds for devices, themes, locales 499 * or other criteria. Your "Ext.beforeLoad" hook (see index.html) is responsible for 500 * selecting the desired build profile by setting "Ext.manifest" to one of these 501 * names. 502 * 503 * "builds": { 504 * "classic": { 505 * "toolkit": "classic", 506 * "theme": "theme-neptune" 507 * }, 508 * 509 * "modern": { 510 * "toolkit": "modern", 511 * "theme": "theme-neptune" 512 * } 513 * } 514 * 515 */ 516 //这里定义多套皮肤toolkit统一为classic 517 //theme就是对应的皮肤 518 //在启动时加入参数例如index.html?theme=modern 519 //这里就会去找modern配置下面的toolkit和theme分别去加载js和css了 520 521 "builds": { 522 "classic": { 523 "toolkit": "classic", 524 "theme": "theme-triton", 525 "sass": { 526 "generated": { 527 "var": "classic/sass/save.scss", 528 "src": "classic/sass/save" 529 } 530 } 531 }, 532 533 "modern": { 534 "toolkit": "classic", 535 "theme": "theme-gray", 536 "sass": { 537 "generated": { 538 "var": "modern/sass/save.scss", 539 "src": "modern/sass/save" 540 } 541 } 542 }, 543 "neptune": { 544 "toolkit": "classic", 545 "theme": "theme-neptune", 546 "sass": { 547 "generated": { 548 "var": "neptune/sass/save.scss", 549 "src": "neptune/sass/save" 550 } 551 } 552 } 553 }, 554 555 /** 556 * File / directory name patttern to ignore when copying to the builds. Must be a 557 * valid regular expression. 558 */ 559 "ignore": [ 560 "(^|/)CVS(/?$|/.*?$)" 561 ], 562 563 /** 564 * Uniquely generated id for this application, used as prefix for localStorage keys. 565 * Normally you should never change this value. 566 */ 567 "id": "1a948c1b-4dad-4c78-8917-615ca8bb45cf" 568 }
3.修改index.html
1 <!DOCTYPE HTML> 2 <html manifest=""> 3 4 <head> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta charset="UTF-8"> 7 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=10, user-scalable=yes"> 8 9 <title>app</title> 10 11 <script type="text/javascript"> 12 var Ext = Ext || {}; // Ext namespace won't be defined yet... 13 14 //根据theme参数切换皮肤,目前支持neptune、modern、classic三种 15 Ext.beforeLoad = function (tags) { 16 var theme = location.href.match(/theme=([\w-]+)/); 17 theme = (theme && theme[1]) || 'classic'; 18 19 console.log('加载系统主题方案:' + theme); 20 Ext.manifest = theme + '.json'; 21 22 23 }; 24 </script> 25 26 <!-- The line below must be kept intact for Sencha Cmd to build your application --> 27 <script id="microloader" data-app="1a948c1b-4dad-4c78-8917-615ca8bb45cf" type="text/javascript" src="bootstrap.js"></script> 28 29 </head> 30 31 <body></body> 32 33 </html>
4.修改代码
我的需求只需要支持classic即可,所以我们修改一下代码,把classic目录中的所有文件移动到根目录即可。需要移动的文件就那么几个,就不一一叙述了,然后清空classic和modern目录下的文件。
5.编译打包
首先执行sencha app build development命令重新生成编译环境,然后执行sencha app build -c命令即可
6.运行
不管是在开发环境还是生产环境我们都可以通过?theme=皮肤名称参数来切换皮肤了
结语:这只是一个基本运用,具体扩展就需要你自己去发掘了。