当前位置: 首页 > news >正文

免费的空间网站iis网站启动不了

免费的空间网站,iis网站启动不了,入门做外贸是先建网站还是先参展,龙岩古田前些天发现了一个巨牛的人工智能学习网站#xff0c;通俗易懂#xff0c;风趣幽默#xff0c;忍不住分享一下给大家。点击跳转到教程。 前言 公司目前制作一个H5活动#xff0c;特别是有一定统一结构的活动#xff0c;都要码一个重复的轮子。后来接到一个基于模板的活动…  前些天发现了一个巨牛的人工智能学习网站通俗易懂风趣幽默忍不住分享一下给大家。点击跳转到教程。 前言 公司目前制作一个H5活动特别是有一定统一结构的活动都要码一个重复的轮子。后来接到一个基于模板的活动设计系统的需求便有了一下的内容。首先会对使用Vue进行开发的一些前期需要的技术储备进行简单介绍。 组件化 需求一到接就是怎么实现技术选型自然成为了第一个问题。鉴于目前web前端mvvm框架以及组件化开发方式的流行决定技术栈采用vue vuex es6 browserify。 这里首先简单说下web前端组件化开发方式的历程 最早的组件化结构代码结构可能如下 - lib/components/calendar|- calendar.css|- calendar.js|- calendar.html 将同功能的组件文件放到同一目录下结构清晰、职责明确视图、样式、脚本的关系显著也易于单元测试是独立展示和交互的最小单元。 后来 在之前基础上对组件进行了生命周期的加工(初始化、获取资源、渲染、更新、销毁等)理顺了组件的各个阶段有助于对组件实现(从初始化到销毁)的理解。并且借助于组件各个阶段的钩子可以对组件有更好的利用和扩展。对外暴露接口数据绑定或者说数据仓库的加入各种xMD模块加载器的出现也让这种这种开发方式上升了一个层级。ExtJs、YUI等都是这方面的专家。 再后来 有了之前发展进步是很大的但依然不够。组件的可复用性(基础样式基础逻辑基础属性、可复用的稳定业务逻辑等)、组件间通信、全局状态管理、甚至是能否有更好的代码组织方式等依然是问题。Angular、React、Polymer、Vue等mvvm框架和webpack、browserify等构建、预编译工具的出现正试图解决这些问题。 ES6 在正式开始vue之前因为本项目用到了es6那么就谈谈大家都关注的EcmaScript6。多余的就不说了es6经历了多年的苦终于在2015年下半年定稿正式名称EcmaScript2015。每个刚开始接触es6的人应该都有这么一个问题es6的出现到底是为了什么或者说它解决了什么。老版本es4/5虽然坑多就像Brendan Eich评价js一样优秀之处并非原创原创之处并不优秀。但我们不也是去其槽粕留其精髓一路填坑走过了吗 来直接一点es6常用的特性有class类的支持、箭头函数、对象和数组的解构、默认参数、不定参数、对象合并、let与const关键字、for of迭代、字符串模板、对象字面量增强、同名对象字面量缩写、模块化import/export、map、promise、* yeild生成器等。 这里挑出几个常用的简单说下 首先class: 在没有class的时候创建类的一种比较标准的方式是将非函数的属性放到构造函数里函数属性在原型链里添加。类的继承的实现就更为多样对象冒充、call/apply方式、原型链方式等。es6的class和extends关键字的出现给出了一个统一的规范 class People {constructor (name, age, gender){this.name name}sayName (){return this.name} }class Student extends People {constructor (name, age, gender, skill){super(name, age, gender)this.skill skill}saySkill (){return this.skill} }let tom new Student(tom, 16, male, computer)tom.sayName() // tom tom.saySkill() // computertom.__proto__ Student.prototype // true Student.__proto__ People // true 可以看出虽然是新的规范但是还是遵守js的原则对象的__proto__指向它的构造函数(类)的prototype。es6对象字面量的__proto__注入也能快速的实现继承。 在纯Vue组件中我们不会自己写class因为Vue是高度封装的我们只需要给底层的class传入我们的配置对象即可但了解es6的class也是有必要的。Vue的这点相对react来说是一个显著不同的地方。 接下来是let es6之前js只有函数作用域let的出现有了块级作用域也就算是if、else、for这类也有了作用域块内用let声明的变量外面是访问不到的在js预解析的时候是不会被提升到当前函数作用域的前面的。基于该特性在for迭代的时候每次迭代都会产生一个块级作用域的独立的迭代变量让最后的结果就是我们期待的结果。 var arr []; for (let i 0; i 10; i ){arr[i] function (){return i} }arr[6]() // 6//如果用var声明i无论多少次迭代外层的i始终被每次迭代的函数内部引用着(闭包)不会被当做垃圾回收最后的结果都指向同一个i值为10。 //以往为了避免这个问题通常会这么做for (var i 0; i 10; i ){arr[i] (function (i){return function (){return i}})(i) } 最后讲讲箭头函数 es6之前的function有一个特点函数内部的上下文并不是由该函数写在那里决定的而是由谁调用决定的谁调用函数内部的this就指向谁。然后我们有些时候并不想让他这样但又没办法只能通过先保存this或者call/apply或者bind来调整上下文。箭头函数的出现解决了这个宁人苦恼的问题因为箭头函数内的上下文(this)是由函数写在哪决定的无论被哪个对象调用上下文都不会改变。 // 在window上下文中var obj {test1 : function (){window.setTimeout(function (){console.info(this)}, 100)},test2 : function (){window.setTimeout(() {console.info(this)}, 100)},test3: () console.info(this),test4: function (){console.info(this)},test5 (){ // 对象增强写法console.info(this);} }obj.test1() // Window {} obj.test2() // obj {} obj.test3() // Window {} obj.test4() // obj {} obj.test5() // obj {} 箭头函数this锁定特性值得细细品味在目前的Vue或者React应用中有妙用。 用普通函数还是箭头函数并非绝对箭头函数也不能完全替代普通函数要用哪个由具体逻辑决定前提是要先了解他们的区别。 箭头函数还有一个特点就是能够简化return的书写。 var a function (n){return n }var b (n) n //可以省略return和花括号var c n n //如果只有一个参数中括号也可以省略a(1) // 1 b(1) // 1 c(1) // 1 从这几个简单的例子可以看出es6不仅仅是新增了几颗糖对之前js的一些不友好的地方的改善才是重点。 Vue 进入正题 Vue.js读音 /vjuː/, 类似于 view是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此它非常容易学习非常容易与其它库或已有项目整合。另一方面在与相关工具和支持库一起使用时Vue.js 也能完美地驱动复杂的单页应用。 — 文中关于vue的大部分内容引用自vue的官方文档感谢作者的工作 响应的数据绑定 div idappp{{ message }}/pinput v-modelmessage /div new Vue({el : #app,data : {message : Hello Vue.js!} }) 结果改变输入框的值p标签的文本也会对应改变。 基本工作原理input输入框的值与vue实例的message属性进行了绑定p标签的文本也与message属性进行了绑定。输入框值的变化会改变message的值message值的变化会反应到p标签的文本上。 Vue.js 的核心是一个响应的数据绑定系统它让数据与 DOM 保持同步非常简单。在使用 jQuery 手工操作 DOM 时我们的代码常常是命令式的、重复的与易错的。Vue.js 拥抱数据驱动的视图概念。通俗地讲它意味着我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。一旦创建了绑定DOM 将与数据保持同步。每当修改了数据DOM 便相应地更新。这样我们应用中的逻辑就几乎都是直接修改数据了不必与 DOM 更新搅在一起。这让我们的代码更容易撰写、理解与维护。 组件系统 组件系统是 Vue.js 另一个重要概念因为它提供了一种抽象让我们可以用独立可复用的小组件来构建大型应用。如果我们考虑到这点几乎任意类型的应用的界面都可以抽象为一个组件树 实际上一个典型的用 Vue.js 构建的大型应用将形成一个组件树。 你可能已经注意到 Vue.js 组件非常类似于自定义元素——它是 Web 组件规范的一部分。实际上 Vue.js 的组件语法参考了该规范。例如 Vue 组件实现了 Slot API 与 is 特性。但是有几个关键的不同 Web 组件规范仍然远未完成并且没有浏览器实现。相比之下Vue.js 组件不需要任何补丁并且在所有支持的浏览器IE9 及更高版本之下表现一致。必要时Vue.js 组件也可以放在原生自定义元素之内。 Vue.js 组件提供了原生自定义元素所不具备的一些重要功能比如组件间的数据流自定义事件系统以及动态的、带特效的组件替换。 组件系统是用 Vue.js 构建大型应用的基础。另外Vue.js 生态系统也提供了高级工具与多种支持库它们和 Vue.js 一起构成了一个更加“框架”性的系统。 这里简单介绍下vue最常用也较重要的两块响应式原理和组件系统。 响应式原理 Vue.js的数据观测实现原理和Angular有着本质的不同。了解Angular的读者可能知道Angular的数据观测采用的是脏检查dirty checking机制。每一个指令都会有一个对应的用来观测数据的对象叫做watcher一个作用域中会有很多个watcher。每当界面需要更新时Angular会遍历当前作用域里的所有watcher对它们一一求值然后和之前保存的旧值进行比较。如果求值的结果变化了就触发对应的更新这个过程叫做digest cycle。 脏检查有两个问题 1.任何数据变动都意味着当前作用域的每一个watcher需要被重新求值因此当watcher的数量庞大时应用的性能就不可避免地受到影响并且很难优化。 2.当数据变动时框架并不能主动侦测到变化的发生需要手动触发digest cycle才能触发相应的DOM 更新。Angular通过在DOM事件处理函数中自动触发digest cycle部分规避了这个问题但还是有很多情况需要用户手动进行触发。 Vue.js采用的则是基于依赖收集的观测机制。从原理上来说和老牌MVVM框架Knockout是一样的。依赖收集的基本原理是 1.将原生的数据改造成 “可观察对象”。一个可观察对象可以被取值也可以被赋值。 2.在watcher的求值过程中每一个被取值的可观察对象都会将当前的watcher注册为自己的一个订阅者并成为当前watcher的一个依赖。 3.当一个被依赖的可观察对象被赋值时它会通知所有订阅自己的watcher重新求值并触发相应的更新。 4.依赖收集的优点在于可以精确、主动地追踪数据的变化不存在上述提到的脏检查的两个问题。但传统的依赖收集实现比如Knockout通常需要包裹原生数据来制造可观察对象在取值和赋值时需要采用函数调用的形式在进行数据操作时写法繁琐不够直观同时对复杂嵌套结构的对象支持也不理想。 Vue.js利用了ES5的Object.defineProperty方法直接将原生数据对象的属性改造为getter和setter(这是ES5的特性需要js解释引擎的支持无法通过各种打shim补丁来实现至少现在的babel pollyfill和各种shim是没法的。这也是为什么Vue不支持IE8及以下版本的原因因为IE8的defineProperty只支持DOM对象纯Object会报错。)在这两个函数内部实现依赖的收集和触发而且完美支持嵌套的对象结构。对于数组则通过包裹数组的可变方法比如push来监听数组的变化。这使得操作Vue.js的数据和操作原生对象几乎没有差别[注:在添加/删除属性或是修改数组特定位置元素时需要调用特定的函数如obj.$add(key, value)才能触发更新。这是受ES5的语言特性所限。在操作对象类型数据的时候一定要注意这点否则无法实现响应。 变化检测 受 ES5 的限制Vue.js 不能检测到对象属性的添加或删除。因为 Vue.js 在初始化实例时将属性转为 getter/setter所以属性必须在 data 对象上才能让 Vue.js 转换它才能让它是响应的。例如 var data {a : 1} var vm new Vue({data : data }) //vm.a 和 data.a 现在是响应的vm.b 2 //vm.b 不是响应的data.b 2 //data.b 不是响应的 不过有办法在实例创建之后添加属性并且让它是响应的。 对于 Vue 实例可以使用 $set(key, value) 实例方法 vm.$set(b, 2) //vm.b 和 data.b 现在是响应的 对于普通数据对象可以使用全局方法 Vue.set(object, key, value) Vue.set(data, c, 3) //vm.c 和 data.c 现在是响应的 有时你想向已有对象上添加一些属性例如使用 Object.assign() 或 _.extend() 添加属性。但是添加到对象上的新属性不会触发更新。这时可以创建一个新的对象包含原对象的属性和新的属性 // 不使用 Object.assign(this.someObject, {a : 1,b : 2}) this.someObject Object.assign({}, this.someObject, {a : 1, b : 2}) 计算属性的奥秘 你应该注意到 Vue.js 的计算属性不是简单的 getter。计算属性持续追踪它的响应依赖。在计算一个计算属性时Vue.js 更新它的依赖列表并缓存结果只有当其中一个依赖发生了变化缓存的结果才无效。因此只要依赖不发生变化访问计算属性会直接返回缓存的结果而不是调用 getter。 为什么要缓存呢假设我们有一个高耗计算属性 A它要遍历一个巨型数组并做大量的计算。然后可能有其它的计算属性依赖 A。如果没有缓存我们将调用 A 的 getter 许多次超过必要次数。 由于计算属性被缓存了在访问它时 getter 不总是被调用。考虑下例 var vm new Vue({data : {msg : hi},computed : {example : function (){return Date.now() this.msg}} }) 计算属性 example 只有一个依赖 vm.msg 。 Date.now()  不是 响应依赖因为它跟 Vue 的数据观察系统无关。因而在访问  vm.example  时将发现时间戳不变除非  vm.msg  变了。 有时希望 getter 不改变原有的行为每次访问  vm.example  时都调用 getter。这时可以为指定的计算属性关闭缓存 computed : {example : {cache : false,get : function (){return Date.now() this.msg}} } 现在每次访问  vm.example  时时间戳都是新的。但是只是在 JavaScript 中访问是这样的数据绑定仍是依赖驱动的。如果在模块中这样绑定计算属性  {{example}} 只有响应依赖发生变化时才更新DOM。 组件系统 组件Component是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素封装可重用的代码。在较高层面上组件是自定义元素Vue.js 的编译器为它添加特殊功能。在有些情况下组件也可以是原生 HTML 元素的形式以 is 特性扩展。 1.创建和注册组件 可以用  Vue.extend()  创建一个组件构造器 var MyComponent Vue.extend({template : divA custom component!/div })要把这个构造器用作组件需要用  Vue.component(tag, constructor)  注册(这个注册是全局的) //全局注册组件tag 为 my-component Vue.component(my-component, MyComponent) 组件在注册之后便可以在父实例的模块中以自定义元素  my-component  的形式使用。要确保在初始化根实例之前注册了组件 div idexamplemy-component/my-component /div 最后渲染为 div idexampledivA custom component!/div /div 当然可以让组件只能用在其它组件内用实例选项 components 注册比如 var Child Vue.extend({ /* ... */ })var Parent Vue.extend({template : ...,components : {// my-component 只能用在父组件模板内my-component: Child} }) 这种局部注册的方式也适用于其它资源比如指令、过滤器和过渡。他们都支持全局和局部组件注册。 前面提到组件是可以被复用的多个实例可能会共享一个组件构造器那么请注意一个组件选项的问题 传入 Vue 构造器的多数选项也可以用在  Vue.extend() 中不过有两个特例 data 和 el。试想如果我们简单地把一个对象作为 data 选项传给  Vue.extend()  var data {a : 1} var MyComponent Vue.extend({data : data }) 这么做的问题是 MyComponent 所有的实例将共享同一个 data 对象因为对象是引用传递的这基本不是我们想要的因此我们应当使用一个函数作为 data 选项让这个函数返回一个新对象 var MyComponent Vue.extend({data : function (){return {a : 1}} }) 同理el 选项用在  Vue.extend()   中时也须是一个函数。 2.使用props传递数据 当一个组件内部还有一个子组件的时候由于组件实例的作用域是孤立的这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。这时父组件可以使用props把数据传给子组件 “prop” 是组件数据的一个字段期望从父组件传下来。子组件需要显式地用 props 选项 声明 props Vue.component(child, {//camelCase in JavaScriptprops : [myMessage],template : span{{ myMessage }}/span }) 然后向它传入一个普通字符串 child my-messagehello!/child 子组件的渲染结果 由于命名的习惯请注意camelCase和kebab-caseHTML 特性不区分大小写。名字形式为 camelCase 的 prop 用作特性时需要转为 kebab-case(短横线隔开)。 根据vue响应的特性props也可以是动态的 类似于用 v-bind 绑定 HTML 特性到一个表达式也可以用  v-bind  绑定动态 Props 到父组件的数据。每当父组件的数据变化时也会传导给子组件 divinput v-modelparentMsgbr/child v-bind:my-messageparentMsg/child /div 也可以使用v-bind的缩写语法来简化绑定 child :my-messageparentMsg/child 渲染结果 改变输入框的值子组件的文本会跟着改变 关于props的其他介绍请参考 props 3.父子组件的通信 子组件可以用  this.$parent  访问它的父组件。根实例的后代可以用 this.$root 访问它。父组件有一个数组  this.$children 包含它所有的子元素。 尽管可以访问父链上任意的实例不过子组件应当避免直接依赖父组件的数据尽量显式地使用 props 传递数据。另外在子组件中修改父组件的状态是非常糟糕的做法因为 这让父组件与子组件紧密地耦合 只看父组件很难理解父组件的状态。因为它可能被任意子组件修改理想情况下只有组件自己能修改它的状态。 Vue 实例实现了一个自定义事件接口用于在组件树中通信。这个事件系统独立于原生 DOM 事件用法也不同。 每个 Vue 实例都是一个事件触发器 使用  $on()  监听事件 使用  $emit()  在它上面触发事件 使用  $dispatch()  派发事件事件沿着父链冒泡 使用  $broadcast()  广播事件事件向下传导给所有的后代。 不同于 DOM 事件Vue 事件在冒泡过程中第一次触发回调之后自动停止冒泡除非回调明确返回  true 。 一个简单的例子 !-- 子组件模板 -- template idchild-templateinput v-modelmsgbutton v-on:clicknotifyDispatch Event/button /template!-- 父组件模板 -- div idevents-examplepMessages: {{ messages | json }}/pchild/child /div 在子组件的输入框输入值以后点击按钮父组件的Messages:[]文本会对应变化 4.再来说说动态组件 多个组件可以使用同一个挂载点然后动态地在它们之间切换。使用保留的  component 元素动态地绑定到它的 is 特性 new Vue({el : body,data : {currentView : home},components : {home : { /* ... */ },posts : { /* ... */ },archive : { /* ... */ }} }) component :iscurrentView!-- 组件在 vm.currentview 变化时改变 -- /component 如果把切换出去的组件保留在内存中可以保留它的状态或避免重新渲染。为此可以添加一个  keep-alive  指令参数 component :iscurrentView keep-alive!-- 非活动组件将被缓存 -- /component 其他动态组件的详细介绍请参考动态组件 在创建复杂应用的时候动态组件或许就显得不那么灵活了这时可以使用路由vue-router路由扩展可以看做是动态组件的升级版可参考vue-router 5.最后组件实例的生命周期 Vue 实例在创建时有一系列初始化步骤——例如它需要建立数据观察编译模板创建必要的数据绑定。在此过程中它也将调用一些生命周期钩子给自定义逻辑提供运行机会。例如 created 钩子在实例创建后调用 var vm new Vue({data : {a : 1},created : function (){// this 指向 vm 实例console.log(a is: this.a)} }) // a is: 1 也有一些其它的钩子在实例生命周期的不同阶段调用如 compiled、 ready 、destroyed。钩子的 this 指向调用它的 Vue 实例。一些用户可能会问 Vue.js 是否有“控制器”的概念答案是没有。组件的自定义逻辑可以分割在这些钩子中。 声明周期的图示 组件的简单介绍就到这里。 Vuex 在大型应用中状态管理常常变得复杂因为状态分散在许多组件内在不同的作用域内。以vue来说当使用vue-router以及组件化开发(.vue)来构建大型单页应用的时候组件之间状态的数据的传递会很困难虽然props、dispatch、broadcast等能够进行跨组件的数据传递但是大量使用它们会使组件之间的耦合程度很高组件越多层级越多维护起来就越复杂。怎么办呢能否在全局提供一个状态管理构架 这里得提出一个概念Flux Flux是Facebook用来构建用户端的web应用的应用程序体系架构。它通过利用数据的单向流动为React的可复用的视图组件提供了补充。相比于形式化的框架它更像是一个架构思想不需要太多新的代码你就可以马上使用Flux构建你的应用。 Flux应用主要包括三部分dispatcher、store和viewsReact components千万不要和MVC(model-View-Controller)搞混。Controller在Flux应用中也确实存在但是是以controller-view的形式。view通常处于应用的顶层它从stores中获取数据同时将这些数据传递给它的后代节点。另外action creators - dispatcher辅助方法 - 一个被用来提供描述应用所有可能存在的改变的语义化的API。把它理解为Flux更新闭环的第四个组成部分可以帮助你更好的理解它。 一句话Flux就是手动将Action从数据流底层视图中的事件手动绑定到数据顶层的数据流架构。 单向数据流的设计目的任何UI不能直接对数据有写操作就是防止同一份数据有多个地方同时在写。相对于直接进行双向绑定编码稍微会复杂一点但换来了排错和维护的便捷。 Flux 架构常用于 React 应用中但它的核心理念也可以适用于 Vue.js 应用。比如 Vuex 就是一个借鉴于 Flux但是专门为 Vue.js 所设计的状态管理方案。React 生态圈中最流行的 Flux 实现 Redux 也可以通过简单的绑定和 Vue 一起使用。 什么是Vuex Vuex 是一个专门为 Vue.js 应用所设计的集中式状态管理架构。它借鉴了 Flux 和 Redux 的设计思想但简化了概念并且采用了一种为能更好发挥 Vue.js 数据响应机制而专门设计的实现。 为什么需要它 当你的应用还很简单的时候你多半并不需要 Vuex。也不建议过早地使用 Vuex。但如果你正在构建一个中型以上规模的 SPA你很有可能已经需要思考应该如何更好地归纳 Vue 之外应用的其他组成部分。这就是 Vuex 要大显身手的时刻。 我们在单独使用 Vue.js 的时候通常会把状态储存在组件的内部。也就是说每一个组件都拥有当前应用状态的一部分整个应用的状态是分散在各个角落的。然而我们经常会需要把状态的一部分共享给多个组件。一个常见的解决策略为使用定制的事件系统让一个组件把一些状态“发送”到其他组件中。这种模式的问题在于大型组件树中的事件流会很快变得非常繁杂并且调试时很难去找出究竟哪错了。 为了更好的解决在大型应用中状态的共用问题我们需要对组件的 组件本地状态(component local state) 和 应用层级状态(application level state) 进行区分。应用级的状态不属于任何特定的组件但每一个组件仍然可以监视(Observe)其变化从而响应式地更新 DOM。通过汇总应用的状态管理于一处我们就不必到处传递事件。因为任何牵扯到一个以上组件的逻辑都应该写在这里。此外这样做也能让我们更容易地记录并观察状态的变更Mutation原意为突变甚至可以实现出华丽如时光旅行一般的调试效果。译注是时候安利一波 vue-devtools 了 Vuex 也对如何管理分撒各地的状态增加了一些约束但仍保留有足够面对真实使用场景的灵活性。 一定需要它吗 Vuex有这么多好处但这并不代表我们一定就要在项目中使用它。假如我们的项目是一个管理平台系统一般无非是列表跳转详情这种搭配不同列表页面、不同详情页面之间没有什么相互关联或者需要共享的状态也不会出现某一个需要获取到所有详情页面的状态这种需求。这时候我们是不需要Vuex的使用它只会增加项目的复杂度。下面将介绍到的活动发布系统最后创建的时候需要获取到所有组件的数据这个时候使用Vuex显得十分有必要。如果你都不知道是否需要Vuex那就不用它。 最简单的store 创建 Vuex store 的过程相当直截了当 - 只要提供一个初始化的 state 对象以及一些 mutations import Vuex from vuexconst state {count : 0 }const mutations {INCREMENT (state){state.count } }export default new Vuex.Store({state,mutations }) 现在你可以通过  store.state   来读取 state 对象还可以通过 dispatch 某 mutation 的名字来触发这些状态变更 store.dispatch(INCREMENT)console.log(store.state.count) // - 1 如果你倾向于对象风格的分发方式你可以用这种语法 // 效果同上 store.dispatch({type : INCREMENT }) 再次强调我们通过分发 mutation 的方式而非直接改变  store.state 是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显这样你在阅读代码的时候能更容易地解读应用内部的状态改变。此外这样也让我们有机会去实现一些能记录每次状态改变保存状态快照的调试工具。有了它我们甚至可以实现如时间穿梭般的调试体验。 Vuex 使用 单一状态树 —— 是的用一个对象就包含了全部的应用层级状态。至此它便作为一个『唯一数据源(SSOT)』而存在。这也意味着每个应用将仅仅包含一个 store 实例。单状态树让我们能够直接地定位任一特定的状态片段在调试的过程中也能轻易地取得整个当前应用状态的快照。 以上只是一个用来展示 store 究竟是什么的一个极简例子。再谈谈三哥核心概念State状态Mutations变更 和 Actions动作。 State和Getters 1.安装 Vuex 并且将您的根组件引入 store 实例 import Vue from vue import Vuex from vuex import store from ./store import MyComponent from ./MyComponent// 关键点教 Vue 组件如何处理与 Vuex 相关的选项 Vue.use(Vuex)var app new Vue({el : #app,store, // 把 store 对象提供给 “store” 选项这可以把 store 的实例注入所有的子组件components : {MyComponent} }) 通过在根实例中注册 store 选项该 store 实例会注入到根组件下的所有子组件中且子组件能通过  this.$store  访问到。不过事实上我们几乎不会需要直接引用它。 2.在子组件中通过在  vuex.getters  选项里定义的 getter 方法来读取状态 // MyComponent.jsexport default {template : ...,data (){ ... },// 此处为我们从 store 实例中取回状态的位置vuex : {getters : {// 该 getter 函数将会把仓库的 store.state.count 绑定为组件的 this.countcount : (state) state.count}} } 请留意 vuex 的这个特殊选项译注getters 子对象。它是我们指定当前组件能从 store 里获取哪些状态信息的地方。它的每个属性名将对应一个 getter 函数。该函数仅接收 store 的整个状态树作为其唯一参数之后既可以返回状态树的一部分也可以返回从状态树中求取的计算值。而返回结果则会依据这个 getter 的属性名添加到组件上用法与组件自身的计算属性一毛一样。 组件不能直接修改store实例的状态 请始终记得非常重要的这点就是组件永远都不应该直接改变 Vuex store 的状态。因为我们想要让状态的每次改变都很明确且可追踪Vuex 状态的所有改变都必须在 store 的 mutation handler (变更句柄) 中管理。为了强化该规则在开启(严格模式(Strict Mode))时若有 store 的状态在 mutation 句柄外被修改Vuex 就会报错。现在有了这一规则我们 Vue 组件的职能就少了很多他们通过只读的 getter 与 Vuex store 的状态相绑定组件唯一能影响全局状态的方法就是想办法触发 mutations我们接下来会谈到。若有必要组件仍然能够处理和操作本地状态但是我们不再在单独的组件中放置任何数据请求或全局状态变更的逻辑。这些操作全部都集中于 Vuex 相关的文件中这样能让大型应用变得更容易理解和维护。 Mutation Mutations 本质上是一个事件系统每个 mutation 都有一个 事件名 (name) 和 一个 回调函数 (handler). 任何一个 Mutation handler 的第一个参数永远为所属 store 的整个 state 对象 import Vuex from vuexconst store new Vuex.Store({state : {count : 1},mutations : {INCREMENT (state){// 改变 statestate.count }} }) 用全部大写命名 mutation 是一个惯例方便将它和 actions 区分开。 你不能直接调用 mutation handler. 这里传入 Store 构造函数的选项更像是在注册事件回调当INCREMENT 事件被触发时调用这个 handler。触发 mutation handler 的方法是 dispatch 一个 mutation 的事件名 store.dispatch(INCREMENT) Mutation必须是同步函数 因为当 mutation 触发的时候回掉函数还没有被调用我们不知道什么时候回调函数实际上被调用。任何在回调函数中进行的的状态的改变都是不可追踪的。 Mutation必须遵守Vue的响应系统规则 1.尽可能在创建 store 时就初始化 state 所需要的所有属性。 2.当添加一个原本不存在的属性时需要使用  Vue.set(obj, newProp, 123)  或者拷贝并替换原本的对象。利用 stage 2 的语言特性 object spread syntax我们可以使用这样的语法:   state.obj {...state.obj, newProp : 123}  Actions Actions 是用于分发 mutations 的函数。按照惯例Vuex actions 的第一个参数是 store 实例附加上可选的自定义参数。 // 最简单的 action function increment (store){store.dispatch(INCREMENT) }// 带附加参数的 action // 使用 ES2015 参数解构 function incrementBy ({dispatch}, amount){dispatch(INCREMENT, amount) } 乍一眼看上去感觉多此一举我们直接分发 mutations 岂不更方便实际上并非如此还记得 mutations 必须同步执行这个限制么Actions 就不受约束我们可以在 action 内部执行异步操作比如执行一个ajax请求数据的操作 function getData ({dispatch}){ajax ({url : ...,data : {...},success : (data) {dispatch(SET_DATA, data)}}) } 我们可以这样在组件中调用actions // 某组件内部// 导入actions import {incrementBy} from ./actionsconst vm new Vue({vuex : {getters : { ... }, // state gettersactions : {incrementBy}} }) 上述代码所做的就是把原生的 incrementBy action 绑定到组件的 store 实例中暴露给组件一个  vm.increamentBy  实例方法。所有传递给  vm.increamentBy 的参数变量都会排列在 store 变量后面然后一起传递给原生的 action 函数所以调用  vm.incrementBy(1) 等价于  incrementBy(vm.$store, 1) 。虽然多写了一些代码但是组件的模板中调用 action 更加省力了 button v-on:clickincrementBy(1)increment by one/button 通常在大型 App 中action 应该按不同目的进行 分组 / 模块化 的管理具体请参考 Actions 下面再谈谈一个重要的东西数据流 为了更好地理解 Vuex app 中的数据流我们来开发一个简单的计数器 app。注意这个例子仅仅是为了更好地解释概念在实际情况中并不需要在这种简单的场合使用 Vuex. // store.js import Vue from vue import Vuex from vuexVue.use(Vuex)// 应用初始状态 const state {count : 0 }// 定义所需的 mutations const mutations {INCREMENT (state){state.count },DECREMENT (state){state.count --} }// 创建 store 实例 export default new Vuex.Store({state,mutations }) // actions.js export const increment ({ dispatch }) dispatch(INCREMENT) export const decrement ({ dispatch }) dispatch(DECREMENT) !- temmplate -- divClicked: {{ count }} timesbutton v-on:clickincrement/buttonbutton v-on:clickdecrement-/button /div // 仅需要在根组件中注入 store 实例一次即可 import store from ./store import {increment, decrement} from ./actionsconst app new Vue({el : #app,store,vuex : {getters: {count: state state.count},actions: {increment,decrement}} }) 你会注意到组件本身非常简单它所做的仅仅是绑定到 state、然后在用户输入时调用 actions。 你也会发现整个应用的数据流是单向的正如 Flux 最初所定义的那样 1.用户在组件中的输入操作触发 action 调用。 2.Actions 通过分发 mutations 来修改 store 实例的状态。 3.Store 实例的状态变化反过来又通过 getters 被组件获知。 最后Vuex 并不强制要求所有的状态都必须放在 Vuex store 中 如果有些状态你觉得并没有需要对其变化进行追踪那么你完全可以把它放在 Vuex 外面(比如作为组件的本地状态)。比如公共组件对外的接口通过props传递数据更为有效。 Vuex的完整介绍请参考Vuex vue-devtools vue-devtools是chrome的一个vue开发插件可以在chrome商店下载crx扩展包进行安装。提供Components和Vuex预览(state变化跟踪等)功能有助于开发和调试。 可以看到组件的prop属性、计算属性、vue getter属性等以及Vuex中的触发的mutation、state 当前的值等我们可能关注的内容都直观地展示了出来。 Vue模块化  对于大型项目为了更好地管理代码使用模块构建系统非常必要。推荐代码使用 CommonJS 或 ES6 模块然后使用 Webpack 或 Browserify 打包。 Webpack 和 Browserify 不只是模块打包器。两者都提供了源码转换 API通过它可以用其它预处理器转换源码。例如借助 babel-loader 或 babelify 代码可以使用 ES2015/2016 语法。 你可以使用 Webpack vue-loader 或 Browserify vueify 构建这些单文件 Vue 组件。 选择哪种构建工具取决于你的经验和需求。Webpack 的功能更强大如代码分割将静态资源当作模块提取组件的 CSS 到单独的一个文件等不过它的配置相对复杂一点。如果你不需要 Webpack 的那些功能使用 Browserify 更简单最快的构建方式是使用官方出品的脚手架工具 vue-cli。参考vue-cli 活动模板设计系统 这个设计系统只是对活动模板要展示的内容进行设计具体的样式和交互由活动h5页面根据视觉和交互设计来定夺。活动里面的每一个子项都可以抽象为一个组件h5展示端拿到每个组件的内容再套上对应组件的样式和交互逻辑最终就形成了一个h5活动页面。 每一个活动组件对应三个模式组件 1.标签组件通过拖动来创建对应类型的组件 2.预览组件展示当前组件各项的内容 3.编辑组件用来编辑当前选中的组件的各项内容 完成后大概是这样的以一个最简单的节标题组件为例 如上图所示左侧容器排列着这些常用组件的标签。将活动需要的组件标签拖入预览区域后会生成对应的预览组件和编辑组件点击这个预览组件组件编辑区域会显示对应的编辑组件在编辑组件中可以对组件各项进行编辑。编辑完成后通过事先的数据绑定预览区域对应的组件就会更新视图显示组件当前的最新内容。 以上就是这个系统的一个大概方案下面谈谈具体的实现。 首先从标签区域开始 标签组件是每个活动组件的开端也就说每一个标签组件必须有一个属性来标识它代表的是哪一个活动组件。那就先给它们指定类型 type 节标题  type sectionTitle  投票  type vote 正文  type content  用户  type user  图片  type image  视频  type video  音频  type audio  跳转链接  type link 然后每当我们拖动一个标签组件到预览区域再根据该标签组件的type生成对应的预览和编辑组件。预览和编辑组件需要确定的无非就是有哪些编辑项这些编辑项是什么内容。以节标题组件为例它就只有一个编辑项节标题的文本。也就是说节标题的预览组件用来显示节标题的文本编辑组件需要有一个文本域来对节标题文本进行编辑在模板事先绑定好对应的数据文本域的数据变化会反应到预览组件的DOM上。 我们需要有一个保存所有组件数据(对象)的容器可以使用一个数组。 我更喜欢操作一个数组而不是对象的原因vue对数组的基本方法(push、splice、shift等)都进行了封装通过这些方法来改变数组的数据结果都是响应的。而在保持响应的情况下改变对象的数据要麻烦些特别是复杂的嵌套对象。如果使用对象可以通过id直接匹配到对应数据通过数组需要遍历一下。但是有了es6的for of代码还是很简单而且也不是在操作DOM性能影响不大。 //widgetData.js[{id : 100,type : vote, ...}, //投票{id : 101,type : image, ...}, //图片{id : 102,type : video, ...}, //视频 ] 每个组件数据对象的id属性是唯一的是拖入标签组件时生成的这个id属性是关联预览组件与对应编辑组件的关键通过它可以找到每个预览组件对应的编辑组件。为什么不通过type来判断呢因为每个活动可能有多个相同的组件比如节标题。通过type没法确定对应关系。 这里我们通过Vuex创建一个store来存储及修改这个数组(官方点的说法就是管理state状态)。按照上面提到的Vuex的数据流规则UI不允许直接修改数据。在编辑项里面改变某项输入框的值并不是直接改变了对应组件数据中那一项的值而是通过DOM事件触发对应的actionaction再派发对应的mutaion处理函数来修改state。这种方式可以确保所有对某项组件数据的修改都是通过触发某一个公共的action来完成的这个action就是进行某项修改的统一和唯一的入口。 当我们知道需要生成什么预览和编辑组件的时候并放进组件数据容器的时候我们就必须知道这个组件到底有哪些编辑项(除了组件类型外我们放入的这个组件数据对象还需要哪些属性)这时候我们就需要一个map来管理组件type和组件编辑项的关系以活动的投票组件为例 根据需求投票组件需要有以下编辑项 1.投票的标题 2.投票项每项要有一个名称后续每项可能还会有其他属性(类似正确选项的标记等) //typeDataMap.jsexport default {vote : {type : vote,title : 投票标题文本,items : [{name : 投票项1}, //每个投票项{name : 投票项2},{name : 投票项3}]} } 只要知道是什么类型通过  typeData[type]  就能获取到组件数据并存入组件数据容器了。由于我们在预览组件和编辑组件的模板视图已事先对DOM进行了数据绑定当我们改变组件容器中某个组件的数据项时更新就会反应到DOM上。当我们保存整个模板的时候只需要取出组件数据容器中的值就行了其实也就是那个数组本身。H5展示端通过这个组件数据数组可以拿到组件的数据以及排序按照定好的模板渲染出来即可。当然像投票组件这类有交互数据的组件该系统设计的模板只是确定了要展示的固定的内容。具体的投票总数、每项投票数等属性需要后端处理后插入到对应组件数据里面供展示端显示。 整个系统大概的设计思想就是这样的下面挑些具体的来讲讲 标签组件 因为标签组件的表现和交互逻辑等都是一致的这里做了一个公共可复用的标签组件对外接收两个参数title(标签文本)和type(标签类型)。在标签容器组件创建一个包含所有标签组件数据对象的数组在模板视图中遍历这个数组就创建了所有的标签组件。 公共标签组件的统一的属性和方法等存入了一个对象字面量里面导入以后通过mixin方式混合组件就会拥有这些属性和方法。目前这样做的意义不大因为已经有一个公共的标签组件了mixin里面的东西完全可以直接写到这个公共组件内。但如果每个类型的标签组件都是一个单独的.vue组件文件mixin的好处就体现出来了可复用、易维护。 具体实现的代码省略掉样式 //labelWrapper.vue 标签组件容器(组件标签区域)templatediv classlabel-wrapperdiv classlabel-title组件标签区域/divdiv classlabel-boxcommon-label v-forlabel in labelArr :titlelabel.title :typelabel.type/common-label/div/div /templatescriptimport commonLabel from ./widget/commonLabel.vue //导入公共标签组件export default {name : label_wrapper,components : {commonLabel //注册为子组件(es6同名对象字面量缩写)},data (){return {labelArr : [{title : 节标题, type : sectionTitle},{title : 投票, type : vote},{title : 正文, type : content},{title : 用户, type : user},{title : 图片, type : image},{title : 视频, type : video},{title : 音频, type : audio},{title : 跳转链接, type : link}]}}} /scriptstyle langstylus/*...*/ /style //commonLabel.vue 公共标签组件templatediv classlabel-item-wrapper title拖入模板设计区域 draggabletrue dragstartdragStartimg classlabel-icon alt{{title}} :srciconUrlspan classlabel-text{{title}}/span/div /templatescript//导入mixinimport labelMixin from ./mixin/labelMixinexport default {name : label,props : {title : String,type : String},mixins : [labelMixin],computed : {iconUrl (){return this.type .png}}} /scriptstyle langstylus/*...*/ /style //labelMixin.jsimport typeDataMap from ./typeDataMapexport default {methods : {dragStart (e){var id parseInt(Date.now() parseInt(Math.random() * 90))var widgetData typeDataMap[this.type]var dt e.dataTransferwidgetData[id] iddt.setData(id, id)dt.setData(type, this.type)dt.setData(widgetData, JSON.stringify(widgetData))}} } 预览组件 预览组件相对较简单除了数据的绑定就是拖动排序。拖动排序的实现是通过html5原生的drag事件基于vue数据驱动的原理拖动的时候并不需要去手动改变预览区域内各组件的DOM顺序只需要改变组件数据数组里面各数据对象的index即可数据的变化会反应到DOM上。简单的节标题预览组件 templatediv classpreview-item-wrapper draggabletrue :class{active: isActive} clickshowEdit dragoverallowDrop dragstartdragStart dropdropInspan classpreview-item-del :class{active: isActive} title删除该组件div v-on:clickdelMex/div/spanlabel classpreview-item-label- 节标题 -/labeldiv classpreview-item-input-wrapperdiv classtitle-text{{text}}/div/div/div /templatescript//导入actionimport {addPreviewAndData, deleteWidgetPreview, changeWidgetEdit, changPreviewAndDataIndex} from ../../../store/actions//导入mixinimport previewMixin from ./mixin/previewMixinexport default {name : sectionTitle_preview,mixins : [previewMixin],props : {id : Number,index : Number},computed : {//mixin外的私有属性text (){for (let value of this.widgetDataArr)if (value.id this.id) return value.text}},vuex : {//绑定mixin需要的属性和方法getters : {widgetDataArr : (state) state.widgetDataArr,currentEditWidgetId : (state) state.currentEditWidgetId},actions : {addPreviewAndData,deleteWidgetPreview,changeWidgetEdit,changPreviewAndDataIndex}}} /scriptstyle langstylus/*...*/ /style /*** previewMixin.js* 预览组件的mixin* 提取同类组件之间可复用的计算属性与方法*/export default {computed : {//该预览组件是否为当前点击的isActive (){return this.id this.currentEditWidgetId}},methods : {//删除该预览组件delMe (){this.deleteWidgetPreview(this.id)},//显示该预览组件对应的编辑组件showEdit (){this.changeWidgetEdit(this.id)},//允许向该预览组件拖放其他组件allowDrop (e){e.preventDefault();},//开始拖放该预览组件dragStart (e){var dt e.dataTransferdt.setData(index, this.index)},//向该预览组件拖放其他组件(预览组件或者标签组件)dropIn (e){e.preventDefault()e.stopPropagation()var dt e.dataTransfervar id parseInt(dt.getData(id))if (id){ //有id表明拖入的是标签组件var type dt.getData(type)var widgetData JSON.parse(dt.getData(widgetData))this.changeWidgetEdit(id)this.addValidation(id) //添加组件验证项} else {var index parseInt(dt.getData(index))this.changPreviewAndDataIndex(index, this.index)}//清空dataTransferdt.clearData()}} } 编辑组件 还是以节标题组件为例 templatediv classedit-item-wrapperlabel classedit-item-label节标题文本/labelvalidator nametitleValidatordiv classedit-item-input-wrappertextarea classtitle-edit-input placeholder必填项16字以内 v-modeltext v-validate:text{required: {rule: true,message: 请填写节标题文本},maxlength: {rule: 16,message: 节标题文本限制在16字以内}} inputinputValue validonValid invalidonInvalid/textareadiv classedit-input-err v-if$titleValidator.text.required{{$titleValidator.text.required}}/divdiv classedit-input-err v-if$titleValidator.text.maxlength{{$titleValidator.text.maxlength}}/div/div/validator/div /templatescript//导入actionimport {changeWidgetData, changeValidation} from ../../../store/actions//导入mixinimport editMixin from ./mixin/editMixinexport default {name : title_edit,mixins : [editMixin],props : {id : Number},computed : {//mixin外的私有属性text (){for (let value of this.widgetDataArr)if (value.id this.id) return value.text}},methods : {//mixin外的私有方法inputValue (e){this.changeWidgetData(this.id, text, e.target.value)}},vuex : {getters : {widgetDataArr : (state) state.widgetDataArr},actions : {changeWidgetData,changeValidation}}} /scriptstyle langstylus/*...*/ /style /*** editMixin.js* 编辑组件的mixin*/export default {data (){return {//isValid : false}},methods : {onValid (){ //验证通过this.isValid truethis.changeValidation(this.id, true)},onInvalid (){ //验证失败this.isValid falsethis.changeValidation(this.id, false)}} } 还有一些公共组件以及store等就不再介绍了前面的讲解已基本包含差不多就到这里了。最后完成后是这样的 活动的展示端 在编辑完所有组件后保存该活动ID和一个包含所有组件数据对象的数组到server端数据库中。我司的活动是用H5做的H5页面按活动ID到server获取到该活动的组件数据按照数组中的顺序和内容依次渲染即可生成对应的H5活动页面。当然H5端也需要有一套组件化的实现方案并与活动发布端有统一的组件和相应属性的命名规范等。 本文由浅入深阐述了ES6和Vue相关的内容和mvvm的思想。其中关于Vue API概述的内容大部分引用自Vue官方1.x中文文档非本人原创并翻译 。 转自https://www.cnblogs.com/rock-roll/p/5692891.html
http://www.pierceye.com/news/317513/

相关文章:

  • 深圳建网站公司哪家好wordpress 采集系统
  • 网站发布与推广广州品牌网站设计公司
  • 帮忙做公司网站淘宝运营培训多少钱
  • 湘潭网站建设搭建WordPress多条件搜索
  • 信息技术 网站建设教案官网定制
  • 丽水专业网站建设公司淘宝美工培训推荐
  • 如何比较网站小程序商城开发平台
  • 品牌推广宣传词seo整站优化更能准确获得客户
  • 五八同城找工作招聘信息seo服务如何收费
  • 冒充it男给某网站做修复欧美专业牙科医院网站网页源码
  • 搭建网站需要做什么大型 视频网站开发
  • 济南招考院网站网站建设需要些什么东西
  • 手机怎么搭建网站厦门 做网站
  • 网站底部友情链接典型十大优秀网络营销案例
  • 公司装修工程免费推广软件平台seo博客
  • 树状结构的网站一个人可以做多少网站
  • 什么网站是专门做评论赚钱的响应式网站标准尺寸
  • 梅州市建设培训中心网站济南网上房地产
  • 海口网站提升排名专业做公司logo的网站
  • fm网站开发做网站自动赚钱
  • 网站二级导航制作wordpress找人做
  • 网站建设市场占有率网站开发工程师的职责
  • wordpress 单本小说站做网站前景
  • 只做网站可以在百度里收到吗平面设计是干嘛的
  • 义乌网站建设优化推广网站开发需要哪些人怎么分工
  • 关键词排行优化网站企业seo外包
  • 自适应网站怎么做广西建设局建设行政主管部网站
  • 把网站做成手机版学网页设计的培训
  • 陕西省建设厅执业资格注册中心网站报名系统网站建设重庆最加科技
  • 网站优化软件排名器wordpress E405