├── ES6 └── promise │ └── index.html ├── LICENSE ├── README.md ├── cnd ├── LocalStore │ └── IndexedDB │ │ ├── index.html │ │ ├── nf-indexedDB - 副本 (2).js │ │ ├── nf-indexedDB - 副本 (3).js │ │ ├── nf-indexedDB - 副本.js │ │ ├── nf-indexedDB.config.js │ │ ├── nf-indexedDB.js │ │ ├── 新建文本文档 (2).txt │ │ └── 新建文本文档.txt ├── Vue3Composition │ ├── index.html │ ├── public │ │ └── favicon.ico │ ├── reactive.html │ └── ref.html ├── caifumoni.html ├── init │ └── index.html ├── project-admin │ ├── README.md │ ├── index.html │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── app.js │ │ ├── components │ │ │ ├── public │ │ │ │ ├── navMenu.html │ │ │ │ ├── navMenu.js │ │ │ │ ├── nfButton.html │ │ │ │ ├── nfButton.js │ │ │ │ ├── nfFind.html │ │ │ │ ├── nfFind.js │ │ │ │ ├── nfForm.html │ │ │ │ ├── nfForm.js │ │ │ │ ├── nfGrid.html │ │ │ │ ├── nfGrid.js │ │ │ │ ├── nfPager.html │ │ │ │ ├── nfPager.js │ │ │ │ ├── nfTabs.html │ │ │ │ └── nfTabs.js │ │ │ ├── test.html │ │ │ └── test.js │ │ ├── main.js │ │ ├── router │ │ │ └── index.js │ │ ├── script │ │ │ └── appImport.js │ │ ├── store │ │ │ ├── actionManage.js │ │ │ ├── index.js │ │ │ ├── map.js │ │ │ └── mutation-types.js │ │ └── views │ │ │ ├── About.html │ │ │ ├── About.js │ │ │ ├── component.html │ │ │ ├── component.js │ │ │ ├── home.js │ │ │ ├── packList.html │ │ │ ├── packList.js │ │ │ ├── store.html │ │ │ └── store.js │ └── web.config ├── project-axios │ ├── README.md │ ├── a.html │ ├── index.html │ ├── json.aspx │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── app.js │ │ ├── component │ │ │ ├── HelloWorld.vue │ │ │ └── test.js │ │ ├── main.js │ │ ├── router │ │ │ └── index.js │ │ ├── store │ │ │ └── index.js │ │ └── views │ │ │ ├── component.js │ │ │ ├── home.js │ │ │ └── state.js │ ├── vuex.vue │ └── web.config ├── project-compositionapi │ ├── README.md │ ├── index.html │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── app.js │ │ ├── components │ │ │ ├── test.html │ │ │ └── test.js │ │ ├── main.js │ │ ├── router │ │ │ └── index.js │ │ ├── script │ │ │ ├── appImport.js │ │ │ ├── nf-indexedDB.config.js │ │ │ └── nf-indexedDB.js │ │ ├── store │ │ │ ├── index.js │ │ │ ├── map-form.js │ │ │ ├── map.js │ │ │ └── mutation-types.js │ │ └── views │ │ │ ├── component.html │ │ │ ├── component.js │ │ │ ├── home.js │ │ │ ├── look │ │ │ ├── index.html │ │ │ ├── index.js │ │ │ └── watch.js │ │ │ ├── reactive │ │ │ ├── check.html │ │ │ ├── check.js │ │ │ ├── index.html │ │ │ ├── index.js │ │ │ ├── let.html │ │ │ ├── let.js │ │ │ ├── markraw.js │ │ │ ├── person.js │ │ │ ├── proxy-reactive.js │ │ │ ├── proxy.js │ │ │ ├── reactive-shallow.js │ │ │ ├── reactive.js │ │ │ ├── readonly-shallow.js │ │ │ ├── readonly.js │ │ │ └── toraw.js │ │ │ ├── store.html │ │ │ └── store.js │ └── web.config ├── project-template │ ├── README.md │ ├── index.html │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── app.js │ │ ├── components │ │ │ ├── test.html │ │ │ └── test.js │ │ ├── main.js │ │ ├── router │ │ │ └── index.js │ │ ├── script │ │ │ └── appImport.js │ │ ├── store │ │ │ ├── index.js │ │ │ ├── map.js │ │ │ └── mutation-types.js │ │ └── views │ │ │ ├── About.html │ │ │ ├── About.js │ │ │ ├── component.html │ │ │ ├── component.js │ │ │ ├── home.js │ │ │ ├── store.html │ │ │ └── store.js │ └── web.config ├── project-vuex │ ├── README.md │ ├── a.html │ ├── demo.json │ ├── index.html │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── app.js │ │ ├── component │ │ │ ├── HelloWorld.vue │ │ │ ├── test.html │ │ │ └── test.js │ │ ├── main.js │ │ ├── router │ │ │ └── index.js │ │ ├── script │ │ │ ├── appImport.js │ │ │ └── myImport.js │ │ ├── store │ │ │ ├── index.js │ │ │ ├── map.js │ │ │ ├── map2.js │ │ │ ├── mutation-types.js │ │ │ └── user.js │ │ └── views │ │ │ ├── 01stateall.html │ │ │ ├── 01stateall.js │ │ │ ├── 02statemember.html │ │ │ ├── 02statemember.js │ │ │ ├── 03getter.html │ │ │ ├── 03getter.js │ │ │ ├── 04setter.html │ │ │ ├── 04setter.js │ │ │ ├── 05action.html │ │ │ ├── 05action.js │ │ │ ├── 06map.html │ │ │ ├── 06map.js │ │ │ ├── 06module.html │ │ │ ├── 06module.js │ │ │ └── home.js │ ├── vuex.vue │ └── web.config └── project │ ├── README.md │ ├── a.html │ ├── index.html │ ├── public │ └── favicon.ico │ ├── src │ ├── app.js │ ├── component │ │ ├── HelloWorld.vue │ │ └── test.js │ ├── main.js │ ├── router │ │ └── index.js │ ├── store │ │ └── index.js │ └── views │ │ ├── component.js │ │ ├── home.js │ │ └── state.js │ ├── vuex.vue │ └── web.config └── web.config /ES6/promise/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | permise的基本使用方法 9 | 10 | 11 |
12 | 演示一下promise的使用
13 |
14 |
15 |
16 | 请按F12,查看结果。 17 |
18 | 19 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 naturefwvue 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nf-vue-cnd 2 | 3 | 在线演示的项目的汇总,基本都是CDN模式的,这个做在线演示比较容易。 4 | 5 | ## cnd模式 6 | 7 | cnd模式下的一些小项目 8 | 9 | ### cnd/project-template (工程化模板) 10 | 11 | CDN 的工程化开发的模板。 12 | 从jQuery的思维转换到Vue工程化的思维的捷径。 13 | 不需要webpack、node、npm等,可以直接感受工程化带来的好处。 14 | 15 | 详细介绍: 16 | 17 | 在线演示: 18 | 19 | 20 | ### cnd/project-admin (管理后台) 21 | 22 | 尝试一下,使用CDN工程化的方式做管理后台。还在完善中。 23 | 24 | 详细内容: 25 | 26 | 27 | 在线演示: 28 | 29 | 30 | ### cnd/project (简单使用) 31 | 32 | CDN的基础使用方式。 33 | 34 | 详细内容: 35 | 36 | 37 | 在线演示: 38 | 39 | 40 | ### cnd/project-vuex (状态管理) 41 | 42 | Vuex状态管理相关的尝试 43 | 44 | 详细内容: 45 | 46 | 47 | 在线演示: 48 | 49 | 50 | ### cnd/project-axios (ajax和后端通信) 51 | 52 | axios相关的尝试 53 | 54 | 详细内容: 55 | 56 | 57 | 在线演示: 58 | 59 | 60 | ### cnd/init 61 | 62 | vue全家桶 + UI库的加载方式,以及简单的使用方式。 63 | 在线演示: 64 | 65 | 66 | ## ES6基础知识的尝试 67 | 68 | ES6 相关的一些演示代码 69 | 70 | ### ES6/promise 71 | 72 | promise 的简单封装 73 | 在线演示: 74 | 75 | -------------------------------------------------------------------------------- /cnd/LocalStore/IndexedDB/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 用Promise封装一下IndexedDB 8 | 9 | 10 | 11 |
12 | 测试功能 13 |
14 |
15 |
16 | IndexedDb的操作演示
17 |

18 |

19 |
20 |

21 | 22 |

23 |
24 |
25 |
26 | 27 | 28 |

29 |
30 | 31 |

32 |

33 |

34 |

35 | 36 |
37 |

38 | 39 |
40 |
41 | 查询结果:
42 |
46 | {{index}}--{{item}} 47 |
48 |
49 |
50 | 操作结果:
51 | {{re}} 52 |
53 |
54 |
55 | 全部数据: 56 |
57 |
63 | {{index}}--{{item}} 64 |
65 |
66 | 67 | 318 | 319 | 320 | -------------------------------------------------------------------------------- /cnd/LocalStore/IndexedDB/nf-indexedDB.config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | dbName: 'dbTest', 3 | ver: 1, 4 | debug: true, 5 | objectStores: [ // 建库依据 6 | { 7 | objectStoreName: 'blog', 8 | index: [ // 索引 , unique 是否可以重复 9 | { name: 'groupId', unique: false } 10 | ] 11 | } 12 | ], 13 | objects: { // 初始化数据 14 | blog: [ 15 | { 16 | id: 1, 17 | groupId: 1, 18 | title: '这是一个博客', 19 | addTime: '2020-10-15', 20 | introduction: '这是博客简介', 21 | concent: '这是博客的详细内容
第二行', 22 | viewCount: 1, 23 | agreeCount: 1 24 | }, 25 | { 26 | id: 2, 27 | groupId: 2, 28 | title: '这是两个博客', 29 | addTime: '2020-10-15', 30 | introduction: '这是博客简介', 31 | concent: '这是博客的详细内容
第二行', 32 | viewCount: 10, 33 | agreeCount: 10 34 | } 35 | ] 36 | } 37 | } 38 | 39 | export default config 40 | -------------------------------------------------------------------------------- /cnd/LocalStore/IndexedDB/新建文本文档 (2).txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/LocalStore/IndexedDB/新建文本文档 (2).txt -------------------------------------------------------------------------------- /cnd/LocalStore/IndexedDB/新建文本文档.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/LocalStore/IndexedDB/新建文本文档.txt -------------------------------------------------------------------------------- /cnd/Vue3Composition/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue3的Composition 的演示 8 | 9 | 10 | 11 |
12 | 目录 13 |
14 |
15 | reactive的演示

16 | ref的演示

17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /cnd/Vue3Composition/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/Vue3Composition/public/favicon.ico -------------------------------------------------------------------------------- /cnd/Vue3Composition/reactive.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue3 的 reactive 的演示 8 | 9 | 10 | 11 |
12 | reactive 的演示... 13 |
14 |
15 |
16 | person:{{person}}
17 | myReatReadonly:{{myReatReadonly}}
18 | myReatReadonly:{{myReatReadonly}}
19 | 20 |
21 | 22 | 52 | 53 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /cnd/Vue3Composition/ref.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue3 的 ref 的演示 8 | 9 | 10 | 11 |
12 | reactive 的演示... 13 |
14 |
15 |
16 | reactive:{{person}}
17 | name: {{name}}
18 |
19 | 20 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /cnd/caifumoni.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 模拟抖音里的一个模拟分配的方案 9 | 10 | 11 | 12 |
13 | 一百个人,每轮都要随机给另一个人一元钱。
14 |
15 |
16 | {{state}}
17 | 20 | 21 |
22 | 23 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /cnd/init/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CND的方式,安装各种js脚本 9 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | vuex状态演示
37 | $store - count:{{$store.state.count}}
38 | $store - myObject:{{$store.state.myObject}}
39 | $store - myObject.time:{{$store.state.myObject.time}}
40 | setup - count:{{count}}
41 | setup - obj :{{obj}}
42 | setup - objTime :{{objTime}}
43 | vuex的 计数
44 | vuex的 设置属性
45 |
46 | 47 | 数据绑定和UI库的演示
48 | {{value}}
49 | 50 |
51 | 52 | elemet的按钮
53 | 55 | 56 | vant的按钮
57 |
58 | 59 | 路由的演示
60 |
61 |

62 | 路由的简单演示,其实CND方式不太适合用路由,因为组件写起来比较麻烦。
63 | 64 | 65 | 66 | 首页    67 | 产品 68 |

69 | 70 | 71 | 路由入口
72 | 73 |
74 |
75 | 76 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /cnd/project-admin/README.md: -------------------------------------------------------------------------------- 1 | 2 | # CND 的工程化 方式做的管理后台 3 | 4 | 先做一个动态tab标签 5 | 6 | # 在线演示 7 | 8 | https://naturefwvue.github.io/nf-vue-cnd/cnd/project-admin 9 | -------------------------------------------------------------------------------- /cnd/project-admin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CDN模式下的管理后台 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 28 | 29 | 62 | 63 | 64 |
65 | 这里是CDN仿工程化开发的后台管理... 66 |
67 |
68 |
69 | 70 | 首页 (路由地址) | 在线演示的首页 (这里是真实地址) 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Footer 84 | 85 | 86 | 87 |
88 |
89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /cnd/project-admin/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project-admin/public/favicon.ico -------------------------------------------------------------------------------- /cnd/project-admin/src/app.js: -------------------------------------------------------------------------------- 1 | 2 | // import { Set_Count, Set_Count_sy } from './store/mutation-types.js' 3 | 4 | export default { 5 | name: 'app', 6 | components: { 7 | NavMenu: Vue.defineAsyncComponent(myImport('components/public/navMenu')), 8 | // NavMenu: Vue.defineAsyncComponent(() => import('./components/Public/navMenu.js')), 9 | nfTabs: Vue.defineAsyncComponent(() => myImport('components/Public/nfTabs')) 10 | }, 11 | setup() { 12 | console.log(myImport) 13 | const store = Vuex.useStore() 14 | 15 | const handleOpen = (key, keyPath) => { 16 | console.log(key, keyPath) 17 | } 18 | const handleClose = (key, keyPath) => { 19 | console.log(key, keyPath) 20 | } 21 | 22 | // 跳转到首页 23 | const router = VueRouter.useRouter() 24 | 25 | // 路由跳转 26 | router.push({ 27 | name: 'Home' 28 | }) 29 | return { 30 | handleOpen, 31 | handleClose 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/navMenu.html: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 20 | {{item.title}} 21 | 22 | 23 | 配置信息 24 | 25 | 26 | -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/navMenu.js: -------------------------------------------------------------------------------- 1 | const moduleList = { 2 | m100: { 3 | moduleId: 100, 4 | title: '关于我们' 5 | }, 6 | m102: { 7 | moduleId: 102, 8 | title: '增删改查一' 9 | }, 10 | m103: { 11 | moduleId: 103, 12 | title: '增删改查二' 13 | }, 14 | m104: { 15 | moduleId: 104, 16 | title: '权限管理' 17 | }, 18 | m105: { 19 | moduleId: 105, 20 | title: '组织架构' 21 | }, 22 | m106: { 23 | moduleId: 106, 24 | title: '员工管理' 25 | } 26 | } 27 | 28 | export default { 29 | name: 'NavMenu', 30 | template: '', 31 | props: { 32 | msg: String 33 | }, 34 | setup () { 35 | const store = Vuex.useStore() 36 | const router = VueRouter.useRouter() 37 | const tabs = store.state.actionManage.tabs 38 | 39 | console.log('router', router) 40 | 41 | const handleOpen = (key, keyPath) => { 42 | console.log(key, keyPath) 43 | } 44 | const handleClose = (key, keyPath) => { 45 | console.log(key, keyPath) 46 | } 47 | const handleSelect = (index, indexPath) => { 48 | console.log(typeof index) 49 | console.log(indexPath) 50 | console.log(tabs.filter((item) => item.id === index)) 51 | // 判断是否已经存在 52 | if (tabs.filter((item) => item.id === index).length === 0) { 53 | // 添加动态tab 54 | tabs.push({ 55 | id: index, 56 | title: moduleList['m' + index].title, 57 | name: moduleList['m' + index].title, 58 | content: '' 59 | }) 60 | } 61 | // 路由跳转 62 | router.push({ 63 | name: 'module', 64 | params: { moduleId: index } 65 | }) 66 | } 67 | 68 | return { 69 | moduleList, 70 | handleSelect, 71 | handleOpen, 72 | handleClose 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfButton.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 添加 5 | 6 | 修改 7 | 删除 8 | 查询 9 | 10 |
-------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfButton.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name:'button', 3 | template: '', 4 | setup () { 5 | const click = (btnId) => { 6 | console.log(btnId) 7 | } 8 | 9 | return { 10 | click 11 | } 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfFind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 查询 13 | 14 | -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfFind.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | name: 'find', 4 | template: '', 5 | setup () { 6 | const formInline = Vue.reactive({ 7 | user: '', 8 | region: '' 9 | }) 10 | 11 | const onSubmit = () => { 12 | console.log('submit!') 13 | } 14 | 15 | return { 16 | formInline, 17 | onSubmit 18 | } 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfForm.html: -------------------------------------------------------------------------------- 1 | 2 | 按钮s 3 | -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfForm.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | name: 'nfForm', 4 | template: '', 5 | setup () { 6 | const editableTabsValue = Vue.ref('2') 7 | 8 | return { 9 | editableTabsValue 10 | } 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfGrid.html: -------------------------------------------------------------------------------- 1 | 5 | 10 | 11 | 15 | 16 | 20 | 21 | 25 | 26 | 30 | 31 | 35 | 36 | -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfGrid.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | name: 'grid', 4 | template: '', 5 | setup () { 6 | const tableData = Vue.reactive([ 7 | { 8 | date: '2016-05-03', 9 | name: '王小虎', 10 | province: '上海', 11 | city: '普陀区', 12 | address: '上海市普陀区金沙江路 1518 弄', 13 | zip: 200333 14 | }, 15 | { 16 | date: '2016-05-02', 17 | name: '王小虎', 18 | province: '上海', 19 | city: '普陀区', 20 | address: '上海市普陀区金沙江路 1518 弄', 21 | zip: 200333 22 | }, 23 | { 24 | date: '2016-05-04', 25 | name: '王小虎', 26 | province: '上海', 27 | city: '普陀区', 28 | address: '上海市普陀区金沙江路 1518 弄', 29 | zip: 200333 30 | }, { 31 | date: '2016-05-01', 32 | name: '王小虎', 33 | province: '上海', 34 | city: '普陀区', 35 | address: '上海市普陀区金沙江路 1518 弄', 36 | zip: 200333 37 | }, { 38 | date: '2016-05-08', 39 | name: '王小虎', 40 | province: '上海', 41 | city: '普陀区', 42 | address: '上海市普陀区金沙江路 1518 弄', 43 | zip: 200333 44 | }, { 45 | date: '2016-05-06', 46 | name: '王小虎', 47 | province: '上海', 48 | city: '普陀区', 49 | address: '上海市普陀区金沙江路 1518 弄', 50 | zip: 200333 51 | }, { 52 | date: '2016-05-07', 53 | name: '王小虎', 54 | province: '上海', 55 | city: '普陀区', 56 | address: '上海市普陀区金沙江路 1518 弄', 57 | zip: 200333 58 | }]) 59 | 60 | return { 61 | tableData 62 | } 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfPager.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfPager.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | name: 'page', 4 | template: '', 5 | setup () { 6 | const currentPage = Vue.ref(2) 7 | const currentChange = (currPager) => { 8 | console.log('currPager', currPager) 9 | } 10 | return { 11 | currentPage, 12 | currentChange 13 | } 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfTabs.html: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /cnd/project-admin/src/components/public/nfTabs.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | name: 'nfTabs', 4 | template: '', 5 | setup () { 6 | const store = Vuex.useStore() 7 | 8 | const editableTabsValue = Vue.ref('2') 9 | const editableTabs = store.state.actionManage.tabs 10 | const tabIndex = Vue.ref(1) 11 | 12 | // 事件 13 | const addTab = (targetName) => { 14 | const newTabName = ++tabIndex.value + '' 15 | editableTabs.push({ 16 | title: 'New Tab', 17 | name: newTabName, 18 | content: 'New Tab content' 19 | }) 20 | this.editableTabsValue = newTabName 21 | } 22 | const removeTab = (targetName) => { 23 | const tabs = editableTabs 24 | let activeName = editableTabsValue.value 25 | if (activeName === targetName) { 26 | tabs.forEach((tab, index) => { 27 | if (tab.name === targetName) { 28 | const nextTab = tabs[index + 1] || tabs[index - 1] 29 | if (nextTab) { 30 | activeName = nextTab.name 31 | } 32 | } 33 | }) 34 | } 35 | 36 | editableTabsValue.value = activeName 37 | editableTabs.length = 0 38 | editableTabs.push(...tabs.filter(tab => tab.name !== targetName)) 39 | } 40 | 41 | return { 42 | editableTabsValue, 43 | editableTabs, 44 | tabIndex, 45 | addTab, 46 | removeTab 47 | } 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/components/test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 这是 组件测试
4 | 父组件传递参数:{{str}}
5 | setup 获取参数:{{str1}}
6 |
-------------------------------------------------------------------------------- /cnd/project-admin/src/components/test.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'component-test', 3 | template: '', 4 | props: { 5 | str: String 6 | }, 7 | setup(props) { 8 | // 在setup里面获取参数值 9 | let str1 = Vue.ref(props.str) 10 | str1.value += '--内部改一下。' 11 | 12 | return { 13 | str1 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | import store from './store/index.js?v=28' 3 | import router from './router/index.js?v=28' 4 | import App from './app.js?v=28' 5 | 6 | 7 | // 创建vue3的实例 8 | const app = Vue.createApp(App) 9 | .use(store) // 挂载vuex 10 | .use(router) // 挂载路由 11 | .use(ElementPlus) // 加载ElementPlus 12 | .mount('#app') // 挂载Vue的app实例 13 | 14 | */ 15 | 16 | const ver = window.__ver || '' 17 | 18 | Promise.all([ 19 | import('./store/index.js' + ver), 20 | import('./router/index.js' + ver), 21 | import('./app.js' + ver), 22 | ]).then((res) => { 23 | // 创建vue3的实例 24 | const app = Vue.createApp(res[2].default) 25 | .use(res[0].default) // 挂载vuex 26 | .use(res[1].default) // 挂载路由 27 | .use(ElementPlus, { size: 'small' }) // 加载ElementPlus 28 | .mount('#app') // 挂载Vue的app实例 29 | }) 30 | -------------------------------------------------------------------------------- /cnd/project-admin/src/router/index.js: -------------------------------------------------------------------------------- 1 | 2 | const routes = [ 3 | { 4 | path: '/', 5 | name: 'Home', 6 | // component: () => myImport('views/home') 7 | components: { 8 | default: () => myImport('views/home'), 9 | naveMenu: () => myImport('components/public/navMenu'), 10 | tabs: () => myImport('components/public/nfTabs') 11 | } 12 | 13 | }, 14 | { 15 | path: '/About', 16 | name: 'About', 17 | component: () => myImport('components/public/navMenu') 18 | }, 19 | { 20 | path: '/module/:moduleId', 21 | name: 'module', 22 | meta: { title: '列表页面' }, 23 | props: true, 24 | // component: () => myImport('views/packList'), 25 | components: { 26 | default: () => myImport('views/packList'), 27 | naveMenu: () => myImport('components/public/navMenu'), 28 | tabs: () => myImport('components/public/nfTabs') 29 | }, 30 | children: [ 31 | { 32 | path: 'btn/:moduleId', 33 | name: 'btn', 34 | props: true, 35 | meta: { title: '弹窗页面' }, 36 | component: () => myImport('views/home') 37 | } 38 | ] 39 | // components: { 40 | // default: () => import('../views/classical/question-main-introduce.vue'), 41 | // answerList: () => import('../views/classical/question-main-answers.vue') 42 | // } 43 | } 44 | ] 45 | 46 | const router = VueRouter.createRouter({ 47 | history: VueRouter.createWebHistory(), 48 | routes 49 | }) 50 | 51 | export default router 52 | -------------------------------------------------------------------------------- /cnd/project-admin/src/script/appImport.js: -------------------------------------------------------------------------------- 1 | // 直接放在Window里面好了。。。 2 | window.myImport = (url) => { 3 | return new Promise((resolve, reject) => { 4 | const ver = window.__ver || '' 5 | const baseUrl = window.__basrUrl || '/src/' 6 | // 先加载js 7 | import(baseUrl + url + '.js' + ver).then((resjs) => { 8 | const js = resjs.default 9 | if (typeof(js.template) === 'undefined' || js.template === '') { 10 | // 如果模板是空的,表示需要加载html作为模板 11 | axios.get(baseUrl + url + '.html' + ver).then((resHTML) => { 12 | js.template = resHTML.data 13 | resolve(js) 14 | }) 15 | } else { 16 | // 否则直接使用js注册组件 17 | resolve(js) 18 | } 19 | }) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /cnd/project-admin/src/store/actionManage.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 各个组件间的交互事件、状态传递 3 | */ 4 | 5 | const actionManage = { 6 | state: () => ({ 7 | // 当前状态集合 8 | currState: { 9 | pageIndex: 1 // 当前激活的分页列表的页号 10 | }, 11 | // tab标签集合 12 | tabs: [ 13 | { 14 | id: 1, 15 | title: '桌面', // tab的标题 16 | name: 'home' // tab的名称 17 | } 18 | ] 19 | // 组件数据集合 20 | }), 21 | mutations: { 22 | // 添加动态tab 23 | }, 24 | actions: { 25 | } 26 | } 27 | 28 | export default actionManage 29 | -------------------------------------------------------------------------------- /cnd/project-admin/src/store/index.js: -------------------------------------------------------------------------------- 1 | 2 | import actionManage from './actionManage.js' 3 | 4 | export default Vuex.createStore({ 5 | state: { 6 | }, 7 | mutations: { 8 | }, 9 | actions: { 10 | }, 11 | modules: { 12 | actionManage 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /cnd/project-admin/src/store/map.js: -------------------------------------------------------------------------------- 1 | 2 | const map = () => { 3 | const store = Vuex.useStore() 4 | 5 | /** 6 | * 获取count, 7 | * 用computed实现相应 8 | */ 9 | const getCount = () => { 10 | return Vue.computed(() => store.state.count) 11 | } 12 | 13 | /** 14 | * 获取count, 15 | ** 用 ref 实现相应 16 | */ 17 | const getRefCount = () => { 18 | return Vue.ref(store.state.count) 19 | } 20 | 21 | /** 22 | * 获取对象 23 | */ 24 | const getObject = () => { 25 | return store.state.myObject 26 | } 27 | 28 | /** 29 | * 获取只读对象 30 | */ 31 | const getReadonlyObject = () => { 32 | return Vue.readonly(store.state.myObject) 33 | } 34 | 35 | /** 36 | * 获取数组 37 | */ 38 | const getArray = () => { 39 | return store.state.myArray 40 | } 41 | /** 42 | * 获取只读数组 43 | */ 44 | const getReadonlyArray = () => { 45 | return Vue.readonly(store.state.myArray) 46 | } 47 | 48 | /** 49 | * 查询数组 50 | ** id:要查询的数据 51 | */ 52 | const filterArray = (id) => { 53 | return Vue.computed(() => store.getters.filterArray(id)) 54 | } 55 | 56 | return { 57 | getCount, 58 | getRefCount, 59 | getObject, 60 | getReadonlyObject, 61 | getArray, 62 | getReadonlyArray, 63 | filterArray 64 | } 65 | 66 | } 67 | 68 | export default map -------------------------------------------------------------------------------- /cnd/project-admin/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const Set_Count = 'set_count' 2 | export const Set_Count_sy = Symbol('set_count') 3 | -------------------------------------------------------------------------------- /cnd/project-admin/src/views/About.html: -------------------------------------------------------------------------------- 1 |
2 | 演示一下由路由加载的组件。
3 | html 和 js分开写的方式。
4 | 插值演示:{{value}}
5 |
6 | -------------------------------------------------------------------------------- /cnd/project-admin/src/views/About.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'About', 3 | template: '', 4 | setup () { 5 | const value = Vue.ref('数据绑定的演示') 6 | 7 | return { 8 | value 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /cnd/project-admin/src/views/component.html: -------------------------------------------------------------------------------- 1 |
2 | 演示一下组件里面使用组件的方式
3 | 4 |
5 | -------------------------------------------------------------------------------- /cnd/project-admin/src/views/component.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'template', 3 | template: ``, 4 | components: { 5 | test: Vue.defineAsyncComponent( 6 | () => myImport('components/test') 7 | ) 8 | }, 9 | setup () { 10 | const value = Vue.ref('传入组件的参数') 11 | return { 12 | value 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cnd/project-admin/src/views/home.js: -------------------------------------------------------------------------------- 1 | const { ref, reactive } = Vue 2 | 3 | const testManage = () => { 4 | const hello = ref('你好,世界') 5 | const clickMe = () => { 6 | hello.value = '好的,收到,现在时间:' + new Date() 7 | } 8 | 9 | return { 10 | hello, 11 | clickMe 12 | } 13 | } 14 | 15 | // vue3的对象 16 | export default { 17 | template: ` 18 |

我是 {{value.name}}

19 |
20 | 老规矩:{{hello}}
21 | 快点我
22 |
23 | 这里是一种CND的开发方式
24 | vue全家桶和UI库用 CND方式 加载。
25 | js代码用 import 方式加载。
26 | 目录结构参考了vue-cli建立的项目。
27 | 支持组件、路由、状态管理等功能。
28 | 不用webpack、npm等,建立网站就可以用。

29 | 状态计数:{{$store.state.count}} 30 |
31 | `, 32 | setup() { 33 | // 使用外面的定义,分解setup内部的代码 34 | const { hello, clickMe } = testManage() 35 | 36 | const value = reactive({ 37 | name: 'jyk' 38 | }) 39 | 40 | 41 | return { 42 | value, 43 | hello, 44 | clickMe 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /cnd/project-admin/src/views/packList.html: -------------------------------------------------------------------------------- 1 |  2 |
3 | 4 | {{moduleId}}
5 | 6 | 7 | 8 |
-------------------------------------------------------------------------------- /cnd/project-admin/src/views/packList.js: -------------------------------------------------------------------------------- 1 |  2 | export default { 3 | name: 'PackList', 4 | template: '', 5 | components: { 6 | nfButton: Vue.defineAsyncComponent( 7 | () => myImport('components/public/nfButton') 8 | ), 9 | nfFind: Vue.defineAsyncComponent( 10 | () => myImport('components/public/nfFind') 11 | ), 12 | nfPager: Vue.defineAsyncComponent( 13 | () => myImport('components/public/nfGrid') 14 | ), 15 | nfGrid: Vue.defineAsyncComponent( 16 | () => myImport('components/public/nfPager') 17 | ) 18 | }, 19 | props: { 20 | moduleId: Number 21 | }, 22 | setup () { 23 | const store = Vuex.useStore() 24 | const aa = store.state.actionManage.tabs 25 | 26 | console.log('aa', aa) 27 | } 28 | } -------------------------------------------------------------------------------- /cnd/project-admin/src/views/store.html: -------------------------------------------------------------------------------- 1 |
2 | 这里演示一下 vuex 的一些操作:
3 | 4 | ref的count :{{refCount}}
5 | 计算属性的Count :{{comCount}}
6 | 只读对象 :{{readonlyObject}}
7 | 8 |
-------------------------------------------------------------------------------- /cnd/project-admin/src/views/store.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 获取状态 4 | const indirectManage = () => { 5 | const store = Vuex.useStore() 6 | 7 | // 用toRef获取 count,有相应性,可以直接修改state 8 | const refCount = Vue.toRef(store.state, 'count') 9 | // 计算属性获取count,有相应性,不可以直接修改state 10 | const comCount = Vue.computed(() => store.state.count + 10) 11 | // 只读的对象,有响应性,浅层不可以修改,但是深层还是可以修改。 12 | const readonlyObject = Vue.readonly(store.state.myObject) 13 | 14 | console.log('refCount:', refCount) 15 | console.log('comCount:', comCount) 16 | console.log('readonlyObject:', readonlyObject) 17 | console.log('================') 18 | 19 | // 定时修改 count 看响应性 20 | setTimeout(() => { 21 | // store.commit('setCount') 22 | // refCount.value += 200 // 会直接改vuex的state 23 | }, 2000) 24 | 25 | return { 26 | refCount, 27 | comCount, 28 | readonlyObject 29 | } 30 | } 31 | 32 | 33 | export default { 34 | name: 'vuex_store', 35 | template: '', 36 | components: { 37 | }, 38 | setup () { 39 | const value = Vue.ref('状态管理的演示') 40 | 41 | // 获取状态 42 | const { refCount, comCount, readonlyObject } = indirectManage() 43 | 44 | return { 45 | value, 46 | refCount, comCount, readonlyObject 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cnd/project-admin/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /cnd/project-axios/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 演示一下axios的各种情况 3 | 4 | * get 5 | * post 6 | * 类型 7 | 8 | # 在线演示 9 | 10 | https://naturefwvue.github.io/nf-vue-cnd/cnd/project-axios 11 | -------------------------------------------------------------------------------- /cnd/project-axios/a.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project-axios/a.html -------------------------------------------------------------------------------- /cnd/project-axios/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | axios的尝试 8 | 9 | 10 | 11 | 12 | 13 |
14 | axios...1 15 |
16 |
17 |
18 | 19 |

20 |

21 | 22 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /cnd/project-axios/json.aspx: -------------------------------------------------------------------------------- 1 | { 2 | "company":{ 3 | "findMeta":{ 4 | "quickFind":[1010,1013,1005,1008], 5 | "allFind":[1000,1001,1002,1003,1009,1004,1005,1010,1006,1007,1012,1011,1008], 6 | "colCount":4, 7 | "customer":{ 8 | "100": { 9 | "name":"方案二", 10 | "keys":[1002,1003,1006] 11 | }, 12 | "101":{ 13 | "name":"方案三", 14 | "keys":[1007,1004,1010] 15 | } 16 | } 17 | }, 18 | "findItem":{ 19 | "1010":{ 20 | "controlId": "1010", 21 | "colName": "private,city,area,c1,c2,c3,c4,c5", 22 | "controlType": 200, 23 | "placeholder": "省市区", 24 | "title": "省市区", 25 | "level": 2, 26 | "optionKind": 2, 27 | "optionList": [ 28 | { "value": 1, "label": "浙江", "isLeaf": false }, 29 | { "value": 2, "label": "江苏", "isLeaf": false }, 30 | { "value": 3, "label": "辽宁", "isLeaf": false } 31 | ], 32 | "optionList2": [ 33 | { "parent": 1, "value": 11, "label": "杭州" }, 34 | { "parent": 1, "value": 12, "label": "宁波" }, 35 | { "parent": 1, "value": 13, "label": "温州" }, 36 | { "parent": 2, "value": 21, "label": "南京" }, 37 | { "parent": 2, "value": 22, "label": "无锡" }, 38 | { "parent": 3, "value": 31, "label": "沈阳" }, 39 | { "parent": 3, "value": 32, "label": "大连" } 40 | ], 41 | "tdCount":3 42 | }, 43 | "1012":{ 44 | "controlId": "1012", 45 | "colName": "education", 46 | "controlType": 183, 47 | "placeholder": "学历", 48 | "title": "学历", 49 | "optionList": [ 50 | { "value": 1, "label": "高中" }, 51 | { "value": 2, "label": "大专" }, 52 | { "value": 3, "label": "本科" }, 53 | { "value": 4, "label": "硕士" }, 54 | { "value": 5, "label": "博士" } 55 | ], 56 | "tdCount":3 57 | }, 58 | "1000":{ 59 | "controlId": 1000, 60 | "colName": "companyName", 61 | "controlType": 101, 62 | "class": "", 63 | "placeholder": "公司名称", 64 | "title": "公司名称", 65 | "size": 10, 66 | "maxlength": 100, 67 | "optionList": [], 68 | "findKind":"402", 69 | "findKindList": [401,403,402,404,405,406], 70 | "tdCount":1 71 | }, 72 | "1001":{ 73 | "controlId": 1001, 74 | "colName": "companyCode", 75 | "controlType": 131, 76 | "class": "", 77 | "placeholder": "公司邮编", 78 | "title": "公司邮编", 79 | "min": 100000, 80 | "max": 999999, 81 | "step": 1, 82 | "maxlength": 6, 83 | "optionList": [] , 84 | "findKind":"401", 85 | "findKindList": [411,417,412,431,413,414,415,416], 86 | "tdCount":1 87 | }, 88 | "1002":{ 89 | "controlId": 1002, 90 | "colName": "legalPerson", 91 | "controlType": 101, 92 | "class": "", 93 | "placeholder": "法人姓名", 94 | "title": "法人", 95 | "autocomplete": "on", 96 | "size": 10, 97 | "maxlength": 50, 98 | "optionList": [] , 99 | "findKind":"403", 100 | "findKindList": [401,403,402,404,405,406], 101 | "tdCount":1 102 | }, 103 | "1003":{ 104 | "controlId": 1003, 105 | "colName": "liaisonMan", 106 | "controlType": 101, 107 | "class": "", 108 | "placeholder": "联系人姓名", 109 | "title": "联系人", 110 | "size": 10, 111 | "maxlength": 50, 112 | "optionList": [], 113 | "findKind":"404", 114 | "findKindList": [401,403,402,404,405,406], 115 | "tdCount":1 116 | }, 117 | "1004": { 118 | "controlId": "1004", 119 | "colName": "address", 120 | "controlType": 101, 121 | "class": "", 122 | "placeholder": "公司地址", 123 | "title": "公司地址", 124 | "size": 10, 125 | "maxlength": 50, 126 | "optionKey": "", 127 | "optionList": [], 128 | "findKind":"405", 129 | "findKindList": [401,403,402,404,405,406], 130 | "tdCount":1 131 | }, 132 | "1005": { 133 | "controlId": "1005", 134 | "colName": "telphone", 135 | "controlType": 103, 136 | "placeholder": "公司电话", 137 | "title": "公司电话", 138 | "size": 10, 139 | "maxlength": 50, 140 | "optionKey": "", 141 | "optionList": [], 142 | "findKind":"401,402", 143 | "findKindList": [401,403,402,404,405,406], 144 | "tdCount":1 145 | }, 146 | "1006": { 147 | "controlId": "1006", 148 | "colName": "URL", 149 | "controlType": 105, 150 | "class": "", 151 | "placeholder": "公司网址", 152 | "title": "公司网址", 153 | "autocomplete": "on", 154 | "size": 10, 155 | "maxlength": 50, 156 | "optionKey": "", 157 | "optionList": [], 158 | "findKind":"401,402", 159 | "findKindList": [401,403,402,404,405,406], 160 | "tdCount":1 161 | }, 162 | "1007": { 163 | "controlId": "1007", 164 | "colName": "Email", 165 | "controlType": 104, 166 | "class": "", 167 | "placeholder": "公司邮件", 168 | "title": "公司邮件", 169 | "size": 10, 170 | "maxlength": 50, 171 | "optionKey": "", 172 | "optionList": [], 173 | "findKind":"402", 174 | "findKindList": [401,403,402,404,405,406], 175 | "tdCount":1 176 | }, 177 | "1008": { 178 | "controlId": 1008, 179 | "colName": "type", 180 | "title": "公司类型", 181 | "controlType": 190, 182 | "placeholder": "公司类型", 183 | "class": "", 184 | "optionList": [ 185 | { "value": 1, "title": "有限责任公司" }, 186 | { "value": 2, "title": "股份有限责任公司" }, 187 | { "value": 3, "title": "个人独资企业" }, 188 | { "value": 4, "title": "合伙企业" }, 189 | { "value": 5, "title": "个体工商户" } 190 | ], 191 | "findKind":"401", 192 | "findKindList": ["401","402"], 193 | "tdCount":1 194 | }, 195 | "1009": { 196 | "controlId": 1009, 197 | "colName": "createDate", 198 | "controlType": 141, 199 | "class": "", 200 | "title": "成立日期", 201 | "placeholder": "成立日期", 202 | "min": "1950-01-01", 203 | "max": "2999-12-31", 204 | "step": 1, 205 | "findKind":"423", 206 | "findKindList": [421,427,422,423,424,425,426], 207 | "tdCount":3 208 | }, 209 | "1013": { 210 | "controlId": 1013, 211 | "colName": "createTime", 212 | "controlType": 149, 213 | "class": "", 214 | "title": "成立时间", 215 | "placeholder": "成立时间", 216 | "min": "1950-01-01", 217 | "max": "2999-12-31", 218 | "step": 1, 219 | "findKind":"423", 220 | "findKindList": [421,427,422,423,424,425,426], 221 | "tdCount":3 222 | }, 223 | "1011":{ 224 | "controlId": 1011, 225 | "colName": "hobby", 226 | "controlType": 182, 227 | "isClear": true, 228 | "disabled": false, 229 | "required": true, 230 | "readonly": false, 231 | "pattern": "", 232 | "class": "", 233 | "title": "爱好", 234 | "optionList": [ 235 | { "value": 1, "label": "篮球" }, 236 | { "value": 2, "label": "足球" }, 237 | { "value": 3, "label": "排球" } 238 | ], 239 | "tdCount":3 240 | } 241 | } 242 | }, 243 | "person":{ 244 | "findMeta":{ 245 | "quickFind":[2000,2001,2002,2003], 246 | "allFind":[2000,2001,2002,2003,2004,2005], 247 | "colCount":4, 248 | "customer":{ 249 | "200": { 250 | "name":"方案一", 251 | "keys":[2000,2004,2005] 252 | }, 253 | "201":{ 254 | "name":"方案二", 255 | "keys":[2002,2004,2005] 256 | } 257 | } 258 | }, 259 | "findItem":{ 260 | "2000":{ 261 | "controlId": 100, 262 | "colName": "personId", 263 | "controlType": 101, 264 | "class": "", 265 | "placeholder": "工号", 266 | "title": "工号", 267 | "size": 10, 268 | "maxlength": 10, 269 | "optionList": [], 270 | "tdCount":1 271 | }, 272 | "2001":{ 273 | "controlId": "2001", 274 | "colName": "personName", 275 | "controlType": 101, 276 | "isClear": true, 277 | "disabled": false, 278 | "required": true, 279 | "readonly": false, 280 | "pattern": "", 281 | "class": "", 282 | "placeholder": "员工姓名", 283 | "title": "姓名", 284 | "autocomplete": "on", 285 | "size": 10, 286 | "maxlength": "50", 287 | "tdCount":1 288 | }, 289 | "2002": { 290 | "controlId": 2002, 291 | "colName": "Gender", 292 | "controlType": 183, 293 | "isClear": true, 294 | "disabled": false, 295 | "required": true, 296 | "readonly": false, 297 | "pattern": "", 298 | "class": "", 299 | "title": "性别", 300 | "optionList": [ 301 | { "value": "男", "title": "男" }, 302 | { "value": "女", "title": "女" } 303 | ], 304 | "tdCount":3 305 | }, 306 | "2003":{ 307 | "controlId": "2012", 308 | "colName": "nation", 309 | "controlType": 106, 310 | "isClear": true, 311 | "disabled": false, 312 | "required": true, 313 | "readonly": false, 314 | "pattern": "", 315 | "class": "", 316 | "placeholder": "员工姓名", 317 | "title": "民族", 318 | "optionKey": "minzu", 319 | "optionList": [ 320 | { "value": 1, "title": "汉" }, 321 | { "value": 2, "title": "蒙古" }, 322 | { "value": 3, "title": "满族" }, 323 | { "value": 4, "title": "回族" }, 324 | { "value": 5, "title": "朝鲜" } 325 | ] 326 | }, 327 | "2004":{ 328 | "controlId": "2012", 329 | "colName": "education", 330 | "controlType": 190, 331 | "isClear": true, 332 | "disabled": false, 333 | "required": true, 334 | "readonly": false, 335 | "pattern": "", 336 | "class": "", 337 | "placeholder": "学历", 338 | "title": "学历", 339 | "optionList": [ 340 | { "value": 1, "title": "高中" }, 341 | { "value": 2, "title": "大专" }, 342 | { "value": 3, "title": "本科" }, 343 | { "value": 4, "title": "硕士" }, 344 | { "value": 5, "title": "博士" } 345 | ], 346 | "tdCount":1 347 | }, 348 | "2005":{ 349 | "controlId": 100, 350 | "colName": "hobby", 351 | "controlType": 182, 352 | "isClear": true, 353 | "disabled": false, 354 | "required": true, 355 | "readonly": false, 356 | "pattern": "", 357 | "class": "", 358 | "title": "爱好", 359 | "optionList": [ 360 | { "value": 1, "title": "篮球" }, 361 | { "value": 2, "title": "足球" }, 362 | { "value": 3, "title": "排球" } 363 | ], 364 | "tdCount":3 365 | } 366 | } 367 | } 368 | } -------------------------------------------------------------------------------- /cnd/project-axios/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project-axios/public/favicon.ico -------------------------------------------------------------------------------- /cnd/project-axios/src/app.js: -------------------------------------------------------------------------------- 1 | 2 | // vue3的对象 3 | const App = { 4 | setup() { // 传说中的setup 5 | 6 | const store = Vuex.useStore() 7 | // 状态的控制事件 8 | const setCount = () =>{ 9 | store.commit('setCount') 10 | } 11 | 12 | return { // 返回给模板,否则模板访问不到。 13 | setCount 14 | } 15 | } 16 | } 17 | 18 | export default App 19 | -------------------------------------------------------------------------------- /cnd/project-axios/src/component/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /cnd/project-axios/src/component/test.js: -------------------------------------------------------------------------------- 1 | const test = { 2 | template: ` 3 | 这是 组件测试
4 | 参数:{{str1}}
5 | `, 6 | model: { 7 | prop: ['str'] 8 | }, 9 | props: { 10 | str: String 11 | }, 12 | setup(props) { 13 | // 在setup里面获取参数值 14 | const str1 = Vue.ref(props.str) 15 | 16 | return { 17 | str1 18 | } 19 | } 20 | } 21 | 22 | export default test -------------------------------------------------------------------------------- /cnd/project-axios/src/main.js: -------------------------------------------------------------------------------- 1 | import store from './store/index.js?v=6' 2 | import router from './router/index.js?v=8' 3 | import App from './app.js?v=6' 4 | 5 | // 创建vue3的实例 6 | const app = Vue.createApp(App) 7 | .use(store) // 挂载vuex 8 | .use(router) // 挂载路由 9 | .use(ElementPlus) // 加载ElementPlus 10 | .mount('#app') // 挂载Vue的app实例 11 | 12 | -------------------------------------------------------------------------------- /cnd/project-axios/src/router/index.js: -------------------------------------------------------------------------------- 1 | // import Home from '../views/home.js?v=2' 2 | 3 | const routes = [ 4 | { 5 | path: '/', 6 | name: 'Home', 7 | component: () => import('../views/home.js?v=8') 8 | }, 9 | { 10 | path: '/state', 11 | name: 'state', 12 | component: () => import('../views/state.js?v=8') 13 | }, 14 | { 15 | path: '/component', 16 | name: 'component', 17 | component: () => import('../views/component.js?v=8') 18 | } 19 | ] 20 | 21 | const router = VueRouter.createRouter({ 22 | history: VueRouter.createWebHistory(), 23 | routes 24 | }) 25 | 26 | export default router 27 | -------------------------------------------------------------------------------- /cnd/project-axios/src/store/index.js: -------------------------------------------------------------------------------- 1 | 2 | export default Vuex.createStore({ 3 | state: { 4 | count: 0, 5 | myObject: { 6 | time: '现在的时间' 7 | } 8 | }, 9 | getters: { 10 | getCount: (state) => { 11 | return state.count 12 | }, 13 | getMyObject: (state) => { 14 | return Vue.readonly(state.myObject) 15 | }, 16 | getTime: (state) => { 17 | return state.myObject.time 18 | } 19 | }, 20 | mutations: { 21 | setCount(state) { 22 | state.count++ 23 | }, 24 | setTime(state) { 25 | state.myObject.time = '现在时间:' + new Date() 26 | } 27 | }, 28 | actions: { 29 | }, 30 | modules: { 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /cnd/project-axios/src/views/component.js: -------------------------------------------------------------------------------- 1 | // 引入组件 2 | import test from '../component/test.js?v=7' 3 | 4 | const demo = { 5 | template: ` 6 |

这是组件演示

7 | 8 | `, 9 | components: { 10 | test 11 | }, 12 | setup() { 13 | 14 | return { 15 | } 16 | } 17 | } 18 | 19 | export default demo -------------------------------------------------------------------------------- /cnd/project-axios/src/views/home.js: -------------------------------------------------------------------------------- 1 | 2 | const testManage = () => { 3 | const hello = Vue.ref('你好,世界') 4 | const clickMe = () => { 5 | hello.value = '好的,收到' + new Date().valueOf() 6 | } 7 | 8 | return { 9 | hello, 10 | clickMe 11 | } 12 | } 13 | 14 | // vue3的对象 15 | const home = { 16 | template: ` 17 |

这是home

18 |
19 | 我是{{value.name}}。
20 | 老规矩:{{hello}}
21 |

22 | 本项目采用“混合”模式开发,            
23 | vue全家桶和UI库用script标签加载。
24 | 代码用import方式加载。              
25 | 目录结构参考了cli建立的项目。         
26 | 支持组件、路由、状态管理等功能。 
27 | 状态计数:{{$store.state.count}}    28 |
29 | `, 30 | setup() { // 传说中的setup 31 | // 使用外面的定义,分解setup内部的代码 32 | const { hello, clickMe } = testManage() 33 | 34 | const value = Vue.reactive({ 35 | name: 'jyk' 36 | }) 37 | 38 | 39 | return { 40 | value, 41 | hello, 42 | clickMe 43 | } 44 | } 45 | } 46 | 47 | export default home -------------------------------------------------------------------------------- /cnd/project-axios/src/views/state.js: -------------------------------------------------------------------------------- 1 | // vue3的对象 2 | const demo = { 3 | template: ` 4 |

这里是状态演示

5 | setup 里面的 count:{{count}}
6 | `, 7 | setup() { // 传说中的setup 8 | const store = Vuex.useStore() 9 | // 在代码里面获取状态 10 | const count = Vue.computed(() => store.getters.getCount) 11 | 12 | return { 13 | count 14 | } 15 | } 16 | } 17 | 18 | export default demo -------------------------------------------------------------------------------- /cnd/project-axios/vuex.vue: -------------------------------------------------------------------------------- 1 |  15 | 16 | 82 | -------------------------------------------------------------------------------- /cnd/project-axios/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 演示一下 vue3 的响应性和composition API 3 | 4 | * vue3 的 reactive 5 | * vue3 的 ref 6 | * vue3 的 监听和计算属性 7 | * vue3 的 composition API 8 | 9 | 在线演示: 10 | https://naturefwvue.github.io/nf-vue-cnd/cnd/project-compositionapi 11 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue3的 响应式 和 Composition API 的演示 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 31 | 32 | 58 | 77 | 78 | 79 | 92 |
93 | 108 |
109 | 110 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project-compositionapi/public/favicon.ico -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/app.js: -------------------------------------------------------------------------------- 1 | 2 | // import { Set_Count, Set_Count_sy } from './store/mutation-types.js' 3 | 4 | export default { 5 | name: 'app', 6 | setup() { 7 | const store = Vuex.useStore() 8 | 9 | // 状态的控制事件 10 | const setCount = () =>{ 11 | store.commit('setCount') 12 | store.commit('setTime') 13 | store.commit('setArray') 14 | // store._mutations.setCount[0] // 这是什么? 15 | } 16 | 17 | return { 18 | // 设置state 19 | setCount 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/components/test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 这是 组件测试
4 | 父组件传递参数:{{str}}
5 | setup 获取参数:{{str1}}
6 |
-------------------------------------------------------------------------------- /cnd/project-compositionapi/src/components/test.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'component-test', 3 | template: '', 4 | props: { 5 | str: String, 6 | obj: Object 7 | }, 8 | setup(props) { 9 | // 在setup里面获取参数值 10 | let str1 = Vue.ref(props.str) 11 | str1.value += '--内部改一下。' 12 | console.log('组件属性——props:', props) 13 | console.log('组件属性——obj:', props.obj) 14 | console.log('组件属性——props:', Vue.isReadonly(props)) 15 | console.log('组件属性——obj:', Vue.isReadonly(props.obj)) 16 | 17 | return { 18 | str1 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | import store from './store/index.js?v=28' 3 | import router from './router/index.js?v=28' 4 | import App from './app.js?v=28' 5 | 6 | 7 | // 创建vue3的实例 8 | const app = Vue.createApp(App) 9 | .use(store) // 挂载vuex 10 | .use(router) // 挂载路由 11 | .use(ElementPlus) // 加载ElementPlus 12 | .mount('#app') // 挂载Vue的app实例 13 | 14 | */ 15 | 16 | const ver = window.__ver || '' 17 | 18 | Promise.all([ 19 | import('./store/index.js' + ver), 20 | import('./router/index.js' + ver), 21 | import('./app.js' + ver), 22 | ]).then((res) => { 23 | // 创建vue3的实例 24 | const app = Vue.createApp(res[2].default) 25 | .use(res[0].default) // 挂载vuex 26 | .use(res[1].default) // 挂载路由 27 | .use(ElementPlus) // 加载ElementPlus 28 | .mount('#app') // 挂载Vue的app实例 29 | }) 30 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/router/index.js: -------------------------------------------------------------------------------- 1 | 2 | const routes = [ 3 | { 4 | path: '/', 5 | name: 'Home', 6 | component: () => myImport('views/home') 7 | }, 8 | { 9 | path: '/reactive', /** reactive 的导航页面 */ 10 | name: 'reactive', 11 | component: () => myImport('views/reactive/index'), 12 | children: [ 13 | { // es6的Proxy 14 | path: 'proxy', 15 | name: 'ret-proxy', 16 | component: () => myImport('views/reactive/proxy') 17 | }, 18 | { // 用Proxy套个娃 19 | path: 'proxy', 20 | name: 'ret-proxy-reactive', 21 | component: () => myImport('views/reactive/proxy-reactive') 22 | }, 23 | { // reactive 响应式 24 | path: 'reactive', 25 | name: 'ret-reactive', 26 | component: () => myImport('views/reactive/reactive') 27 | }, 28 | { // shallowReactive 响应式 29 | path: 'shallowReactive', 30 | name: 'ret-reactive-shallow', 31 | component: () => myImport('views/reactive/reactive-shallow') 32 | }, 33 | { // readonly 只读 34 | path: 'readonly', 35 | name: 'ret-readonly', 36 | component: () => myImport('views/reactive/readonly') 37 | }, 38 | { // shallowReadonly 只读 39 | path: 'shallowReadonly', 40 | name: 'ret-readonly-shallow', 41 | component: () => myImport('views/reactive/readonly-shallow') 42 | }, 43 | { // toRaw 44 | path: 'toRaw', 45 | name: 'ret-toRaw', 46 | component: () => myImport('views/reactive/toraw') 47 | }, 48 | { // toRaw 49 | path: 'MarkRaw', 50 | name: 'ret-MarkRaw', 51 | component: () => myImport('views/reactive/markraw') 52 | }, 53 | { 54 | path: 'let', 55 | name: 'ret-let', 56 | component: () => myImport('views/reactive/let') 57 | }, 58 | { // 验证对象类型 59 | path: 'check', 60 | name: 'ret-check', 61 | component: () => myImport('views/reactive/check') 62 | } 63 | 64 | ] 65 | }, 66 | { 67 | path: '/ref', 68 | name: 'ref', 69 | component: () => myImport('views/component') 70 | }, 71 | { 72 | path: '/look', 73 | name: 'look', 74 | component: () => myImport('views/look/index'), 75 | children: [ 76 | { // es6的Proxy 77 | path: 'watch', 78 | name: 'look-watch', 79 | component: () => myImport('views/look/watch') 80 | } 81 | ] 82 | }, 83 | { 84 | path: '/store', 85 | name: 'store', 86 | component: () => myImport('views/store') 87 | } 88 | ] 89 | 90 | const router = VueRouter.createRouter({ 91 | history: VueRouter.createWebHistory(), 92 | routes 93 | }) 94 | 95 | export default router 96 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/script/appImport.js: -------------------------------------------------------------------------------- 1 | // 直接放在Window里面好了。。。 2 | window.myImport = (url) => { 3 | return new Promise((resolve, reject) => { 4 | const ver = window.__ver || '' 5 | const baseUrl = window.__basrUrl || '/src/' 6 | // 先加载js 7 | import(baseUrl + url + '.js' + ver).then((resjs) => { 8 | const js = resjs.default 9 | if (js.template === '') { 10 | // 如果模板是空的,表示需要加载html作为模板 11 | axios.get(baseUrl + url + '.html' + ver).then((resHTML) => { 12 | js.template = resHTML.data 13 | resolve(js) 14 | }) 15 | } else { 16 | // 否则直接使用js注册组件 17 | resolve(js) 18 | } 19 | }) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/script/nf-indexedDB.config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | dbName: 'dbTest-reactive', 3 | ver: 1, 4 | debug: true, 5 | objectStores: [ // 建库依据 6 | { 7 | objectStoreName: 'reactive' 8 | } 9 | ] 10 | } 11 | 12 | export default config 13 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/store/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { Set_Count } from './mutation-types.js' 3 | 4 | export default Vuex.createStore({ 5 | state: { 6 | // 表单弹窗的状态 7 | formState: { 8 | editState: 'add', // 编辑状态,add:添加;update:修改;show :只读显示 9 | id: 0, // 0:添加;其他:要修改或者显示的数据的ID 10 | isOpen: false, // 是否打开弹窗(模态) 11 | model: {} // 这里只是演示异步加载,实际项目中并不适合这么做 12 | } 13 | }, 14 | mutations: { 15 | // 改变表单弹窗的状态 16 | setFormState(state, form) { 17 | // 可以设置单独的属性,这里偷懒了。 18 | Object.assign(state.formState, form) 19 | } 20 | }, 21 | modules: { 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/store/map-form.js: -------------------------------------------------------------------------------- 1 | const mapForm = () => { 2 | const store = Vuex.useStore() 3 | const readonly = Vue.readonly 4 | 5 | // 返回可读可写的表单弹窗状态 6 | const formState = () => { 7 | return store.state.formState 8 | } 9 | 10 | // 返回只读的表单弹窗状态 11 | const getFormState = () => { 12 | return readonly(store.state.formState) 13 | } 14 | 15 | // 打开弹窗 16 | const openForm = () =>{ 17 | store.commit('setFormState', { isOpen: true}) 18 | } 19 | 20 | // 打开弹窗 21 | const closeForm = () =>{ 22 | store.commit('setFormState', { isOpen: false}) 23 | } 24 | 25 | // 设置添加数据 26 | const addData = () =>{ 27 | store.commit('setFormState', { 28 | isOpen: true, 29 | id: 0, 30 | editState: 'add' 31 | }) 32 | } 33 | 34 | // 设置修改状态 35 | const updateData = (id) =>{ 36 | store.commit('setFormState', { 37 | isOpen: true, 38 | id: id, 39 | editState: 'update' 40 | }) 41 | } 42 | 43 | // 设置只读状态 44 | const showData = (id) =>{ 45 | store.commit('setFormState', { 46 | isOpen: true, 47 | id: id, 48 | editState: 'show' 49 | }) 50 | } 51 | 52 | // 异步获取数据 53 | const loadData = (id) =>{ 54 | return new Promise((resolve, reject) => { 55 | setTimeout(() => { 56 | store.commit('setFormState', { 57 | model: { 58 | title: '假装异步获取了数据' 59 | } 60 | }) 61 | resolve('成功了!') 62 | }, 1000); 63 | }) 64 | 65 | } 66 | 67 | return { 68 | formState, // 可读写状态 69 | getFormState, // 只读状态 70 | openForm, // 打开弹窗 71 | closeForm, // 关闭弹窗 72 | addData, // 添加新纪录并且打开弹窗 73 | updateData, // 修改记录并且打开弹窗 74 | showData, // 显示数据并且打开弹窗 75 | loadData // 异步加载数据 76 | } 77 | 78 | } 79 | 80 | export default mapForm -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/store/map.js: -------------------------------------------------------------------------------- 1 | 2 | const map = () => { 3 | const store = Vuex.useStore() 4 | 5 | /** 6 | * 获取count, 7 | * 用computed实现相应 8 | */ 9 | const getCount = () => { 10 | return Vue.computed(() => store.state.count) 11 | } 12 | 13 | /** 14 | * 获取count, 15 | ** 用 ref 实现相应 16 | */ 17 | const getRefCount = () => { 18 | return Vue.ref(store.state.count) 19 | } 20 | 21 | /** 22 | * 获取对象 23 | */ 24 | const getObject = () => { 25 | return store.state.myObject 26 | } 27 | 28 | /** 29 | * 获取只读对象 30 | */ 31 | const getReadonlyObject = () => { 32 | return Vue.readonly(store.state.myObject) 33 | } 34 | 35 | /** 36 | * 获取数组 37 | */ 38 | const getArray = () => { 39 | return store.state.myArray 40 | } 41 | /** 42 | * 获取只读数组 43 | */ 44 | const getReadonlyArray = () => { 45 | return Vue.readonly(store.state.myArray) 46 | } 47 | 48 | /** 49 | * 查询数组 50 | ** id:要查询的数据 51 | */ 52 | const filterArray = (id) => { 53 | return Vue.computed(() => store.getters.filterArray(id)) 54 | } 55 | 56 | return { 57 | getCount, 58 | getRefCount, 59 | getObject, 60 | getReadonlyObject, 61 | getArray, 62 | getReadonlyArray, 63 | filterArray 64 | } 65 | 66 | } 67 | 68 | export default map -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const Set_Count = 'set_count' 2 | export const Set_Count_sy = Symbol('set_count') 3 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/component.html: -------------------------------------------------------------------------------- 1 |
2 | 演示一下组件里面使用组件的方式
3 | 4 |
5 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/component.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'template', 3 | template: ``, 4 | components: { 5 | test: Vue.defineAsyncComponent( 6 | () => myImport('components/test') 7 | ) 8 | }, 9 | setup () { 10 | const value = Vue.ref('传入组件的参数') 11 | return { 12 | value 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/home.js: -------------------------------------------------------------------------------- 1 | const { ref, reactive } = Vue 2 | 3 | const testManage = () => { 4 | const hello = ref('你好,世界') 5 | const clickMe = () => { 6 | hello.value = '好的,收到,现在时间:' + new Date() 7 | } 8 | 9 | return { 10 | hello, 11 | clickMe 12 | } 13 | } 14 | 15 | // vue3的对象 16 | export default { 17 | template: ` 18 |

我是 {{value.name}}

19 |
20 | 老规矩:{{hello}}
21 | 快点我
22 |
23 | 这里演示 Vue3 的 响应式 和 composition API 的各种用法 24 |
25 | `, 26 | setup() { 27 | // 使用外面的定义,分解setup内部的代码 28 | const { hello, clickMe } = testManage() 29 | 30 | const value = reactive({ 31 | name: 'jyk' 32 | }) 33 | 34 | 35 | return { 36 | value, 37 | hello, 38 | clickMe 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/look/index.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | watch

5 | 6 |
7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/look/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * 监听和计算属性 5 | */ 6 | export default { 7 | name: 'look', 8 | template: '', 9 | setup () { 10 | const value = Vue.ref('数据绑定的演示') 11 | 12 | return { 13 | value 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/look/watch.js: -------------------------------------------------------------------------------- 1 | const watch = Vue.watch 2 | 3 | import { person, personReactive, objectReactive } from '../reactive/person.js' 4 | 5 | /** 6 | * watch 监听 7 | * 8 | */ 9 | export default { 10 | name: 'watch-watch', 11 | template: ` 12 |
13 | 展示 watch
14 | js 对象:{{ personReactive }}

15 | 16 | 修改属性

17 |
18 | `, 19 | setup () { 20 | // 查看 reactive 实例结构 21 | console.log('reactive', personReactive) 22 | // 获取嵌套对象属性 23 | 24 | // 监听属性 25 | watch(() =>  personReactive.name, (v1,v2) => { 26 | console.log('name改变了', v1) 27 | }) 28 | 29 | // 监听对象 30 | watch(() =>  personReactive, (v1,v2) => { 31 | console.log('改变了', v1) 32 | }, 33 | { 34 | deep:true 35 | }) 36 | 37 | const update = () => { 38 | personReactive.name = '改变' + Math.random() 39 | personReactive.contacts.QQ = Math.random() 40 | } 41 | 42 | return { 43 | person, // js对象 44 | personReactive, // perosn 套上 reactive 45 | objectReactive, // {} 套上 reactive 46 | update // 修改属性 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/check.html: -------------------------------------------------------------------------------- 1 |
2 | 验证类型函数
3 | 4 | 待验证类型 5 | isProxy 6 | isReactive 7 | isReadonly 8 | 9 | 10 | object 11 | {{obj.check1}} 12 | {{obj.check2}} 13 | {{obj.check3}} 14 | 15 | 16 | 自定义Proxy (object) 17 | {{myproxy.check1}} 18 | {{myproxy.check2}} 19 | {{myproxy.check3}} 20 | 21 | 22 | 自定义Proxy (Reactive) 23 | {{myproxyReactive.check1}} 24 | {{myproxyReactive.check2}} 25 | {{myproxyReactive.check3}} 26 | 27 | 28 | 29 | reactive (object) 30 | {{reto.check1}} 31 | {{reto.check2}} 32 | {{reto.check3}} 33 | 34 | 41 | 42 | 43 | shallowReactive (object) 44 | {{shallowRetObj.check1}} 45 | {{shallowRetObj.check2}} 46 | {{shallowRetObj.check3}} 47 | 48 | 49 | shallowReactive (Reactive) 50 | {{shallowRetRet.check1}} 51 | {{shallowRetRet.check2}} 52 | {{shallowRetRet.check3}} 53 | 54 | 55 | 56 | readonly (object) 57 | {{readObj.check1}} 58 | {{readObj.check2}} 59 | {{readObj.check3}} 60 | 61 | 62 | readonly (Reactive) 63 | {{readRet.check1}} 64 | {{readRet.check2}} 65 | {{readRet.check3}} 66 | 67 | 68 | 69 | shallowReadonly (object) 70 | {{shallowReadObj.check1}} 71 | {{shallowReadObj.check2}} 72 | {{shallowReadObj.check3}} 73 | 74 | 75 | shallowReadonly (Reactive) 76 | {{shallowReadRet.check1}} 77 | {{shallowReadRet.check2}} 78 | {{shallowReadRet.check3}} 79 | 80 | 81 |
82 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/check.js: -------------------------------------------------------------------------------- 1 | const isProxy = Vue.isProxy 2 | const isReactive = Vue.isReactive 3 | const isReadonly = Vue.isReadonly 4 | const toRaw = Vue.toRaw 5 | 6 | import { 7 | person, // object 对象 8 | personReactive, // object 的 reactive 代理 9 | // 深层读写 10 | objectReactive, // reactive (object) 11 | // 浅层读写 12 | objectShallowReactive, // 浅层 代理 13 | // 浅层 reactive 的读写 14 | retShallowReactive, 15 | // 浅层只读 16 | objectShallowReadonly, // 浅层只读 object 17 | reactiveShallowReadonly, // 浅层只读 reactive 18 | // 深层只读 19 | objectReadonly , // 深层只读 object 20 | reactiveReadonly // 深层只读 reactive 21 | } from './person.js?v=1' 22 | 23 | const myProxy = (obj) => { 24 | const pp = new Proxy(obj, { 25 | get: function (target, key, receiver) { 26 | if (typeof key !== 'symbol') { 27 | console.log(`getting ${key}!`, target[key]) 28 | } else { 29 | console.log('getting symbol:', key, target[key]) 30 | } 31 | return Reflect.get(target, key, receiver) 32 | }, 33 | set: function (target, key, value, receiver) { 34 | console.log(`setting ${key}:${value}!`) 35 | return Reflect.set(target, key, value, receiver) 36 | } 37 | }) 38 | return pp 39 | } 40 | 41 | /** 42 | * 验证类型 43 | * isPoxy、isReactive、isReadonly做对比测试 44 | */ 45 | export default { 46 | name: 'reactive-check', 47 | template: ``, 48 | setup () { 49 | 50 | const myProxyObject = myProxy({title:'222', __v_isReactive: true}) 51 | console.log('myProxyObject', myProxyObject) 52 | const myProxyReactive = myProxy(objectReactive) 53 | console.log('myProxyReactive', myProxyReactive) 54 | 55 | // 试一试 __v_isReadonly 56 | console.log('objectReactive', objectReactive) 57 | console.log('__v_isReadonly' 58 | , objectReactive.__v_isReadonly 59 | , objectReactive.__v_isReactive 60 | ) 61 | 62 | // 取原型 63 | const raw = toRaw(myProxyReactive) 64 | console.log('自己定义的Proxy取原型', raw) 65 | 66 | return { 67 | obj: { // js对象 68 | check1: isProxy(person), 69 | check2: isReactive(person), 70 | check3: isReadonly(person) 71 | }, 72 | myproxy: { // 自己定义的Proxy object 73 | check1: isProxy(myProxyObject), 74 | check2: isReactive(myProxyObject), 75 | check3: isReadonly(myProxyObject) 76 | }, 77 | myproxyReactive: { // 自己定义的Proxy reactive 78 | check1: isProxy(myProxyReactive), 79 | check2: isReactive(myProxyReactive), 80 | check3: isReadonly(myProxyReactive) 81 | }, 82 | // 深层响应 reactive(object) 83 | reto: { // reactive(object) 84 | check1: isProxy(objectReactive), 85 | check2: isReactive(objectReactive), 86 | check3: isReadonly(objectReactive) 87 | }, 88 | // 浅层响应 参数:object 89 | shallowRetObj: { 90 | check1: isProxy(objectShallowReactive), 91 | check2: isReactive(objectShallowReactive), 92 | check3: isReadonly(objectShallowReactive) 93 | }, 94 | // 浅层响应 参数:reactive 95 | shallowRetRet: { 96 | check1: isProxy(retShallowReactive), 97 | check2: isReactive(retShallowReactive), 98 | check3: isReadonly(retShallowReactive) 99 | }, 100 | 101 | // 深层只读,参数 object ======================= 102 | readObj: { // readonly object 103 | check1: isProxy(objectReadonly), 104 | check2: isReactive(objectReadonly), 105 | check3: isReadonly(objectReadonly) 106 | }, 107 | // 深层只读,参数 reactive 108 | readRet: { // readonly reactive 109 | check1: isProxy(reactiveReadonly), 110 | check2: isReactive(reactiveReadonly), 111 | check3: isReadonly(reactiveReadonly) 112 | }, 113 | // 浅层只读 参数:object 114 | shallowReadObj: { 115 | check1: isProxy(objectShallowReadonly), 116 | check2: isReactive(objectShallowReadonly), 117 | check3: isReadonly(objectShallowReadonly) 118 | }, 119 | // 浅层只读 参数:reactive 120 | shallowReadRet: { 121 | check1: isProxy(reactiveShallowReadonly), 122 | check2: isReactive(reactiveShallowReadonly), 123 | check3: isReadonly(reactiveShallowReadonly) 124 | }, 125 | person 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/index.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | ES6的Proxy

5 | 用Proxy套个娃

6 | reactive

7 | shallowReactive

8 | MarkRaw

9 | readonly

10 | shallowReadonly

11 | toRaw取原型

12 | 判断类型

13 | 响应性测试

14 | 15 |
16 | 17 | 18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * reactive的导航页面 4 | * 1、定义reactive看效果 5 | * 2、只读模式 6 | * 3、类型判断 7 | * 4、响应性测试 8 | */ 9 | export default { 10 | name: 'reactive', 11 | template: '', 12 | setup () { 13 | const value = Vue.ref('数据绑定的演示') 14 | 15 | return { 16 | value 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/let.html: -------------------------------------------------------------------------------- 1 |
2 | 展示reactive的定义 3 |
4 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/let.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'About', 3 | template: '', 4 | setup () { 5 | const value = Vue.ref('数据绑定的演示') 6 | 7 | return { 8 | value 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/markraw.js: -------------------------------------------------------------------------------- 1 | const reactive = Vue.reactive 2 | const markRaw = Vue.markRaw 3 | 4 | const testmarkRaw = () => { 5 | // js对象 6 | const object = markRaw({ 7 | name: 'jyk', 8 | age: 18, 9 | contacts: { 10 | QQ: 11111, 11 | phone: 123456789 12 | } 13 | }) 14 | 15 | // reactive的对象 16 | const retObject1 = reactive({ 17 | name: object.name 18 | }) 19 | 20 | const retObject2 = reactive(object) 21 | 22 | return { 23 | object, 24 | retObject1, 25 | retObject2 26 | } 27 | } 28 | 29 | /** 30 | * MarkRaw 做个标记,不响应。 31 | * 自己定义一个Proxy,看看效果 32 | */ 33 | export default { 34 | name: 'reactive-Proxy', 35 | components: { 36 | test: Vue.defineAsyncComponent(() => myImport('components/test')) 37 | }, 38 | template: ` 39 |
40 | markRaw 标记
41 | retObject1:{{retObject1}}

42 | 11 43 | 修改状态 44 |
45 | `, 46 | setup () { 47 | const { 48 | object, 49 | retObject1, 50 | retObject2 51 | } = testmarkRaw() 52 | 53 | console.log('作为初始值:', retObject1) 54 | console.log('无法变成响应式:', retObject2) 55 | 56 | // 修改数据 57 | const update = () => { 58 | // 新增属性 59 | // myProxyReactive['new'] = '这是一个新属性' + Math.random() 60 | } 61 | 62 | return { 63 | object, 64 | retObject1, 65 | retObject2, 66 | update 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/person.js: -------------------------------------------------------------------------------- 1 | 2 | const reactive = Vue.reactive 3 | const shallowReactive = Vue.shallowReactive 4 | const readonly = Vue.readonly 5 | const shallowReadonly = Vue.shallowReadonly 6 | 7 | /** 8 | * 普通js对象的 person 9 | */ 10 | export const person = { 11 | name: 'jyk', 12 | age: 18, 13 | contacts: { 14 | QQ: 11111, 15 | phone: 123456789 16 | } 17 | } 18 | 19 | /** 20 | * person 的 reactive 代理 21 | */ 22 | export const personReactive = reactive(person) 23 | 24 | /** 25 | * js对象的 reactive 响应式代理 26 | */ 27 | export const objectReactive = reactive({ 28 | name: 'jykReactive', 29 | age: 18, 30 | contacts: { 31 | QQ: 11111, 32 | phone: 123456789 33 | } 34 | }) 35 | 36 | /** 37 | * js对象的 shallowReactive 响应式代理 38 | */ 39 | export const objectShallowReactive = shallowReactive({ 40 | name: 'jykShallowReactive', 41 | age: 18, 42 | contacts: { 43 | QQ: 11111, 44 | phone: 123456789 45 | } 46 | }) 47 | 48 | /** 49 | * reactive 的 shallowReactive 响应式代理 50 | */ 51 | export const retShallowReactive = shallowReactive(objectReactive) 52 | 53 | // ================================================ 54 | 55 | /** 56 | * person 的 readonly 代理 57 | */ 58 | export const objectReadonly = readonly(person) 59 | 60 | /** 61 | * reactive 的 readonly 代理 62 | */ 63 | export const reactiveReadonly = readonly(objectReactive) 64 | 65 | /** 66 | * person 的 shallowReadonly 响应式代理 67 | */ 68 | export const objectShallowReadonly = shallowReadonly(person) 69 | 70 | /** 71 | * reactive 的 shallowReadonly 响应式代理 72 | */ 73 | export const reactiveShallowReadonly = shallowReadonly(objectReactive) 74 | 75 | // ================================================ 76 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/proxy-reactive.js: -------------------------------------------------------------------------------- 1 | const reactive = Vue.reactive 2 | const watch = Vue.watch 3 | 4 | const test = () => { 5 | // js对象 6 | const object = { 7 | name: 'jyk', 8 | age: 18, 9 | contacts: { 10 | QQ: 11111, 11 | phone: 123456789 12 | } 13 | } 14 | 15 | // reactive的对象 16 | const retObject = reactive({ 17 | name: 'jyk', 18 | age: 18, 19 | contacts: { 20 | QQ: 11111, 21 | phone: 123456789 22 | } 23 | }) 24 | 25 | /** 26 | * 用Proxy定义一个 reactive 的套娃,实现可以监听任意属性变化的目的 27 | * @param {*} _target 要拦截的目标 28 | * @param {*} callback 属性变化后的回调函数 29 | */ 30 | const myReactive = (_target, callback) => { 31 | let _change = (key, value) => {console.log('内部函数')} 32 | const proxy = new Proxy(_target, { 33 | get: function (target, key, receiver) { 34 | if (typeof key !== 'symbol') { 35 | console.log(`getting ${key}!`, target[key]) 36 | } else { 37 | console.log('getting symbol:', key, target[key]) 38 | } 39 | // 调用原型方法 40 | return Reflect.get(target, key, receiver) 41 | }, 42 | set: function (target, key, value, receiver) { 43 | console.log(`setting ${key}:${value}!`) 44 | // 源头监听 45 | if (typeof callback === 'function') { 46 | callback(key, value) 47 | } 48 | // 任意位置监听 49 | if (typeof _target.__watch === 'function') { 50 | _change(key, value) 51 | } 52 | // 调用原型方法 53 | return Reflect.set(target, key, value, target) 54 | } 55 | }) 56 | // 实现任意位置的监听, 57 | proxy.__watch = (callback) => { 58 | if (typeof callback === 'function') { 59 | _change = callback 60 | } 61 | } 62 | // 返回实例 63 | return proxy 64 | } 65 | 66 | const myProxy = (_target) => { 67 | const proxy = new Proxy(_target, { 68 | get: function (target, key, receiver) { 69 | console.log(`getting ${key}:`, target[key]) 70 | // 调用原型方法 71 | return Reflect.get(target, key, receiver) 72 | }, 73 | set: function (target, key, value, receiver) { 74 | console.log(`setting ${key}:${value}!`) 75 | // 调用原型方法 76 | return Reflect.set(target, key, value, receiver) 77 | } 78 | }) 79 | // 返回实例 80 | return proxy 81 | } 82 | 83 | return { 84 | object, 85 | retObject, 86 | myReactive, 87 | myProxy 88 | } 89 | } 90 | 91 | /** 92 | * ES6的Proxy 93 | * 自己定义一个Proxy,看看效果 94 | */ 95 | export default { 96 | name: 'reactive-Proxy', 97 | template: ` 98 |
99 | 用 Proxy 给reactive 套个娃看看效果
100 | 拦截reactive的myProxy:{{myProxyReactive}}

101 | 修改状态 102 |
103 | `, 104 | setup () { 105 | const { 106 | object, 107 | retObject, 108 | myReactive, 109 | myProxy 110 | } = test() 111 | 112 | console.log('object', object) 113 | console.log('retObject', retObject) 114 | 115 | // 定义一个拦截普通对象的Proxy 116 | const myProxyObject = myReactive(object, ((key, value) =>{ 117 | console.log(`obj外部获得通知:${key}:${value}`) 118 | })) 119 | console.log('myProxyObject', myProxyObject) 120 | 121 | // 定义一个拦截reactive的Proxy 122 | // 并且实现源头的监听 123 | const myProxyReactive = myReactive(retObject, 124 | ((key, value) =>{ 125 | console.log(`ret外部获得通知:${key}:${value}`) 126 | }) 127 | ) 128 | console.log('myProxyReactive', myProxyReactive) 129 | 130 | // 任意位置的监听 131 | myProxyReactive.__watch((key, value) => { 132 | console.log(`任意位置的监听:${key}:${value}`) 133 | }) 134 | 135 | // 定义自己写的Proxy 136 | const testProxy = myProxy({ 137 | name: 'jyk', 138 | age: 18 139 | }) 140 | console.log('自己定义的Proxy实例:') 141 | console.log(testProxy) 142 | 143 | // 测试拦截情况 144 | testProxy.name = '新的名字' 145 | console.log(testProxy.name) 146 | 147 | // 深度监听 148 | watch(() => retObject, (v1, v2) => { 149 | console.log('监听属性', v1, v2) 150 | },{ 151 | deep: true // 深度监听 152 | }) 153 | 154 | // 修改数据 155 | const update = () => { 156 | // retObject.name = 'reactive修改name' 157 | retObject['newprops'] = '新增一个属性:' + Math.random() 158 | myProxyReactive.name = '自定义的拦截修改name' + Math.random() 159 | myProxyReactive.contacts.QQ = 123456 160 | // 新增属性 161 | // myProxyReactive['new'] = '这是一个新属性' + Math.random() 162 | } 163 | 164 | return { 165 | object, 166 | retObject, 167 | myProxyObject, 168 | myProxyReactive, 169 | update 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/proxy.js: -------------------------------------------------------------------------------- 1 | 2 | const test = () => { 3 | // js对象 4 | const object = { 5 | name: 'jyk', 6 | age: 18, 7 | contacts: { 8 | QQ: 11111, 9 | phone: 123456789 10 | } 11 | } 12 | 13 | /** 14 | * 模仿reactive,定义一个Proxy实例,观察拦截情况 15 | * @param {*} _target 原型对象 16 | */ 17 | const myProxy = (_target) => { 18 | const proxy = new Proxy(_target, { 19 | get: function (target, key, receiver) { 20 | console.log('getting',key, ':', target[key]) 21 | // 调用原型方法 22 | return Reflect.get(target, key, receiver) 23 | }, 24 | set: function (target, key, value, receiver) { 25 | console.log(`setting ${key} : ${value}`) 26 | // 调用原型方法 27 | return Reflect.set(target, key, value, receiver) 28 | } 29 | }) 30 | // 返回实例 31 | return proxy 32 | } 33 | 34 | return { 35 | object, 36 | myProxy 37 | } 38 | } 39 | 40 | /** 41 | * ES6的Proxy 42 | * 自己定义一个Proxy,看看效果 43 | */ 44 | export default { 45 | name: 'es6-Proxy', 46 | template: ` 47 |
48 | ES6的proxy
49 | 自己定义的myProxy:{{testProxy}}

50 | 修改状态 51 |
52 | `, 53 | setup () { 54 | const { 55 | object, 56 | myProxy 57 | } = test() 58 | 59 | console.log('object', object) 60 | 61 | // 定义自己写的Proxy 62 | const testProxy = myProxy({ 63 | name: 'jyk', 64 | age: 18, 65 | contacts: { 66 | QQ: 11111, 67 | phone: 123456789 68 | } 69 | }) 70 | console.log('自己定义的Proxy实例:') 71 | console.log(testProxy) 72 | 73 | // 测试拦截情况 74 | testProxy.name = '新的名字' 75 | console.log(testProxy.name) 76 | 77 | // 伪造一个reactive,看看toRaw好用不。 78 | const raw = Vue.toRaw(Vue.toRaw(myProxy({name: 'jyk',__v_isReactive: true}))) 79 | console.log('伪装成reactive 的raw11', raw) 80 | 81 | // 修改数据 82 | const update = () => { 83 | // retObject.name = 'reactive修改name' 84 | testProxy['newprops'] = '新增一个属性:' + Math.random() 85 | testProxy.name = '自定义的拦截修改name' + Math.random() 86 | testProxy.contacts.QQ = 123456 87 | // 新增属性 88 | // myProxyReactive['new'] = '这是一个新属性' + Math.random() 89 | } 90 | 91 | return { 92 | object, 93 | testProxy, 94 | update 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/reactive-shallow.js: -------------------------------------------------------------------------------- 1 | 2 | import { person, objectShallowReactive } from './person.js' 3 | 4 | /** 5 | * 定义 shallowReactive 6 | */ 7 | export default { 8 | name: 'reactive-shallowReactive', 9 | template: ` 10 |
11 | 展示 shallowReactive
12 | shallowReactive 对象:{{objectShallowReactive}}

13 | shallowReactive 的name属性:{{objectShallowReactive.name}} (有响应)

14 | shallowReactive 的contacts属性 的 QQ属性:{{objectShallowReactive.contacts.QQ}} (没有相应)

15 | 16 | 单独的 name:{{name}} (没有相应)

17 | 单独的 contacts:{{contacts}} (没有响应)

18 | 19 | 修改属性 20 |
21 | `, 22 | setup () { 23 | // 查看 shallowReactive 实例结构 24 | console.log('shallowReactive', objectShallowReactive) 25 | // 获取嵌套对象属性 26 | const contacts = objectShallowReactive.contacts 27 | // 因为浅层,所以没有响应性 28 | console.log('contacts属性:', contacts) 29 | // 获取简单类型的属性 30 | let name = objectShallowReactive.name 31 | // 属性是简单类型的,所以失去响应性 32 | console.log('name属性:', name) 33 | 34 | const update = () => { 35 | // 修改原型 36 | person.name = '修改原型的name' + Math.random() 37 | 38 | // 修改属性 39 | objectShallowReactive.name = '设置代理的name属性' // + Math.random() 40 | objectShallowReactive.contacts.QQ = 123 + Math.random() 41 | 42 | // 修改结构的属性 43 | name = '设置解构的name属性' + Math.random() 44 | contacts.QQ = 123 + Math.random() 45 | } 46 | 47 | return { 48 | person, // js对象 49 | objectShallowReactive, // perosn 套上 reactive 50 | name, // 结构的name属性 51 | contacts, // 结构的对象属性 52 | update // 修改属性 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/reactive.js: -------------------------------------------------------------------------------- 1 | const reactive = Vue.reactive 2 | 3 | import { person, personReactive, objectReactive } from './person.js' 4 | 5 | /** 6 | * reactive 的结构 7 | * 属性的深层响应性 8 | * 9 | */ 10 | export default { 11 | name: 'reactive-reactive', 12 | template: ` 13 |
14 | 展示 reactive
15 | js 对象:{{person}}

16 | reactive 对象:{{objectReactive}}

17 | reactive 的name属性:{{objectReactive.name}}

18 | reactive 的contacts属性 的 QQ属性:{{objectReactive.contacts.QQ}}

19 | 20 | 单独的 name:{{name}} (没有相应)

21 | 单独的 contacts:{{contacts}} (有响应)

22 | 23 | reactive 数组:{{reactiveArray}}

24 | 25 | 修改属性

26 | 整体赋值

27 |
28 | `, 29 | setup () { 30 | // 查看 reactive 实例结构 31 | console.log('reactive', personReactive) 32 | // 获取嵌套对象属性 33 | const contacts = personReactive.contacts 34 | console.log('contacts属性:', contacts) // 因为深层响应,所以依然有响应性 35 | // 获取简单类型的属性 36 | let name = personReactive.name 37 | console.log('name属性:', name) // 属性是简单类型的,所以失去响应性 38 | 39 | // js对象 40 | console.log('person', person) 41 | 42 | // reactive 的数组 43 | const reactiveArray = reactive([ 44 | { 45 | name: 'jyk', 46 | age: 18 47 | }, 48 | { 49 | name: 'jyk111', 50 | age: 19 51 | } 52 | ]) 53 | 54 | const update = () => { 55 | // 修改原型 56 | person.name = '修改原型的name' + Math.random() 57 | 58 | // 修改 person 的代理 属性 59 | personReactive.name = '修改person代理的name属性' + Math.random() 60 | 61 | // 修改属性 62 | objectReactive.name = '设置代理的name属性' + Math.random() 63 | objectReactive.contacts.QQ = 123 + Math.random() 64 | 65 | // 修改结构的属性 66 | name = '设置解构的name属性' + Math.random() 67 | contacts.QQ = 123 + Math.random() 68 | // retArray 69 | // console.log('现在的person', person) 70 | } 71 | 72 | const setReactive = () => { 73 | // 直接赋值 74 | Object.assign(objectReactive, {name: '合并', age: 111, newp: '新属性'}) 75 | // reactiveArray.length = 0 // 容易照成闪烁 76 | setTimeout(() => { 77 | const newArray = [ 78 | { name: '11', age: 18 }, 79 | { name: '22', age: 18 }, 80 | { name: '33', age: 18 } 81 | ] 82 | // 可以防止闪烁 83 | reactiveArray.length = 0 84 | reactiveArray.push(...newArray) 85 | }, 1000); 86 | } 87 | 88 | return { 89 | person, // js对象 90 | personReactive, // perosn 套上 reactive 91 | objectReactive, // {} 套上 reactive 92 | name, // 结构的name属性 93 | contacts, // 结构的对象属性 94 | reactiveArray, // 数组的响应性 95 | update, // 修改属性 96 | setReactive // 直接设置 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/readonly-shallow.js: -------------------------------------------------------------------------------- 1 | import { 2 | person, // object 对象 3 | objectReactive, // 普通的 object 的 reactive 代理 4 | objectShallowReadonly, // reactive 的 readonly 代理 5 | reactiveShallowReadonly // 普通的 object 的 readonly 代理 6 | } from './person.js' 7 | 8 | /** 9 | * 定义 shallowReadonly 10 | * 11 | */ 12 | export default { 13 | name: 'reactive-shallowReadonly', 14 | template: ` 15 |
16 | 展示 shallowReadonly
17 | object 的只读代理:{{objectShallowReadonly}}

18 | reactive 的 只读代理:{{reactiveShallowReadonly}}

19 | reactive 对象:{{objectReactive}}

20 | 21 | 修改属性 22 |
23 | `, 24 | setup () { 25 | // 查看 readonly 实例结构 26 | console.log('object 的 objectShallowReadonly') 27 | console.log(objectShallowReadonly) 28 | console.log('reactive 的 reactiveShallowReadonly') 29 | console.log(reactiveShallowReadonly) 30 | 31 | // 修改数据 32 | const update = () => { 33 | 34 | } 35 | 36 | return { 37 | objectShallowReadonly, 38 | reactiveShallowReadonly, 39 | objectReactive, 40 | update 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/readonly.js: -------------------------------------------------------------------------------- 1 | 2 | import { 3 | person, // object 对象 4 | objectReactive, // object 的 reactive 代理 5 | reactiveReadonly, // reactive 的 readonly 代理 6 | objectReadonly // object 的 readonly 代理 7 | } from './person.js' 8 | 9 | /** 10 | * 展示 readonly 11 | * 12 | */ 13 | export default { 14 | name: 'reactive-readonly', 15 | template: ` 16 |
17 | 展示 readonly
18 | js 对象的只读代理:{{objectReadonly}}

19 | reactive 的 只读代理:{{reactiveReadonly}}

20 | reactive 对象:{{objectReactive}}

21 | 22 | 修改属性 23 |
24 | `, 25 | setup () { 26 | // 查看 readonly 实例结构 27 | console.log('object 的readonly') 28 | console.log(objectReadonly) 29 | console.log('reactive 的readonly') 30 | console.log(reactiveReadonly) 31 | 32 | // 获取嵌套对象属性 33 | const contacts = reactiveReadonly.contacts 34 | console.log('contacts属性:', contacts) // 因为深层响应,所以依然有响应性 35 | // 获取简单类型的属性 36 | let name = reactiveReadonly.name 37 | console.log('name属性:', name) // 属性是简单类型的,所以失去响应性 38 | 39 | // 修改数据 40 | const update = () => { 41 | // 可以影响readonlyObject.name的值,但是模板不会刷新 42 | person.name = '修改对象原型的name' 43 | // 不会修改,有警告 44 | objectReadonly.name = '改只读纯对象的name' 45 | // 不会修改,有警告 46 | objectReadonly.contacts.QQ = 1232222 47 | // 不会修改,有警告 48 | reactiveReadonly.name = '改只读reactive的name' 49 | // 不会修改,有警告 50 | reactiveReadonly.contacts.QQ = 345 51 | // 可以修改 readonly代理的值,并且可以更新模板 52 | person.name = '改原型reactive的name' 53 | // 可以修改 readonly代理的值,并且可以更新模板 54 | person.contacts.QQ = 789 55 | 56 | } 57 | 58 | return { 59 | person, 60 | objectReactive, 61 | reactiveReadonly, 62 | objectReadonly, 63 | update 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/reactive/toraw.js: -------------------------------------------------------------------------------- 1 | const toRaw = Vue.toRaw 2 | 3 | import { 4 | person, // object 对象 5 | objectReactive, // 普通的 object 的 reactive 代理 6 | objectShallowReactive, // reactive 的 shallowReactive 代理 7 | objectReadonly, // 普通的 object 的 readonly 代理 8 | objectShallowReadonly 9 | } from './person.js' 10 | 11 | import indexedDB from '../../script/nf-indexedDB.js' 12 | 13 | /** 14 | * toRaw 取原型 15 | * 序列化 16 | * 存储 17 | */ 18 | export default { 19 | name: 'reactive-toRaw', 20 | template: ` 21 |
22 | 展示 toRaw
23 | 24 | 修改属性 25 | 26 |
27 | `, 28 | setup () { 29 | 30 | const { setup, addObject} = indexedDB() 31 | 32 | console.log('reacive 的原型', toRaw(objectReactive)) 33 | console.log('shallowReactive 的原型', toRaw(objectShallowReactive)) 34 | console.log('readonly 的原型', toRaw(objectReadonly)) 35 | console.log('shallowReadonly 的原型', toRaw(objectShallowReadonly)) 36 | 37 | // 转为json 38 | const json1 = JSON.stringify(person) 39 | console.log('json1', json1) 40 | const json2 = JSON.stringify(toRaw(objectReactive)) 41 | console.log('json2', json2) 42 | const json3 = JSON.stringify(objectReactive) 43 | console.log('json3', json3) 44 | 45 | // 保存到 46 | const update = () => { 47 | const storage = window.sessionStorage 48 | //写入 reactive 49 | storage['test-reactive'] = objectReactive 50 | storage['test-json'] = json3 51 | // 直接存入 indexedDB会报错 52 | // addObject('reactive', objectReactive) 53 | // 存入原型 54 | addObject('reactive', toRaw(objectReactive)) 55 | 56 | } 57 | 58 | return { 59 | objectReactive, 60 | objectReadonly, 61 | update 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/store.html: -------------------------------------------------------------------------------- 1 |
2 | 这里演示一下 vuex 的一些操作:
3 | 4 | ref的count :{{refCount}}
5 | 计算属性的Count :{{comCount}}
6 | 只读对象 :{{readonlyObject}}
7 | 8 |
-------------------------------------------------------------------------------- /cnd/project-compositionapi/src/views/store.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 获取状态 4 | const indirectManage = () => { 5 | const store = Vuex.useStore() 6 | 7 | // 用toRef获取 count,有相应性,可以直接修改state 8 | const refCount = Vue.toRef(store.state, 'count') 9 | // 计算属性获取count,有相应性,不可以直接修改state 10 | const comCount = Vue.computed(() => store.state.count + 10) 11 | // 只读的对象,有响应性,浅层不可以修改,但是深层还是可以修改。 12 | const readonlyObject = Vue.readonly(store.state.myObject) 13 | 14 | console.log('refCount:', refCount) 15 | console.log('comCount:', comCount) 16 | console.log('readonlyObject:', readonlyObject) 17 | console.log('================') 18 | 19 | // 定时修改 count 看响应性 20 | setTimeout(() => { 21 | // store.commit('setCount') 22 | // refCount.value += 200 // 会直接改vuex的state 23 | }, 2000) 24 | 25 | return { 26 | refCount, 27 | comCount, 28 | readonlyObject 29 | } 30 | } 31 | 32 | 33 | export default { 34 | name: 'vuex_store', 35 | template: '', 36 | components: { 37 | }, 38 | setup () { 39 | const value = Vue.ref('状态管理的演示') 40 | 41 | // 获取状态 42 | const { refCount, comCount, readonlyObject } = indirectManage() 43 | 44 | return { 45 | value, 46 | refCount, comCount, readonlyObject 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cnd/project-compositionapi/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /cnd/project-template/README.md: -------------------------------------------------------------------------------- 1 | 2 | # CND 的工程化开发的模板 3 | 4 | * vue的全家桶和UI库采用CDN方式加载。 5 | * 支持路由,Router。 6 | * 支持状态管理,Vuex。 7 | * 支持UI库: element-plus、ant Design Vue,其他的没测试。 8 | * 支持axios。 9 | * 采用工程化的目录结构和代码编写方式。 10 | * vue文件需要拆分成 html 文件 + js 文件的方式。 11 | * 用版本号更新浏览器的js文件的缓存。 12 | 13 | # 特点 14 | 15 | * 建立网站即可运行,不需要安装、打包。 16 | * 不需要webpack 17 | * 不需要node_modules 文件夹 18 | * jQuery的风格,可以断点跟踪调试 19 | 20 | 在线演示: 21 | https://naturefwvue.github.io/nf-vue-cnd/cnd/project-template 22 | -------------------------------------------------------------------------------- /cnd/project-template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CDN模式下的工程化开发的模板 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 28 | 29 | 48 | 49 | 50 |
51 | 这里是CDN仿工程化开发的模板... 如果你没看到“首页”的内容,说明网页没有在网站的更目录。 52 |
53 |
54 | 66 |
67 |
68 | vuex状态演示
69 | $store.state :{{$store.state}}
70 | 71 | 更改状态
72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /cnd/project-template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project-template/public/favicon.ico -------------------------------------------------------------------------------- /cnd/project-template/src/app.js: -------------------------------------------------------------------------------- 1 | 2 | // import { Set_Count, Set_Count_sy } from './store/mutation-types.js' 3 | 4 | export default { 5 | name: 'app', 6 | setup() { 7 | const store = Vuex.useStore() 8 | 9 | // 状态的控制事件 10 | const setCount = () =>{ 11 | store.commit('setCount') 12 | store.commit('setTime') 13 | store.commit('setArray') 14 | // store._mutations.setCount[0] // 这是什么? 15 | } 16 | 17 | return { 18 | // 设置state 19 | setCount 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /cnd/project-template/src/components/test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 这是 组件测试
4 | 父组件传递参数:{{str}}
5 | setup 获取参数:{{str1}}
6 |
-------------------------------------------------------------------------------- /cnd/project-template/src/components/test.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'component-test', 3 | template: '', 4 | props: { 5 | str: String 6 | }, 7 | setup(props) { 8 | // 在setup里面获取参数值 9 | let str1 = Vue.ref(props.str) 10 | str1.value += '--内部改一下。' 11 | 12 | return { 13 | str1 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /cnd/project-template/src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | import store from './store/index.js?v=28' 3 | import router from './router/index.js?v=28' 4 | import App from './app.js?v=28' 5 | 6 | 7 | // 创建vue3的实例 8 | const app = Vue.createApp(App) 9 | .use(store) // 挂载vuex 10 | .use(router) // 挂载路由 11 | .use(ElementPlus) // 加载ElementPlus 12 | .mount('#app') // 挂载Vue的app实例 13 | 14 | */ 15 | 16 | const ver = window.__ver || '' 17 | 18 | Promise.all([ 19 | import('./store/index.js' + ver), 20 | import('./router/index.js' + ver), 21 | import('./app.js' + ver), 22 | ]).then((res) => { 23 | // 创建vue3的实例 24 | const app = Vue.createApp(res[2].default) 25 | .use(res[0].default) // 挂载vuex 26 | .use(res[1].default) // 挂载路由 27 | .use(ElementPlus) // 加载ElementPlus 28 | .mount('#app') // 挂载Vue的app实例 29 | }) 30 | -------------------------------------------------------------------------------- /cnd/project-template/src/router/index.js: -------------------------------------------------------------------------------- 1 | 2 | const routes = [ 3 | { 4 | path: '/', 5 | name: 'Home', 6 | component: () => myImport('views/home') 7 | }, 8 | { 9 | path: '/About', 10 | name: 'About', 11 | component: () => myImport('views/About') 12 | }, 13 | { 14 | path: '/component', 15 | name: 'component', 16 | component: () => myImport('views/component') 17 | }, 18 | { 19 | path: '/store', 20 | name: 'store', 21 | component: () => myImport('views/store') 22 | } 23 | ] 24 | 25 | const router = VueRouter.createRouter({ 26 | history: VueRouter.createWebHistory(), 27 | routes 28 | }) 29 | 30 | export default router 31 | -------------------------------------------------------------------------------- /cnd/project-template/src/script/appImport.js: -------------------------------------------------------------------------------- 1 | // 直接放在Window里面好了。。。 2 | window.myImport = (url) => { 3 | return new Promise((resolve, reject) => { 4 | const ver = window.__ver || '' 5 | const baseUrl = window.__basrUrl || '/src/' 6 | // 先加载js 7 | import(baseUrl + url + '.js' + ver).then((resjs) => { 8 | const js = resjs.default 9 | if (js.template === '') { 10 | // 如果模板是空的,表示需要加载html作为模板 11 | axios.get(baseUrl + url + '.html' + ver).then((resHTML) => { 12 | js.template = resHTML.data 13 | resolve(js) 14 | }) 15 | } else { 16 | // 否则直接使用js注册组件 17 | resolve(js) 18 | } 19 | }) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /cnd/project-template/src/store/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { Set_Count } from './mutation-types.js' 3 | 4 | export default Vuex.createStore({ 5 | state: { 6 | count: 0, 7 | myObject: { 8 | time: '现在的时间:' 9 | }, 10 | myArray: [1,2,2,3,4] 11 | }, 12 | getters: { 13 | getAddCount: (state) => { 14 | return state.count + 1 15 | }, 16 | getTime: (state) => { 17 | return state.myObject.time + new Date() 18 | }, 19 | filterArray: (state) => (id) => { 20 | return state.myArray.filter((item) => item === id) 21 | } 22 | }, 23 | mutations: { 24 | // 计数器 25 | setCount(state, num = 1) { 26 | state.count += num 27 | }, 28 | [Set_Count](state, num = 1) { 29 | state.count += num 30 | }, 31 | // 设置当前时间 32 | setTime(state) { 33 | state.myObject.time = '现在时间:' + new Date() 34 | 35 | }, 36 | // 设置数组的值 37 | setArray(state, val = 4) { 38 | state.myArray[1] = val 39 | }, 40 | reloadArray(state, arr) { 41 | state.myArray.lenth = 0 42 | state.myArray = [...arr] 43 | } 44 | }, 45 | actions: { 46 | // 异步获取数组 47 | getArray(context) { 48 | setTimeout(() => { 49 | context.commit('setArray', new Date().valueOf()) 50 | }, 10000) 51 | }, 52 | // 异步获取数组 53 | getArrayPromise(context) { 54 | return new Promise((resolve, reject) => { 55 | setTimeout(() => { 56 | const time = new Date().valueOf() 57 | resolve(time) 58 | }, 2000) 59 | }) 60 | }, 61 | // axios 62 | getDat2(context) { 63 | const ajax = axios.get('demo.json') 64 | ajax.then((response) => { 65 | const arr = response.data.company.formItem 66 | console.log('getData - axios - response', arr) 67 | // context.commit('reloadArray', arr) 68 | }) 69 | .catch((error) => { 70 | console.log('getData - axios - error', error) 71 | }) 72 | return ajax // 直接返回 axios 的promise的实例 73 | } 74 | }, 75 | modules: { 76 | } 77 | }) 78 | -------------------------------------------------------------------------------- /cnd/project-template/src/store/map.js: -------------------------------------------------------------------------------- 1 | 2 | const map = () => { 3 | const store = Vuex.useStore() 4 | 5 | /** 6 | * 获取count, 7 | * 用computed实现相应 8 | */ 9 | const getCount = () => { 10 | return Vue.computed(() => store.state.count) 11 | } 12 | 13 | /** 14 | * 获取count, 15 | ** 用 ref 实现相应 16 | */ 17 | const getRefCount = () => { 18 | return Vue.ref(store.state.count) 19 | } 20 | 21 | /** 22 | * 获取对象 23 | */ 24 | const getObject = () => { 25 | return store.state.myObject 26 | } 27 | 28 | /** 29 | * 获取只读对象 30 | */ 31 | const getReadonlyObject = () => { 32 | return Vue.readonly(store.state.myObject) 33 | } 34 | 35 | /** 36 | * 获取数组 37 | */ 38 | const getArray = () => { 39 | return store.state.myArray 40 | } 41 | /** 42 | * 获取只读数组 43 | */ 44 | const getReadonlyArray = () => { 45 | return Vue.readonly(store.state.myArray) 46 | } 47 | 48 | /** 49 | * 查询数组 50 | ** id:要查询的数据 51 | */ 52 | const filterArray = (id) => { 53 | return Vue.computed(() => store.getters.filterArray(id)) 54 | } 55 | 56 | return { 57 | getCount, 58 | getRefCount, 59 | getObject, 60 | getReadonlyObject, 61 | getArray, 62 | getReadonlyArray, 63 | filterArray 64 | } 65 | 66 | } 67 | 68 | export default map -------------------------------------------------------------------------------- /cnd/project-template/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const Set_Count = 'set_count' 2 | export const Set_Count_sy = Symbol('set_count') 3 | -------------------------------------------------------------------------------- /cnd/project-template/src/views/About.html: -------------------------------------------------------------------------------- 1 |
2 | 演示一下由路由加载的组件。
3 | html 和 js分开写的方式。
4 | 插值演示:{{value}}
5 |
6 | -------------------------------------------------------------------------------- /cnd/project-template/src/views/About.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'About', 3 | template: '', 4 | setup () { 5 | const value = Vue.ref('数据绑定的演示') 6 | 7 | return { 8 | value 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /cnd/project-template/src/views/component.html: -------------------------------------------------------------------------------- 1 |
2 | 演示一下组件里面使用组件的方式
3 | 4 |
5 | -------------------------------------------------------------------------------- /cnd/project-template/src/views/component.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'template', 3 | template: ``, 4 | components: { 5 | test: Vue.defineAsyncComponent( 6 | () => myImport('components/test') 7 | ) 8 | }, 9 | setup () { 10 | const value = Vue.ref('传入组件的参数') 11 | return { 12 | value 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cnd/project-template/src/views/home.js: -------------------------------------------------------------------------------- 1 | const { ref, reactive } = Vue 2 | 3 | const testManage = () => { 4 | const hello = ref('你好,世界') 5 | const clickMe = () => { 6 | hello.value = '好的,收到,现在时间:' + new Date() 7 | } 8 | 9 | return { 10 | hello, 11 | clickMe 12 | } 13 | } 14 | 15 | // vue3的对象 16 | export default { 17 | template: ` 18 |

我是 {{value.name}}

19 |
20 | 老规矩:{{hello}}
21 | 快点我
22 |
23 | 这里是一种CND的开发方式
24 | vue全家桶和UI库用 CND方式 加载。
25 | js代码用 import 方式加载。
26 | 目录结构参考了vue-cli建立的项目。
27 | 支持组件、路由、状态管理等功能。
28 | 不用webpack、npm等,建立网站就可以用。

29 | 状态计数:{{$store.state.count}} 30 |
31 | `, 32 | setup() { 33 | // 使用外面的定义,分解setup内部的代码 34 | const { hello, clickMe } = testManage() 35 | 36 | const value = reactive({ 37 | name: 'jyk' 38 | }) 39 | 40 | 41 | return { 42 | value, 43 | hello, 44 | clickMe 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /cnd/project-template/src/views/store.html: -------------------------------------------------------------------------------- 1 |
2 | 这里演示一下 vuex 的一些操作:
3 | 4 | ref的count :{{refCount}}
5 | 计算属性的Count :{{comCount}}
6 | 只读对象 :{{readonlyObject}}
7 | 8 |
-------------------------------------------------------------------------------- /cnd/project-template/src/views/store.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 获取状态 4 | const indirectManage = () => { 5 | const store = Vuex.useStore() 6 | 7 | // 用toRef获取 count,有相应性,可以直接修改state 8 | const refCount = Vue.toRef(store.state, 'count') 9 | // 计算属性获取count,有相应性,不可以直接修改state 10 | const comCount = Vue.computed(() => store.state.count + 10) 11 | // 只读的对象,有响应性,浅层不可以修改,但是深层还是可以修改。 12 | const readonlyObject = Vue.readonly(store.state.myObject) 13 | 14 | console.log('refCount:', refCount) 15 | console.log('comCount:', comCount) 16 | console.log('readonlyObject:', readonlyObject) 17 | console.log('================') 18 | 19 | // 定时修改 count 看响应性 20 | setTimeout(() => { 21 | // store.commit('setCount') 22 | // refCount.value += 200 // 会直接改vuex的state 23 | }, 2000) 24 | 25 | return { 26 | refCount, 27 | comCount, 28 | readonlyObject 29 | } 30 | } 31 | 32 | 33 | export default { 34 | name: 'vuex_store', 35 | template: '', 36 | components: { 37 | }, 38 | setup () { 39 | const value = Vue.ref('状态管理的演示') 40 | 41 | // 获取状态 42 | const { refCount, comCount, readonlyObject } = indirectManage() 43 | 44 | return { 45 | value, 46 | refCount, comCount, readonlyObject 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cnd/project-template/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /cnd/project-vuex/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 介绍vuex的相关内容 3 | 4 | * state 5 | * getter 6 | 7 | 在线演示: 8 | https://naturefwvue.github.io/nf-vue-cnd/cnd/project-vuex 9 | -------------------------------------------------------------------------------- /cnd/project-vuex/a.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project-vuex/a.html -------------------------------------------------------------------------------- /cnd/project-vuex/demo.json: -------------------------------------------------------------------------------- 1 | { 2 | "company":{ 3 | "formMeta":{ 4 | "name":"company", 5 | "allColumn":[1000,1001,1002,1003,1004,1005,1006,1007,1008,1009], 6 | "state":"add", 7 | "colCount":1 8 | }, 9 | "formItem":{ 10 | "1000":{ 11 | "controlId": 1000, 12 | "colName": "companyName", 13 | "controlType": 101, 14 | "isClear": true, 15 | "disabled": false, 16 | "required": true, 17 | "readonly": false, 18 | "pattern": "", 19 | "class": "", 20 | "placeholder": "请输入公司名称", 21 | "title": "公司名称", 22 | "autocomplete": "on", 23 | "size": 30, 24 | "maxlength": 100, 25 | "optionList": [], 26 | "tdCount":1 27 | }, 28 | "1001":{ 29 | "controlId": 1001, 30 | "colName": "companyCode", 31 | "controlType": 131, 32 | "isClear": true, 33 | "disabled": false, 34 | "required": true, 35 | "readonly": false, 36 | "pattern": "", 37 | "class": "", 38 | "placeholder": "公司邮编", 39 | "title": "公司邮编", 40 | "autocomplete": "on", 41 | "min": 100000, 42 | "max": 999999, 43 | "step": 1, 44 | "maxlength": 6, 45 | "optionList": [], 46 | "tdCount":1 47 | }, 48 | "1002":{ 49 | "controlId": 1002, 50 | "colName": "legalPerson", 51 | "controlType": 101, 52 | "isClear": true, 53 | "disabled": false, 54 | "required": true, 55 | "readonly": false, 56 | "pattern": "", 57 | "class": "", 58 | "placeholder": "请输入法人姓名", 59 | "title": "法人", 60 | "autocomplete": "on", 61 | "size": 20, 62 | "maxlength": 50, 63 | "optionList": [], 64 | "tdCount":1 65 | }, 66 | "1003":{ 67 | "controlId": 1003, 68 | "colName": "liaisonMan", 69 | "controlType": 101, 70 | "isClear": true, 71 | "disabled": false, 72 | "required": true, 73 | "readonly": false, 74 | "pattern": "", 75 | "class": "", 76 | "placeholder": "请输入联系人姓名", 77 | "title": "联系人", 78 | "autocomplete": "on", 79 | "size": 20, 80 | "maxlength": 50, 81 | "optionList": [], 82 | "tdCount":1 83 | }, 84 | "1004": { 85 | "controlId": "1004", 86 | "colName": "address", 87 | "controlType": 101, 88 | "isClear": true, 89 | "defaultValue": "", 90 | "autofocus": false, 91 | "disabled": false, 92 | "required": true, 93 | "readonly": false, 94 | "pattern": "", 95 | "class": "", 96 | "placeholder": "请输入公司地址", 97 | "title": "公司地址", 98 | "autocomplete": "on", 99 | "size": 30, 100 | "maxlength": 50, 101 | "optionKey": "", 102 | "optionList": [], 103 | "tdCount":1 104 | }, 105 | "1005": { 106 | "controlId": "1005", 107 | "colName": "telphone", 108 | "controlType": 103, 109 | "isClear": true, 110 | "defaultValue": "", 111 | "autofocus": false, 112 | "disabled": false, 113 | "required": true, 114 | "readonly": false, 115 | "pattern": "", 116 | "class": "", 117 | "placeholder": "请输入公司电话", 118 | "title": "公司电话", 119 | "autocomplete": "on", 120 | "size": 30, 121 | "maxlength": 50, 122 | "optionKey": "", 123 | "optionList": [], 124 | "tdCount":1 125 | }, 126 | "1006": { 127 | "controlId": "1006", 128 | "colName": "URL", 129 | "controlType": 105, 130 | "isClear": true, 131 | "defaultValue": "", 132 | "autofocus": false, 133 | "disabled": false, 134 | "required": true, 135 | "readonly": false, 136 | "pattern": "", 137 | "class": "", 138 | "placeholder": "https://www.", 139 | "title": "公司网址", 140 | "autocomplete": "on", 141 | "size": 30, 142 | "maxlength": 50, 143 | "optionKey": "", 144 | "optionList": [], 145 | "tdCount":1 146 | }, 147 | "1007": { 148 | "controlId": "1007", 149 | "colName": "Email", 150 | "controlType": 104, 151 | "isClear": true, 152 | "defaultValue": "", 153 | "autofocus": false, 154 | "disabled": false, 155 | "required": true, 156 | "readonly": false, 157 | "pattern": "", 158 | "class": "", 159 | "placeholder": "@", 160 | "title": "公司邮件", 161 | "autocomplete": "on", 162 | "size": 30, 163 | "maxlength": 50, 164 | "optionKey": "", 165 | "optionList": [], 166 | "tdCount":1 167 | }, 168 | "1008": { 169 | "controlId": 1008, 170 | "colName": "type", 171 | "title": "公司类型", 172 | "controlType": 190, 173 | "isClear": true, 174 | "defaultValue": "", 175 | "autofocus": false, 176 | "disabled": false, 177 | "required": true, 178 | "pattern": "", 179 | "class": "", 180 | "optionList": [ 181 | { "value": 1, "title": "有限责任公司" }, 182 | { "value": 2, "title": "股份有限责任公司" }, 183 | { "value": 3, "title": "个人独资企业" }, 184 | { "value": 4, "title": "合伙企业" }, 185 | { "value": 5, "title": "个体工商户" } 186 | ], 187 | "tdCount":1 188 | }, 189 | "1009": { 190 | "controlId": 1009, 191 | "colName": "createDate", 192 | "controlType": 140, 193 | "isClear": true, 194 | "defaultValue": "", 195 | "autofocus": false, 196 | "disabled": false, 197 | "required": true, 198 | "readonly": false, 199 | "pattern": "", 200 | "class": "", 201 | "title": "成立日期", 202 | "min": "1950-01-01", 203 | "max": "2999-12-31", 204 | "step": 1, 205 | "tdCount":1 206 | }, 207 | "1010":{ 208 | "controlId": "2012", 209 | "colName": "education", 210 | "controlType": 183, 211 | "isClear": true, 212 | "disabled": false, 213 | "required": true, 214 | "readonly": false, 215 | "pattern": "", 216 | "class": "", 217 | "placeholder": "", 218 | "title": "学历", 219 | "optionList": [ 220 | { "value": 1, "title": "高中" }, 221 | { "value": 2, "title": "大专" }, 222 | { "value": 3, "title": "本科" }, 223 | { "value": 4, "title": "硕士" }, 224 | { "value": 5, "title": "博士" } 225 | ] 226 | }, 227 | "1011":{ 228 | "controlId": 100, 229 | "colName": "hobby", 230 | "controlType": 182, 231 | "isClear": true, 232 | "disabled": false, 233 | "required": true, 234 | "readonly": false, 235 | "pattern": "", 236 | "class": "", 237 | "title": "爱好", 238 | "optionList": [ 239 | { "value": 1, "title": "篮球" }, 240 | { "value": 2, "title": "足球" }, 241 | { "value": 3, "title": "排球" } 242 | ] 243 | } 244 | } 245 | }, 246 | "person":{ 247 | "formMeta":{ 248 | "name":"person", 249 | "allColumn":[2000,2001,2002,2003,2012,2030], 250 | "state":"add", 251 | "colCount":1 252 | }, 253 | "formItem":{ 254 | "2000":{ 255 | "controlId": 2000, 256 | "colName": "personId", 257 | "controlType": 101, 258 | "isClear": true, 259 | "disabled": false, 260 | "required": true, 261 | "readonly": false, 262 | "pattern": "", 263 | "class": "", 264 | "placeholder": "请输入", 265 | "title": "工号", 266 | "autocomplete": "on", 267 | "size": 10, 268 | "maxlength": 10, 269 | "optionList": [] 270 | }, 271 | "2001":{ 272 | "controlId": 2001, 273 | "colName": "personName", 274 | "controlType": 101, 275 | "isClear": true, 276 | "disabled": false, 277 | "required": true, 278 | "readonly": false, 279 | "pattern": "", 280 | "class": "", 281 | "placeholder": "请输入员工姓名", 282 | "title": "姓名", 283 | "autocomplete": "on", 284 | "size": 10, 285 | "maxlength": "50" 286 | }, 287 | "2002": { 288 | "controlId": 2002, 289 | "colName": "Gender", 290 | "controlType": 183, 291 | "isClear": true, 292 | "disabled": false, 293 | "required": true, 294 | "readonly": false, 295 | "pattern": "", 296 | "class": "", 297 | "title": "性别", 298 | "optionList": [ 299 | { "value": "男", "title": "男" }, 300 | { "value": "女", "title": "女" } 301 | ] 302 | }, 303 | "2003":{ 304 | "controlId": 2012, 305 | "colName": "nation", 306 | "controlType": 106, 307 | "isClear": true, 308 | "disabled": false, 309 | "required": true, 310 | "readonly": false, 311 | "pattern": "", 312 | "class": "", 313 | "placeholder": "请输入员工姓名", 314 | "title": "民族", 315 | "optionKey": "minzu", 316 | "optionList": [ 317 | { "value": 1, "title": "汉" }, 318 | { "value": 2, "title": "蒙古" }, 319 | { "value": 3, "title": "满族" }, 320 | { "value": 4, "title": "回族" }, 321 | { "value": 5, "title": "朝鲜" } 322 | ] 323 | }, 324 | "2012":{ 325 | "controlId": 2012, 326 | "colName": "education", 327 | "controlType": 190, 328 | "isClear": true, 329 | "disabled": false, 330 | "required": true, 331 | "readonly": false, 332 | "pattern": "", 333 | "class": "", 334 | "placeholder": "", 335 | "title": "学历", 336 | "optionList": [ 337 | { "value": 1, "title": "高中" }, 338 | { "value": 2, "title": "大专" }, 339 | { "value": 3, "title": "本科" }, 340 | { "value": 4, "title": "硕士" }, 341 | { "value": 5, "title": "博士" } 342 | ] 343 | }, 344 | "2030":{ 345 | "controlId": 2030, 346 | "colName": "hobby", 347 | "controlType": 182, 348 | "isClear": true, 349 | "disabled": false, 350 | "required": true, 351 | "readonly": false, 352 | "pattern": "", 353 | "class": "", 354 | "title": "爱好", 355 | "optionList": [ 356 | { "value": 1, "title": "篮球" }, 357 | { "value": 2, "title": "足球" }, 358 | { "value": 3, "title": "排球" } 359 | ] 360 | } 361 | } 362 | } 363 | } -------------------------------------------------------------------------------- /cnd/project-vuex/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | CDN 的工程化开发 的模板 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 48 | 49 | 50 |
51 | 这里演示一下vuex的演示... 52 |
53 |
54 | 69 |
70 | vuex状态演示
71 | 模板:
72 | $store :{{$store.state}}
73 | $store - myObject :{{$store.state.myObject}}
74 | 75 | 更新状态
76 |
77 |
78 |
79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /cnd/project-vuex/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project-vuex/public/favicon.ico -------------------------------------------------------------------------------- /cnd/project-vuex/src/app.js: -------------------------------------------------------------------------------- 1 | 2 | // import { Set_Count, Set_Count_sy } from './store/mutation-types.js' 3 | 4 | export default { 5 | setup() { 6 | const store = Vuex.useStore() 7 | 8 | // 状态的控制事件 9 | const setCount = () =>{ 10 | store.commit('setCount') 11 | store.commit('setTime') 12 | store.commit('setArray') 13 | // store._mutations.setCount[0] // 这是什么? 14 | } 15 | 16 | return { 17 | // 设置state 18 | setCount 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /cnd/project-vuex/src/component/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 26 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/component/test.html: -------------------------------------------------------------------------------- 1 |
2 | 这是一个测试看看动态加载的组件 3 |

{{title}}

4 |
-------------------------------------------------------------------------------- /cnd/project-vuex/src/component/test.js: -------------------------------------------------------------------------------- 1 | 2 | const aa = '外部定义' 3 | 4 | const test = { 5 | template: ` 6 | 这是 组件测试
7 | 参数:{{str1}}
8 | 外部函数:{{aa}}
9 | `, 10 | props: { 11 | str: String 12 | }, 13 | setup(props) { 14 | // 在setup里面获取参数值 15 | const str1 = Vue.ref(props.str) 16 | // alert('test的alert') 17 | return { 18 | str1, 19 | aa 20 | } 21 | } 22 | } 23 | 24 | export default test -------------------------------------------------------------------------------- /cnd/project-vuex/src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | import store from './store/index.js?v=28' 3 | import router from './router/index.js?v=28' 4 | import App from './app.js?v=28' 5 | 6 | 7 | // 创建vue3的实例 8 | const app = Vue.createApp(App) 9 | .use(store) // 挂载vuex 10 | .use(router) // 挂载路由 11 | .use(ElementPlus) // 加载ElementPlus 12 | .mount('#app') // 挂载Vue的app实例 13 | 14 | */ 15 | 16 | const ver = window.__ver || '' 17 | 18 | Promise.all([ 19 | import('./store/index.js' + ver), 20 | import('./router/index.js' + ver), 21 | import('./app.js' + ver), 22 | ]).then((res) => { 23 | // 创建vue3的实例 24 | const app = Vue.createApp(res[2].default) 25 | .use(res[0].default) // 挂载vuex 26 | .use(res[1].default) // 挂载路由 27 | .use(ElementPlus) // 加载ElementPlus 28 | .mount('#app') // 挂载Vue的app实例 29 | }) 30 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/router/index.js: -------------------------------------------------------------------------------- 1 | // import myImport from '../script/myImport.js?v=29' 2 | 3 | const routes = [ 4 | { 5 | path: '/', 6 | name: 'Home', 7 | component: () => myImport('views/home') 8 | }, 9 | { 10 | path: '/state', 11 | name: 'state', 12 | component: () => myImport('views/01stateall') 13 | }, 14 | { 15 | path: '/state2', 16 | name: 'state2', 17 | component: () => myImport('views/02statemember') 18 | }, 19 | { 20 | path: '/getter', 21 | name: 'getter', 22 | component: () => myImport('views/03getter') 23 | }, 24 | { 25 | path: '/setter', 26 | name: 'setter', 27 | component: () => myImport('views/04setter') 28 | }, 29 | { 30 | path: '/action', 31 | name: 'action', 32 | component: () => myImport('views/05action') 33 | }, 34 | { 35 | path: '/module', 36 | name: 'module', 37 | component: () => myImport('views/06module') 38 | } 39 | ] 40 | 41 | const router = VueRouter.createRouter({ 42 | history: VueRouter.createWebHistory(), 43 | routes 44 | }) 45 | 46 | export default router 47 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/script/appImport.js: -------------------------------------------------------------------------------- 1 | // 直接放在Window里面好了。。。 2 | window.myImport = (url) => { 3 | return new Promise((resolve, reject) => { 4 | const ver = window.__ver || '' 5 | const baseUrl = window.__basrUrl || '/src/' 6 | // 先加载js 7 | import(baseUrl + url + '.js' + ver).then((resjs) => { 8 | const js = resjs.default 9 | if (js.template === '') { 10 | // 如果模板是空的,表示需要加载html作为模板 11 | axios.get(baseUrl + url + '.html' + ver).then((resHTML) => { 12 | js.template = resHTML.data 13 | resolve(js) 14 | }) 15 | } else { 16 | // 否则直接使用js注册组件 17 | resolve(js) 18 | } 19 | }) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/script/myImport.js: -------------------------------------------------------------------------------- 1 | // 同步加载的方式 2 | const myImport2 = (url) => { 3 | return new Promise((resolve, reject) => { 4 | const ver = window.__ver || '' 5 | const baseUrl = window.__basrUrl || '/src/' 6 | Promise.all([ 7 | axios.get(baseUrl + url + '.html' + ver), 8 | import(baseUrl + url + '.js' + ver) 9 | ]).then((req) => { 10 | resolve({ 11 | template: req[0].data, 12 | props: req[1].default.props, 13 | setup: req[1].default.setup 14 | }) 15 | }) 16 | }) 17 | } 18 | 19 | // 加载html和js 20 | const myImport = (url) => { 21 | return new Promise((resolve, reject) => { 22 | const ver = window.__ver || '' 23 | const baseUrl = window.__basrUrl || '/src/' 24 | // 先加载js 25 | import(baseUrl + url + '.js' + ver).then((resjs) => { 26 | const js = resjs.default 27 | if (js.template === '') { 28 | // 如果模板是空的,表示需要加载html作为模板 29 | axios.get(baseUrl + url + '.html' + ver).then((resHTML) => { 30 | js.template = resHTML.data 31 | resolve(js) 32 | }) 33 | } else { 34 | // 否则直接使用js注册组件 35 | resolve(js) 36 | } 37 | }) 38 | }) 39 | } 40 | 41 | export default myImport -------------------------------------------------------------------------------- /cnd/project-vuex/src/store/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { Set_Count, Set_Count_sy } from './mutation-types.js' 3 | 4 | import user from './user.js' 5 | 6 | const myPlugin = store => { 7 | console.log('插件--store', store) 8 | // 当 store 初始化后调用 9 | store.subscribe((mutation, state) => { 10 | console.log('插件--store', store) 11 | console.log('插件--', mutation) 12 | 13 | // 每次 mutation 之后调用 14 | // mutation 的格式为 { type, payload } 15 | 16 | }) 17 | } 18 | 19 | export default Vuex.createStore({ 20 | // plugins: [myPlugin], 21 | state: { 22 | count: 0, 23 | myObject: { 24 | time: '现在的时间:' 25 | }, 26 | myArray: [1,2,2,3,4] 27 | }, 28 | getters: { 29 | getAddCount: (state) => { 30 | return state.count + 1 31 | }, 32 | getTime: (state) => { 33 | return state.myObject.time + new Date() 34 | }, 35 | filterArray: (state) => (id) => { 36 | return state.myArray.filter((item) => item === id) 37 | } 38 | }, 39 | mutations: { 40 | // 计数器 41 | setCount(state, num = 1) { 42 | state.count += num 43 | 44 | }, 45 | [Set_Count](state, num = 1) { 46 | state.count += num 47 | }, 48 | // 设置当前时间 49 | setTime(state) { 50 | state.myObject.time = '现在时间:' + new Date() 51 | 52 | }, 53 | // 设置数组的值 54 | setArray(state, val = 4) { 55 | state.myArray[1] = val 56 | }, 57 | reloadArray(state, arr) { 58 | state.myArray.lenth = 0 59 | state.myArray = [...arr] 60 | } 61 | }, 62 | actions: { 63 | // 异步获取数组 64 | getArray(context) { 65 | console.log('================================') 66 | console.log('异步getArray——context', context) 67 | setTimeout(() => { 68 | context.commit('setArray', new Date().valueOf()) 69 | }, 10000) 70 | }, 71 | // 异步获取数组 72 | getArrayPromise(context) { 73 | return new Promise((resolve, reject) => { 74 | console.log('================================') 75 | console.log('异步 getArrayPromise ——context', context) 76 | setTimeout(() => { 77 | const time = new Date().valueOf() 78 | // context.commit('setArray', time) 79 | resolve(time) 80 | }, 2000) 81 | }) 82 | }, 83 | // axios 84 | getData(context) { 85 | return new Promise((resolve, reject) => { 86 | axios.get('demo.json') 87 | .then((response) => { 88 | const arr = response.data.company.formItem 89 | console.log('getData - axios - response', response) 90 | // context.commit('reloadArray', response.data.company.formItem) 91 | resolve(arr) 92 | }) 93 | .catch((error) => { 94 | console.log('getData - axios - error', error) 95 | }) 96 | }) 97 | }, 98 | // axios 99 | getDat2(context) { 100 | const ajax = axios.get('demo.json') 101 | ajax.then((response) => { 102 | const arr = response.data.company.formItem 103 | console.log('getData - axios - response', arr) 104 | // context.commit('reloadArray', arr) 105 | }) 106 | .catch((error) => { 107 | console.log('getData - axios - error', error) 108 | }) 109 | return ajax // 直接返回 axios 的promise的实例 110 | } 111 | }, 112 | modules: { 113 | myObject: user, 114 | user: user, 115 | person: user 116 | } 117 | }) 118 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/store/map.js: -------------------------------------------------------------------------------- 1 | 2 | const map = () => { 3 | const store = Vuex.useStore() 4 | 5 | /** 6 | * 获取count, 7 | * 用computed实现相应 8 | */ 9 | const getCount = () => { 10 | return Vue.computed(() => store.state.count) 11 | } 12 | 13 | /** 14 | * 获取count, 15 | ** 用 ref 实现相应 16 | */ 17 | const getRefCount = () => { 18 | return Vue.ref(store.state.count) 19 | } 20 | 21 | /** 22 | * 获取对象 23 | */ 24 | const getObject = () => { 25 | return store.state.myObject 26 | } 27 | 28 | /** 29 | * 获取只读对象 30 | */ 31 | const getReadonlyObject = () => { 32 | return Vue.readonly(store.state.myObject) 33 | } 34 | 35 | /** 36 | * 获取数组 37 | */ 38 | const getArray = () => { 39 | return store.state.myArray 40 | } 41 | /** 42 | * 获取只读数组 43 | */ 44 | const getReadonlyArray = () => { 45 | return Vue.readonly(store.state.myArray) 46 | } 47 | 48 | /** 49 | * 查询数组 50 | ** id:要查询的数据 51 | */ 52 | const filterArray = (id) => { 53 | return Vue.computed(() => store.getters.filterArray(id)) 54 | } 55 | 56 | return { 57 | getCount, 58 | getRefCount, 59 | getObject, 60 | getReadonlyObject, 61 | getArray, 62 | getReadonlyArray, 63 | filterArray 64 | } 65 | 66 | } 67 | 68 | export default map -------------------------------------------------------------------------------- /cnd/project-vuex/src/store/map2.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * 获取计数器 5 | */ 6 | export const getCount = () => { 7 | return Vuex.useStore().state.count 8 | } 9 | 10 | export const getCount1 = () => { 11 | return Vuex.useStore().state.state.getter.getCount 12 | } 13 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const Set_Count = 'set_count' 2 | export const Set_Count_sy = Symbol('set_count') 3 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/store/user.js: -------------------------------------------------------------------------------- 1 | 2 | const user = { 3 | namespaced: true, // 避免重名 4 | state: () => ({ 5 | userInfo: { 6 | userId: 123, 7 | userCode: '', 8 | userNick: '' 9 | }, 10 | userRole: [] 11 | }), 12 | mutations: { 13 | setUser(state, code) { 14 | state.userInfo.userCode = code 15 | } 16 | }, 17 | getters: { 18 | getUser(state) { 19 | return state.userInfo 20 | } 21 | }, 22 | actions: { 23 | // { state, commit, rootState } 24 | setUsera (store, code) { 25 | store.commit('setUser', code) 26 | } 27 | } 28 | } 29 | 30 | export default user -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/01stateall.html: -------------------------------------------------------------------------------- 1 |
2 | 整体22:
3 | allState :{{allState}}
4 | 5 | 成员 :
6 | memberCount : {{memberCount}} (用简单类型的成员定义,没有相应性)
7 | memberObject :{{memberObject}} (用引用类型的成员定义,自带响应性)
8 | 9 |
10 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/01stateall.js: -------------------------------------------------------------------------------- 1 | 2 | // 整体获取 3 | const allStateManage = () => { 4 | const store = Vuex.useStore() 5 | 6 | // 看看state的类型 7 | console.log('state:', store.state) 8 | console.log('state.count:', store.state.count) 9 | console.log('state.myObject:', store.state.myObject) 10 | 11 | // 获得整体的state 12 | const allState = store.state 13 | console.log('allState:', allState) 14 | console.log('================') 15 | 16 | // 定时修改 count 看响应性 17 | setTimeout(() => { 18 | // store.commit('setCount') 19 | allState.count += 101 // 会直接改vuex的state 20 | }, 1000) 21 | 22 | return { 23 | allState 24 | } 25 | } 26 | 27 | 28 | export default { 29 | name: 'vuex_state_all', 30 | template: '', 31 | components: { 32 | }, 33 | setup () { 34 | const value = Vue.ref('state_all') 35 | 36 | // 获取state 37 | const { allState } = allStateManage() 38 | 39 | return { 40 | value, 41 | allState 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/02statemember.html: -------------------------------------------------------------------------------- 1 |
2 | 间接获取:
3 | refCount :{{refCount}} (ref)
4 | comCount :{{comCount}} (计算属性)
5 | readonlyObject : {{readonlyObject}} (只读的reactive) 6 |
7 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/02statemember.js: -------------------------------------------------------------------------------- 1 | 2 | // 直接获取state的成员 3 | const stateMemberManage = () => { 4 | const store = Vuex.useStore() 5 | 6 | // 看看state的类型 7 | let memberCount = store.state.count // 失去响应性 8 | const memberObject = store.state.myObject 9 | console.log('memberCount', memberCount) 10 | console.log('memberObject', memberObject) 11 | console.log('================') 12 | 13 | // 定时修改 count 看响应性 14 | setTimeout(() => { 15 | // memberCount += 101 16 | // const 定义的会报错,不允许赋值,常量。 17 | // let 定义的可以修改,但是没有相应性 18 | }, 1000) 19 | 20 | return { 21 | memberCount, 22 | memberObject 23 | } 24 | } 25 | 26 | 27 | export default { 28 | name: 'vuex_action', 29 | template: '', 30 | components: { 31 | }, 32 | setup () { 33 | const value = Vue.ref('测试动态加载组件333') 34 | 35 | // action 36 | const { memberCount, memberObject } = stateMemberManage() 37 | 38 | return { 39 | value, 40 | memberCount, 41 | memberObject 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/03getter.html: -------------------------------------------------------------------------------- 1 |
2 | 这里演示一下 vuex 的 getter 的相关操作:
3 | 4 | addCount :{{addCount}} (计算属性,导致整体都 +1)
5 | getAddCount :{{getAddCount}} (getter,自己没有相应性)
6 | comGetAddCount :{{comGetAddCount}} (getter,需要套一个computed才能相应)
7 | filterArray :{{filterArray}} (getter,需要套一个computed才能相应)
8 | comFilterArray :{{comFilterArray}} (getter,需要套一个computed才能相应)
9 | 10 |
-------------------------------------------------------------------------------- /cnd/project-vuex/src/views/03getter.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 间接获取 4 | const indirectManage = () => { 5 | const store = Vuex.useStore() 6 | 7 | // 用toRef获取 count,有相应性,可以直接修改state 8 | const refCount = Vue.toRef(store.state, 'count') 9 | // 计算属性获取count,有相应性,不可以直接修改state 10 | const comCount = '' // Vue.computed(() => store.state.count) 11 | // 只读的对象,有相应性,浅层不可以修改,但是深层还是可以修改。 12 | const readonlyObject = Vue.readonly(store.state.myObject) 13 | 14 | console.log('refCount:', refCount) 15 | console.log('comCount:', comCount) 16 | console.log('readonlyObject:', readonlyObject) 17 | console.log('================') 18 | 19 | // 定时修改 count 看响应性 20 | setTimeout(() => { 21 | // store.commit('setCount') 22 | // refCount.value += 200 // 会直接改vuex的state 23 | }, 2000) 24 | 25 | return { 26 | refCount, 27 | comCount, 28 | readonlyObject 29 | } 30 | } 31 | 32 | 33 | // 处理后返回 34 | const operationManage = () => { 35 | const store = Vuex.useStore() 36 | // 计算属性获取count 37 | const addCount = Vue.computed(() => store.state.count + 1) 38 | const getAddCount = store.getters.getAddCount 39 | const comGetAddCount = Vue.computed(() => store.getters.getAddCount) 40 | const filterArray = store.getters.filterArray(2) 41 | const comFilterArray = Vue.computed(() => store.getters.filterArray(2)) 42 | 43 | console.log('addCount :', addCount) 44 | console.log('getAddCount :', getAddCount) 45 | console.log('comGetAddCount :', comGetAddCount) 46 | console.log('filterArray :', filterArray) 47 | console.log('comFilterArray :', comFilterArray) 48 | console.log('================') 49 | 50 | return { 51 | addCount, 52 | getAddCount, 53 | comGetAddCount, 54 | filterArray, 55 | comFilterArray 56 | } 57 | 58 | } 59 | 60 | export default { 61 | name: 'vuex_getter', 62 | template: '', 63 | components: { 64 | }, 65 | setup () { 66 | const value = Vue.ref('getter') 67 | 68 | // 间接获取成员 69 | const { refCount, comCount, readonlyObject } = indirectManage() 70 | 71 | // 间接获取成员 72 | const { 73 | addCount, 74 | getAddCount, 75 | comGetAddCount, 76 | filterArray, 77 | comFilterArray 78 | } = operationManage() 79 | 80 | return { 81 | value, 82 | addCount, 83 | getAddCount, 84 | comGetAddCount, 85 | filterArray, 86 | comFilterArray, 87 | refCount, comCount, readonlyObject 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/04setter.html: -------------------------------------------------------------------------------- 1 |
2 | 这里演示一下 vuex 的 mutations 的相关操作:
3 | commitSetCount :{{commitSetCount}}
4 |
-------------------------------------------------------------------------------- /cnd/project-vuex/src/views/04setter.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 设置state 4 | const mutationsManage = () => { 5 | const store = Vuex.useStore() 6 | 7 | let commitSetCount = Vue.computed({ 8 | get: () => store.state.count + 1, 9 | set: (val) => { 10 | // store.commit('setCount', val) 11 | } 12 | }) 13 | console.log('commitSetCount :', commitSetCount) 14 | console.log('================') 15 | 16 | // 定时修改 count 看响应性 17 | setTimeout(() => { 18 | // commitSetCount.value = 202 // 会直接改vuex的state 19 | }, 2000) 20 | 21 | return { 22 | commitSetCount 23 | } 24 | } 25 | 26 | export default { 27 | name: 'vuex_setter', 28 | template: '', 29 | components: { 30 | }, 31 | setup () { 32 | const value = Vue.ref('setter') 33 | 34 | // mutations 35 | const { commitSetCount } = mutationsManage() 36 | 37 | return { 38 | value, 39 | // 突变 40 | commitSetCount, 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/05action.html: -------------------------------------------------------------------------------- 1 |
2 | 这里演示一下 vuex 的 action 的相关操作
3 | value22 :{{value}}
4 | 5 |
-------------------------------------------------------------------------------- /cnd/project-vuex/src/views/05action.js: -------------------------------------------------------------------------------- 1 | 2 | // 异步操作 3 | const actionManame = () => { 4 | const store = Vuex.useStore() 5 | 6 | const getArray = store.dispatch('getArray') 7 | console.log('外部调用 getArray', getArray) 8 | getArray.then((data) => { 9 | console.log('===========') 10 | console.log('getArray 异步操作完成,返回数据:', data) 11 | console.log('===========') 12 | }) 13 | 14 | const getArrayPromise = store.dispatch('getArrayPromise') 15 | console.log('外部调用 getArrayPromise', getArrayPromise) 16 | getArrayPromise.then((data) => { 17 | console.log('===========') 18 | console.log('getArrayPromise 异步操作完成,返回数据:', data) 19 | console.log('===========') 20 | }) 21 | 22 | store.dispatch('getData').then((data) => { 23 | console.log('===========') 24 | console.log('getData 异步操作完成,返回数据:', data) 25 | console.log('===========') 26 | 27 | }) 28 | 29 | return { 30 | getArray, 31 | getArrayPromise 32 | } 33 | } 34 | 35 | 36 | export default { 37 | name: 'vuex_action', 38 | template: '', 39 | components: { 40 | }, 41 | setup () { 42 | const value = Vue.ref('测试动态加载组件333') 43 | 44 | // action 45 | const { getArray, getArrayPromise } = actionManame() 46 | 47 | return { 48 | value, 49 | getArray, 50 | getArrayPromise 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/06map.html: -------------------------------------------------------------------------------- 1 |
2 | 封装:
3 | mapCount :{{mapCount}}
4 |
5 |
-------------------------------------------------------------------------------- /cnd/project-vuex/src/views/06map.js: -------------------------------------------------------------------------------- 1 | 2 | import map from './store/map.js?v=12' 3 | 4 | export default { 5 | name: 'vuex_map', 6 | template: '', 7 | components: { 8 | }, 9 | setup () { 10 | const value = Vue.ref('map') 11 | 12 | // 通过map 获取 count 13 | // 可以使用别名 14 | const { 15 | getCount: mapGetCount 16 | } = map() 17 | 18 | const mapCount = mapGetCount() 19 | return { 20 | value, 21 | mapCount 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/06module.html: -------------------------------------------------------------------------------- 1 |
2 | 模块演示:
3 | 用户信息: {{userInfo}} 4 |
-------------------------------------------------------------------------------- /cnd/project-vuex/src/views/06module.js: -------------------------------------------------------------------------------- 1 | 2 | const moduleManage = () => { 3 | const store = Vuex.useStore() 4 | 5 | const userInfo = store.state.user.userInfo 6 | 7 | const userInfo2 = store.getters['user/getUser'] 8 | 9 | // store.commit('setUser', '没有命名空间的code') 10 | 11 | // store.dispatch('setUsera', 'actionde的code') 12 | 13 | store.commit('user/setUser', 'user的code') 14 | store.commit('myObject/setUser', 'myObject的code') 15 | store.commit('person/setUser', 'person的code') 16 | 17 | store.dispatch('user/setUsera', 'action的user的code') 18 | 19 | 20 | return { 21 | userInfo, 22 | userInfo2 23 | } 24 | } 25 | 26 | export default { 27 | name: 'vuex_module', 28 | template: '', 29 | components: { 30 | }, 31 | setup () { 32 | const value = Vue.ref('module') 33 | 34 | const { 35 | userInfo 36 | } = moduleManage() 37 | 38 | return { 39 | value, 40 | userInfo 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cnd/project-vuex/src/views/home.js: -------------------------------------------------------------------------------- 1 | const { ref } = Vue 2 | 3 | const testManage = () => { 4 | const hello = ref('你好,世界') 5 | const clickMe = () => { 6 | hello.value = '好的22,收到' + new Date().valueOf() 7 | } 8 | 9 | return { 10 | hello, 11 | clickMe 12 | } 13 | } 14 | 15 | // vue3的对象 16 | const home = { 17 | template: ` 18 |

这是home

19 |
20 | 我是{{value.name}}。
21 | 老规矩:{{hello}}
22 |

23 | 本项目采用“混合”模式开发,            
24 | vue全家桶和UI库用script标签加载。
25 | 代码用import方式加载。              
26 | 目录结构参考了cli建立的项目。         
27 | 支持组件、路由、状态管理等功能。 
28 | 状态计数:{{$store.state.count}}    29 |
30 | `, 31 | setup() { // 传说中的setup 32 | // 使用外面的定义,分解setup内部的代码 33 | const { hello, clickMe } = testManage() 34 | 35 | const value = Vue.reactive({ 36 | name: 'jyk' 37 | }) 38 | 39 | 40 | return { 41 | value, 42 | hello, 43 | clickMe 44 | } 45 | } 46 | } 47 | 48 | export default home -------------------------------------------------------------------------------- /cnd/project-vuex/vuex.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 82 | -------------------------------------------------------------------------------- /cnd/project-vuex/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /cnd/project/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 一种尝试 3 | * vue的全家桶和UI库,采用传统的方式加载(CND)。 4 | * 自己写的js代码,采用ES6的import方式加载。 5 | * 目录结构采用工程化的项目的结构。 6 | * 首页用vite项目的首页。 7 | * 不用babel做转义(因为还不会用)。 8 | * 不用webpack(因为总是报错,头痛...)。 9 | 10 | 11 | 在线演示: 12 | https://naturefwvue.github.io/nf-vue-cnd/cnd/project 13 | 14 | -------------------------------------------------------------------------------- /cnd/project/a.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project/a.html -------------------------------------------------------------------------------- /cnd/project/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 一种怪异的方式 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 34 | 35 | 36 |
37 | 这是一个尝试... 38 |
39 |
40 | 48 |
49 | vuex状态演示
50 | $store - count:{{$store.state.count}}
51 | vuex的 计数
52 |
53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /cnd/project/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naturefwvue/nf-vue-cnd/7670d199337cc527a04865181c5aacd8168fb901/cnd/project/public/favicon.ico -------------------------------------------------------------------------------- /cnd/project/src/app.js: -------------------------------------------------------------------------------- 1 | 2 | // vue3的对象 3 | const App = { 4 | setup() { // 传说中的setup 5 | 6 | const store = Vuex.useStore() 7 | // 状态的控制事件 8 | const setCount = () =>{ 9 | store.commit('setCount') 10 | } 11 | 12 | return { // 返回给模板,否则模板访问不到。 13 | setCount 14 | } 15 | } 16 | } 17 | 18 | export default App 19 | -------------------------------------------------------------------------------- /cnd/project/src/component/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /cnd/project/src/component/test.js: -------------------------------------------------------------------------------- 1 | const test = { 2 | template: ` 3 | 这是 组件测试
4 | 参数:{{str1}}
5 | `, 6 | model: { 7 | prop: ['str'] 8 | }, 9 | props: { 10 | str: String 11 | }, 12 | setup(props) { 13 | // 在setup里面获取参数值 14 | const str1 = Vue.ref(props.str) 15 | 16 | return { 17 | str1 18 | } 19 | } 20 | } 21 | 22 | export default test -------------------------------------------------------------------------------- /cnd/project/src/main.js: -------------------------------------------------------------------------------- 1 | import store from './store/index.js?v=6' 2 | import router from './router/index.js?v=8' 3 | import App from './app.js?v=6' 4 | 5 | // 创建vue3的实例 6 | const app = Vue.createApp(App) 7 | .use(store) // 挂载vuex 8 | .use(router) // 挂载路由 9 | .use(ElementPlus) // 加载ElementPlus 10 | .mount('#app') // 挂载Vue的app实例 11 | 12 | -------------------------------------------------------------------------------- /cnd/project/src/router/index.js: -------------------------------------------------------------------------------- 1 | // import Home from '../views/home.js?v=2' 2 | 3 | const routes = [ 4 | { 5 | path: '/', 6 | name: 'Home', 7 | component: () => import('../views/home.js?v=8') 8 | }, 9 | { 10 | path: '/state', 11 | name: 'state', 12 | component: () => import('../views/state.js?v=8') 13 | }, 14 | { 15 | path: '/component', 16 | name: 'component', 17 | component: () => import('../views/component.js?v=8') 18 | } 19 | ] 20 | 21 | const router = VueRouter.createRouter({ 22 | history: VueRouter.createWebHistory(), 23 | routes 24 | }) 25 | 26 | export default router 27 | -------------------------------------------------------------------------------- /cnd/project/src/store/index.js: -------------------------------------------------------------------------------- 1 | 2 | export default Vuex.createStore({ 3 | state: { 4 | count: 0, 5 | myObject: { 6 | time: '现在的时间' 7 | } 8 | }, 9 | getters: { 10 | getCount: (state) => { 11 | return state.count 12 | }, 13 | getMyObject: (state) => { 14 | return Vue.readonly(state.myObject) 15 | }, 16 | getTime: (state) => { 17 | return state.myObject.time 18 | } 19 | }, 20 | mutations: { 21 | setCount(state) { 22 | state.count++ 23 | }, 24 | setTime(state) { 25 | state.myObject.time = '现在时间:' + new Date() 26 | } 27 | }, 28 | actions: { 29 | }, 30 | modules: { 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /cnd/project/src/views/component.js: -------------------------------------------------------------------------------- 1 | // 引入组件 2 | import test from '../component/test.js?v=7' 3 | 4 | const demo = { 5 | template: ` 6 |

这是组件演示

7 | 8 | `, 9 | components: { 10 | test 11 | }, 12 | setup() { 13 | 14 | return { 15 | } 16 | } 17 | } 18 | 19 | export default demo -------------------------------------------------------------------------------- /cnd/project/src/views/home.js: -------------------------------------------------------------------------------- 1 | 2 | const testManage = () => { 3 | const hello = Vue.ref('你好,世界') 4 | const clickMe = () => { 5 | hello.value = '好的,收到' + new Date().valueOf() 6 | } 7 | 8 | return { 9 | hello, 10 | clickMe 11 | } 12 | } 13 | 14 | // vue3的对象 15 | const home = { 16 | template: ` 17 |

这是home

18 |
19 | 我是{{value.name}}。
20 | 老规矩:{{hello}}
21 |

22 | 本项目采用“混合”模式开发,            
23 | vue全家桶和UI库用script标签加载。
24 | 代码用import方式加载。              
25 | 目录结构参考了cli建立的项目。         
26 | 支持组件、路由、状态管理等功能。 
27 | 状态计数:{{$store.state.count}}    28 |
29 | `, 30 | setup() { // 传说中的setup 31 | // 使用外面的定义,分解setup内部的代码 32 | const { hello, clickMe } = testManage() 33 | 34 | const value = Vue.reactive({ 35 | name: 'jyk' 36 | }) 37 | 38 | 39 | return { 40 | value, 41 | hello, 42 | clickMe 43 | } 44 | } 45 | } 46 | 47 | export default home -------------------------------------------------------------------------------- /cnd/project/src/views/state.js: -------------------------------------------------------------------------------- 1 | // vue3的对象 2 | const demo = { 3 | template: ` 4 |

这里是状态演示

5 | setup 里面的 count:{{count}}
6 | `, 7 | setup() { // 传说中的setup 8 | const store = Vuex.useStore() 9 | // 在代码里面获取状态 10 | const count = Vue.computed(() => store.getters.getCount) 11 | 12 | return { 13 | count 14 | } 15 | } 16 | } 17 | 18 | export default demo -------------------------------------------------------------------------------- /cnd/project/vuex.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 82 | -------------------------------------------------------------------------------- /cnd/project/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | --------------------------------------------------------------------------------