📖 earlier posts 📖
在 Vue.js 中,v-bind
指令提供了 :class
/style
参数进行处理,并对此针对性的进行了增强表达式类型除了字符串之外,还可以是对象或是数组。
Class 绑定 通常我们可以使用 :class
对象以动态的切换 class
,但这个 class 的使用与否取决与属性 isActive
的 Truthy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <style> .active { padding : 1. 5em; border : 1px solid #e4e4e4; } .err { border : 1px solid red; color : red; padding : 1. 5em; } </style> <div id ="app" > <p v-bind:class ="{active: isActive, err: isError}" > {{message}}</p > </div > <script > const app = Vue .createApp ({ data ( ) { return { message : 'This is v-bind:class' , isActive : true , isError : false } } }) const vm = app.mount ('#app' ) </script >
Truthy(真值) ,在 JavaScript 的定义中,值得是布尔值的上下文转换后的值为 true ,除下述意外皆为真值。也就是说当我们在 :class
中使用的是 :class="{active: true}"
才会使用该样式。
name
false
0
“”
null
undefined
Nan
对于上下文 (context) 是一个任务中不不可少的一组数据,当数据任务中断时,这次之后仍然可以在同一个位置继续执行。
任务可以是进程或线程
数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <style> .active { padding : 1. 5em; border : 1px solid #e4e4e4; } .err { border : 1px solid red; color : red; padding : 1. 5em; } </style> <div id ="app" > <p v-bind:class ="[headerActive, paddingError]" > {{message}}</p > </div > <script > const app = Vue .createApp ({ data ( ) { return { message : 'This is v-bind:class' , headerActive : 'active' , paddingError : false } } }) const vm = app.mount ('#app' ) </script >
三元表达式 在下述的例子中,假设 isActive
的 Truthy 为 false,则直接使用 paddingError
作为样式,反之使用 headerActive
作为其 Class,这提供了两种写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <style> .active { padding : 1. 5em; border : 1px solid #e4e4e4; } .err { border : 1px solid red; color : red; padding : 1. 5em; } </style> <div id ="app" > <p v-bind:class ="[isActive ? headerActive : '', paddingError]" > {{message}}</p > </div > <script > const app = Vue .createApp ({ data ( ) { return { message : 'This is v-bind:class' , headerActive : 'active' , paddingError : 'err' , isActive : true } } }) const vm = app.mount ('#app' ) </script >
Style 对象语法 v-bind 的 style 语法非常的类似于 class ,需要注意的是 CSS 属性名可以使用驼峰式(camelCase)或短横线分割(kebab-case)的进行命名:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div id="app" > <p v-bind:style ="{border: borderBold, padding: '1.5em'}" > {{message}}</p > </div> <script > const app = Vue .createApp ({ data ( ) { return { message : 'This is v-bind:style' , borderBold : '1px solid #e4e4e4' } } }) const vm = app.mount ('#app' ) </script >
数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id="app" > <p v-bind:style ="[borderStyle, paddingStyle]" > {{message}}</p > </div> <script > const app = Vue .createApp ({ data ( ) { return { message : 'This is v-bind:style' , borderStyle : 'border:1px solid #e4e4e4' , paddingStyle : 'padding:1em' } } }) const vm = app.mount ('#app' ) </script >
计算属性 (computed)
getter Vue 提供了 computed 和 watch 属性,分别实现了计算属性和侦听器,其中计算属性为模板提供了一种家但便捷的表达式虽然设计他们的初衷是用于实现简单的运算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div id="app" > <p > {{projectMessage}}</p > </div> <script > const app = Vue .createApp ({ data ( ) { return { project : { name : [ 'Linux system' , 'Git' ] } } }, computed : { projectMessage ( ) { return this .project .name .length > 0 ? 'Welcome you to join' : 'Sorry you can’t enter the community, please participate or create a project' } } }) const vm = app.mount ('#app' ) </script >
如上述的例子中,主要声明了一个 computed
属性 projectMessage
,假设 project
>0 即可加入社区,而 < 0 的 User 将会被拒绝。
projectMessage 所依赖的是 data()
中 project
数组的值,当 vm.project.name
发生更改时 projectMessage
也会对应的进行改变。
setter setter 主要的作用就是当改变 projectMessge
时来重新进行调整,也就是你可以在该函数下写一些你想重新改变的东西,比如添加或者关联等:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <div id="app" > <p > {{projectMessage}}</p > </div> <script > const app = Vue .createApp ({ data ( ) { return { project : 'Vue' , author : 'Evan You' } }, computed : { projectMessage : { get ( ) { return this .project + ' ' + this .author }, set (newValue ) { alert ("当前名称是:" + newValue); const names = newValue.split (' ' ) this .project = names[0 ] this .author = names + 'Vue!' } } } }) const vm = app.mount ('#app' ) </script >
侦听器 (watch) 侦听器主要通过 watch
选项来提供一个通用的方法来进行响应数据的变化,当数据变化或开销较大的时候这种方法最为有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <div id="app" > <input type ="text" v-model ="id" > <p > {{message}}</p > </div > <script > const app = Vue .createApp ({ data ( ) { return { id : '0' , message : 'Your id' } }, watch : { id (newId ) { if (newId >= 0 ) { this .getId () } } }, methods : { getId ( ) { this .message = 'Thinking...' if (this .id <= 712 ) this .message = 'true' else this .message = 'false' } } }) const vm = app.mount ('#app' ) </script >
RootComponent 在 Vue 3.0 中,每个应用的创建都是通过 createApp
函数进行创建一个新的应用:
1 2 3 const app = Vue .createApp ({ })
上述这种方法可以更加明显的表示出 createApp
函数的作用,但 Vue3.0 中还有另一种方法更加遵循 MVVM 模型。
尽管 Vue 的设计没有完全遵循,但设计收到了他的启发,因此在文档中也会使用 vm
来作为 ViewModel 的缩写来表示组件实例。
在大多数真实应用中,这些语法都是层层嵌套的,为此为了一个可重用的组件树,还提供了 根组件 的写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id="app" > {{message.hey }} </div> <script > const RootComponent = { data ( ) { return { message : { hey : 'hey,world!' } } } } const app = Vue .createApp (RootComponent ) const vm = app.mount ('#app' ) </script >
MVVM 架构的核心是通过数据进行驱动,即 ViewModel,通过 ViewModel 将 View 和 Model 进行关联映射,更加通俗的说法 ViewModel 就是一个负责转换 Model 中的数据对象,使得数据对象更加便与管理和使用,也就是双向绑定。
当用户操作 View 时,ViewModel 就会监听到改变后通知 Model 发生了改变,如果 Model 改变则 View 也会改变。
生命周期
当使用 createApp
时,会初始化事件和生命周期,之后创建将模板渲染函数并将 app.$el
添加到 el
安装,当数据发生变化时重新渲染并更新,最后当 app.unmount()
被调用时将会卸载该应用。
在初始化事件和生命周期之前还会初始化注射(ingections)以及响应式(reactivify)
Data Property 组件中的 data
函数在 Vue 创建新的实例的过程中将会被调用,他返回的是一个对象,之后 Vue 会通过相应性系统将其包裹,并以 $data
的形式存储在组件实例中,该函数的任何属性也会直接通过他来暴露出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id="app" > {{message}} </div> <script > const app = Vue .createApp ({ data ( ) { return { message : 'hey,world!' , } } }) const vm = app.mount ('#app' ) console .log (vm.message ) vm.message = 'hey,message!' console .log (vm.$data .message ) </script >
这些属性在实例创建时进行添加,所以需要保证他们在 data
返回的对象中,他还支持属性使用 null
以及 undefined
或其他站位值。
Vue 使用的是 $
前缀来通过组件实例所暴露自己的内置 API,对于内部还提供了 _
前缀。
直接将不包含 data
中的属性添加到实例中是可行的,但由于睡醒那个不再背后的响应式,因此 Vue 相应性系统不会自动跟踪,也就是说他无法自动更新。
methods methods 选项向组件实例添加方法,主要用于包含所需方法对象,Vue 自动将 methods
绑定为 this
,以便于他始终指向组件实例。
需要注意的是在定义 methods
时应避免使用箭头函数,这回阻止 Vue 绑定恰当的 this
指向。
通常 this
指向该实例的本身
在模板指令中通常 方法(methods) 会和其他的属性在组件模板中被访问,这通常是事件监听,如 v-on
指令 (他有很多的 methods)
Lodash Lodash 是遵循 MIT 开源协议所发布的,一致性、模块化、高性能的 JavaScript 实用工具库。
本文主要演示下 _.debounce(func,[wait=0],[options={}])
函数以及 Vue Data Property 的 “相应性” 的使用。
_.debounce 函数主要的作用就是延迟 function
到 wait
自上次调用 debounced
函数以来经过多少毫秒后。
可参考下 Lodash doc: https://www.lodashjs.com/docs/lodash.debounce
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div id="app" > <button @click ="toclick" > up go</button > <p > {{message}}</p > </div> <script src ="https://unpkg.com/lodash@4.17.20/lodash.min.js" > </script > <script > const app = Vue .createApp ({ data ( ) { return { toclick : _.debounce (function ( ) { vm.message = 'hey,lodash' }, 1000 ), message : 'hey,world!' } } }) const vm = app.mount ('#app' ) </script >
如上述的例子中主要通过 lodash
所提供的 _.debounce
函数延迟 1ms 来改变 message
属性的值。当数据发生变化时 DOM 将会重新渲染并更新。
Vue.js主要使用了基于HTML的模板语法,允许开发者声明式的将DOM绑定至底层的Vue实例数据,由于Vue.js基于HTML模板语法,所以所编写的自然而然能被浏览器所解析(除了远古浏览器)。
插值 插值(interpolation) 在数学领域中表示了一个有限的数值函数其中自变量的值,而在 Vue 中可以表示在元素中所使用的自变量,根据这些子变量可以通过双向绑定来实现其最终效果。
Mustache Mustache(小胡子) 是一个模板系统(template system),支持了如 C++、Java、JavaScript、PHP、Python 等众多主流语言。
Available in Ruby, JavaScript, Python, Erlang, Elixir, PHP, Perl, Raku, Objective-C, Java, C#/.NET, Android, C++, CFEngine, Go, Lua, ooc, ActionScript, ColdFusion, Scala, Clojure[Script], Clojure, Fantom, CoffeeScript, D, Haskell, XQuery, ASP, Io, Dart, Haxe, Delphi, Racket, Rust, OCaml, Swift, Bash, Julia, R, Crystal, Common Lisp, Nim, Pharo, Tcl, C, ABAP, Elm, Kotlin, and for SQL
Works great with TextMate, Vim, Emacs, Coda, and Atom
他也被描述为 “无逻辑” 系统,因为缺少任何明确的控制流语句,这主要取决与他是一个大量使用的符号 “**{}**” ,类似与一个横向的小胡子因此而得名。
Vue 为此支持了这种方法,Mustache 标签将会替代对应组件中的属性值,但无论如何绑定组件上的属性发生了改变,所以插值处还是会被更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!DOCTYPE html> <html lang ="en" > <head > <meta charset ="UTF-8" > <title > index</title > <script src ="https://unpkg.com/vue@next" > </script > </head > <body > <div id ="app" > <span > {{message}}</span > </div > <script > var App = { data ( ) { return { message : 'hey,world!' } } } Vue .createApp (App ).mount ("#app" ) </script > </body > </html >
v-once 为此、Vue 还提供了 v-once
指令,该指令类似于 Object.freeze()
阻止修改的方法,但主要作用就是只渲染元素和组件一次,随后元素/组件及其子节点将会被视为静态内容并跳过:
Vue 渐进式主要体现在其文档中,通常 Vue 文档写一个实例会出现你认知以外的方法,因此你需要阅读之后的文档在折回来学习目前的实例才可理解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div id="app" > <p v-once > {{message}}</p > <input type ="button" value ="upgrate message" v-on:click ="message ='hey,v-on'" /> </div> <script > var App = { data ( ) { return { message : 'hey,world!' } } } Vue .createApp (App ).mount ("#app" ) </script >
上述的例子中,主要通过使用 v-once
来阻止 v-on
指令来进行修改,从而整个 v-on
事件失败。
v-html 需要注意的是,Mustache 将会被 Vue 解析为普通的文本,并不是正常的 HTML 代码,因此如果需要输出 HTML 则需要使用 v-html
指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div id="app" > <p > {{message}}</p > <p v-html ="message" > {{message}}</p > </div> <script > var App = { data ( ) { return { message : '<h1>Hello,world!</h1>' } } } Vue .createApp (App ).mount ("#app" ) </script >
JavaScript 表达式 需要注意的是虽然在 Vue 模板中使绑定的一直都是属性插值,但实际上对于所有的数据绑定(Data Bigings) 都完全的支持了 JavaScript 表达式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id="app" > <p > {{'This is ' + message}}</p > <p > {{gender ? '我是女孩!' : '我不是女孩'}}</p > </div> <script > var App = { data ( ) { return { message : 'Hello,world!' , gender : false } } } Vue .createApp (App ).mount ("#app" ) </script >
但 在 Mustache 的限制下每个绑定的都只能包含单个表达式,所以向类似与 Lareavel 那种 Mustache 是不会生效的,如:
1 {{ if (ok) { return message } }}
Attribute 属性(Attribute) 语法是一个在元素层级之下,通常被指令包含在其中的都会被称之为 Attribute。
v-bind v-bind 是一个富有很多 Attribute 的指令之一,他最为常用的就是 src\class\style
三种,并支持使用 :
作为简写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <style type="text/css" > .logo -size { width : 3em; } .logo -layout { border : 1px solid #e3e3e3; } </style> <div id ="app" > <p > {{message}}</p > <img v-bind:src ="logo" :class ="[logo_size,logo_layout]" /> <img :src ="title" :style ="{ width: title_size + 'em' }" /> <a :href ="home" > to Jiangxue Team Home</a > </div > <script > var App = { data ( ) { return { message : 'Hello,world!' , logo : 'logo: ' https : title : 'https://gitee.com/analysis-of-river-snow/drawing-bed/raw/master/20210918002526.png' , logo_size : 'logo-size' , logo_layout : 'logo-layout' , title_size : '5' , home : 'https://www.jiangxue.team/' } } } Vue .createApp (App ).mount ("#app" ) </script >
需要注意的是 DOM 模板 v-bind
property 支持陀峰命名
当元素上是指一个绑定的时候 Vue 将会默认通过 in
操作检测元素是否有一个被定义的属性的 key,如果属性被定义了则个值也就被设置为一个 DOM Propetry 而不是单纯的 Attribute。
指令 指令(Directives) 指的是 Vue 中带有 v-
前缀的特殊 Attribute,指令是预期的单个 JavaScript 表达式。主要的作用是当表达式的值发生改变的时候,同样会响应式的作用与 DOM 。
通常指令的 attribute 预期值是单个的 JavaScript 表达式,但 v-for
和 v-on
是特殊的情况
v-if 指令的 DOM 传递可直接通过 v-if
来根据表达式 Attribute
的值来决定是否出现这个元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id="app" > <p > {{'This is ' + message}}</p > <p v-if ="gender" > This is true</p > </div> <script > var App = { data ( ) { return { message : 'Hello,world!' , gender : true } } } Vue .createApp (App ).mount ("#app" ) </script >
参数 参数通常在指令的冒号之后表示(:
),在 Vue 中最为常用到参数的指令就是 v-bind
,如下述 code 中的 :href
就是一个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id="app" > <p > {{'This is ' + message}}</p > <a :href ="home" > to Jiangxue Team Home</a > </div> <script > var App = { data ( ) { return { message : 'Hello,world!' , home : 'https://www.jiangxue.team/' } } } Vue .createApp (App ).mount ("#app" ) </script >
修饰符 修饰符(Access modifiers) 是一个面向对象语言中的关键字,用于设置类或方法和其他成员的可访问性,在 Vue 中主要使用到修饰符的指令是 v-on
v-on v-on 的缩写为 @
,其参数为 event
即监听对应的事件是否被触发,这主要用法就是绑定事件监听器,事件的类型都由修饰符进行指定。
ID
DA
FA
click.stop
调用 event.stopPropagation()
阻止捕获和冒泡阶段中当前事件的进一步传播
click.prevent
调用 event.preventDefault()
阻止默认的点击事件执行
.capture
添加事件侦听器时使用capture(捕获) 模式
.self
只当事件从侦听器绑定元素本身触发时才进行回调
```.{keyCode
keyAlias}```
只当事件从特定键触发时才进行回调
.once
只触发一次回调
.left
只当点击鼠标左键时触发
.right
只当鼠标点击右键时触发
.middle
当鼠标中键时触发
.passive
以 { passive: true } 模式添加侦听器
我们主要以 prevent
为例,监听其 submit 元素是否被触发,并组织默认的单击事件执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id="app" > <form v-on:click.prevent ="doThis" > <a :href ="home" > {{message}}</a > </form > </div> <script > var App = { data ( ) { return { message : 'Go Jiangxue Team' , home : 'https://www.jiangxue.team/' } } } Vue .createApp (App ).mount ("#app" ) </script >
或者通过 v-on
的简写 @
来实现没有表达式的阻止默认行为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id="app" > <form @click.prevent > <a :href ="home" > {{message}}</a > </form > </div> <script > var App = { data ( ) { return { message : 'Go Jiangxue Team' , home : 'https://www.jiangxue.team/' } } } Vue .createApp (App ).mount ("#app" ) </script >
可参考下 Vue 官方文档中所提供的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <!-- 方法处理器 --> <button v-on:click ="doThis" > </button > <!-- 动态事件 --> <button v-on: [event ]="doThis" > </button > <!-- 内联语句 --> <button v-on:click ="doThat('hello', $event)" > </button > <!-- 缩写 --> <button @click ="doThis" > </button > <!-- 动态事件缩写 --> <button @[event ]="doThis" > </button > <!-- 停止冒泡 --> <button @click.stop ="doThis" > </button > <!-- 阻止默认行为 --> <form @submit.prevent > </form > / <form @click.prevent></ form><!-- 阻止默认行为,没有表达式 --> <form @click.prevent > </form > <!-- 串联修饰符 --> <button @click.stop.prevent ="doThis" > </button > <!-- 键修饰符,键别名 --> <input @keyup.enter ="onEnter" /> <!-- 点击回调只会触发一次 --> <button v-on:click.once ="doThis" > </button > <!-- 对象语法 --> <button v-on ="{ mousedown: doThis, mouseup: doThat }" > </button >
组件(component) 是 Vue.js 中最为核心的功能,在前端应用程序中可以采用模块化以及实现可重用、可扩展的 Vue 实例,通常使用 template
作为方法进行注册组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div id="app" > <button-counter > </button-counter > </div> <script > const app = Vue .createApp ({}) app.component ('button-counter' , { data ( ) { return { count : 0 } }, template : ` <button @click="count++"> This is click {{count}} </button> ` }).mount ('#app' ) </script >
当然我们也可以重复使用各个独立的 <button-counter>
组件,但前提我们的组件需要高度解藕。
点击按钮的时候,上述的 flag 将会被证实,就因为每个组件都会各自独立并维护他的 count,每次使用 <button-conters>
都会有一个新的实例会被新建。
1 2 3 4 5 <div id="app" > <button-counter > </button-counter > <button-counter > </button-counter > <button-counter > </button-counter > </div>
或者可以选择组件使用同一个 count
来进行同时的数据绑定与渲染:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <div id="app" > <button-counter > </button-counter > <button-counter > </button-counter > <button-counter > </button-counter > </div> <script > const app = Vue .createApp ({}) var buttonCounter = { count : 0 } app.component ('button-counter' , { data ( ) { return buttonCounter }, template : ` <button @click="count++"> This is click {{count}} </button> ` }).mount ('#app' ) </script >
Prop
Prop 也被直译为 “支柱”,通常他可以为组建提供一个属性用于传递数据并建立链接,这也方便了数据的获取和各个组件之间的解藕:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <style> .header { border : 1px solid #eaeaea; padding : 2em; width : 40 %; } .header_item { border-left : 10px solid #1488ff; padding-left : 14px; } .header_txt { text-indent : 1em; } </style> <div id="app"> <item-main title="Hey,world" text="当然我们也可以重复使用各个独立的 <button-counter> 组件,但前提我们的组件需要高度解藕。点击按钮的时候,上述的 flag 将会被证实,就因为每个组件都会各自独立并维护他的 count,每次使用 <button-conters> 都会有一个新的实例会被新建。"></item-main> </div> <script> const app = Vue.createApp({}) app.component('item-main', { data() { return { } }, props: ['title', 'text'], template: ` <div class="header"> <h1 class="header_item">{{title}}</h1> <p class="header_txt">{{text}}</p> </div> ` }).mount('#app') </script>
为了使用的方便我们还可以直接使用 Prop 数组来提供数据的绑定和输出,这会更加的方便和简洁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 43 44 45 46 47 48 <style> .header { border : 1px solid #eaeaea; padding : 2em; width : 40 %; } .header_item { border-left : 10px solid #1488ff; padding-left : 14px; } .header_txt { text-indent : 1em; } </style> <div id ="app" > <item-main v-for ="post in posts" :key ="post.id" :title ="post.title" :txt ="post.txt" > </item-main > </div > <script > const App = { data ( ) { return { posts : [ { id : 1 , title : 'Vue' , txt : '一个优秀的渐进式框架' }, { id : 2 , title : 'Jquery' , txt : 'JavaScript 组件库,集成了多种实用方法' }, { id : 3 , title : 'D3' , txt : '专业的数据可视化框架' } ] } } } const app = Vue .createApp (App ) app.component ('item-main' , { props : ['title' , 'txt' ], template : ` <div class="header"> <h1 class="header_item">{{title}}</h1> <p class="header_txt">{{txt}}</p> </div> ` }) app.mount ('#app' ) </script >
监听 最为明显的一个例子就是通过监听器来修改字号或进行一些其他方面的监听,而这这种的实现方式也非常的简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 <style> .header { border : 1px solid #eaeaea; padding : 2em; width : 40 %; } .header_item { border-left : 10px solid #1488ff; padding-left : 14px; } .header_txt { text-indent : 1em; } .txt_button { float : left; display : -webkit-inline-box; } </style> <div id="app"> <item-main title="Hey,world" text="当然我们也可以重复使用各个独立的 <button-counter> 组件,但前提我们的组件需要高度解藕。点击按钮的时候,上述的 flag 将会被证实,就因为每个组件都会各自独立并维护他的 count,每次使用 <button-conters> 都会有一个新的实例会被新建。"></item-main> <div class="txt_button"> <button-addcounter></button-addcounter> <button-redcounter></button-redcounter> </div> </div> <script> const app = Vue.createApp({}) var txtSize = { size: '15' } app.component('item-main', { data() { return txtSize }, props: ['title', 'text'], template: ` <div class="header"> <h1 class="header_item">{{title}}</h1> <p class="header_txt" :style="{fontSize: size+'px'}">{{text}}</p> </div> ` }) app.component('button-redcounter', { data() { return txtSize; }, template: ` <button @click="size--"> Reduce to fontSize - 1 </button> ` }) app.component('button-addcounter', { data() { return txtSize; }, template: ` <button @click="size++"> Add to fontSize + 1 </button> ` }) app.mount('#app') </script>
插槽 组件通常通过元素进行使用,并以属性作为内容,而元素本身的内容将会被覆盖,因此 Vue 提供了 <slot>
元素来解决这一问题,此外 slot 也可被理解为组件之间的一种传递方式或占位符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <style> .header { border : 1px solid #eaeaea; padding : 2em; width : 40 %; } .header_item { border-left : 10px solid #1488ff; padding-left : 14px; } .header_txt { text-indent : 1em; } </style> <div id ="app" > <item-main > 和 HTML 元素一样,我们经常需要向一个组件传递内容</item-main > </div > <script > const app = Vue.createApp({}) app.component('item-main', { data() { return { title: 'This is <slot > ' } }, template: ` <div class ="header" > <h1 class ="header_item" > {{title }} </h1 > <slot > </slot > </div > ` }).mount('#app') </script >
动态组件 在通常情况下,不同组件之间的动态切换可以让页面变得更加的拥有趣味,且可以减少一些不必要的从页面占用。动态组建可以用于构建一些非动态的填写,而如果需要满足一些OAuth等切换或登录的场景,则需要使用 Vue 动态组件中的异步组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <div id="app" > <button v-for ="nav in navs" :key ="nav" @click ="currentTab = nav" > {{nav}}</button > <component :is ="currentTabDev" > </component > </div> <script > const app = Vue .createApp ({ data ( ) { return { currentTab : 'Home' , navs : ['home' , 'arch' , 'about' ] } }, computed : { currentTabDev ( ) { return 'nav-' + this .currentTab .toLowerCase () } } }) app.component ('nav-home' , { template : ` <div>Home</div> ` }) app.component ('nav-arch' , { template : ` <div>Arch</div> ` }) app.component ('nav-about' , { template : ` <div>About</div> ` }) app.mount ('#app' ) </script >
上述 code 中,currentTabDev
可以是一个组件的名字或一个选项对象,通过 :is
属性来作为一个自定义的内置元素进行转译。
很多时候我们所使用的 :key
只是用于进行排序,有相同父元素的子元素必须有唯一的 key。重复的 key 会造成渲染错误,因此需要使用属性
也就是说当 currentTabDev
发生改变的时候,组件也就会发生变化,这是 Vue 3.x 中所新增的特殊属性。
keep-alive Vue创建一个新的 ```currentTabDev``` 实例,也就是说只要通过使用``````元素进行包裹,即可让他们在第一次创建时会被进行**缓存**,即保存刚刚切换后的数据,为了更加的体现```< keep-alive>```效果,我们可以使用表单来进行验证: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 43 44 45 46 47 48 49   ```js <div id="app"> <button v-for="nav in navs" :key="nav" @click="currentTab = nav">{{nav}}</button> <keep-alive> <component :is="currentTabDev"></component> </keep-alive> </div> <script> const app = Vue.createApp({ data() { return { currentTab: 'Home', navs: ['home', 'arch', 'about'] } }, computed: { currentTabDev() { return 'nav-' + this.currentTab.toLowerCase() } } }) app.component('nav-home', { template: ` <div><input type="text" /></div> ` }) app.component('nav-arch', { template: ` <div>Arch</div> ` }) app.component('nav-about', { template: ` <div>About</div> ` }) app.mount('#app') </script>
Vue(/vju:/,类似与 view
),是由尤雨溪
所开发的一种前端js
框架,以vue为中心的vue 库最为出名,其中知名的有vue-data、vue-table……
分别运用在数据大屏
以及表格处理
方面,其中vue主要用于构建用户界面 的渐进式框架,核心库只支持前端显示。
而渐进式框架主要是:“一开始不需要完全掌握全部功能,到后面会慢慢的提升”,就以vue-data
为例,即使光通过官方文档也可以快速上手,这与vue.js的成功密切相关。
Vue 的部分设计理念遵守了 MVVM(Model-view-viewmodel) 软件架构模式,用于构建用户界面的渐进式框架,是被一个设计自低向上逐层应用。
通过 MVVM 有助于将图形用户界面的开发和业务逻辑的开发分离开来,因此 Vue 也是一个用于构建用户界面的渐进式框架
虽然并没有完全遵守 MVVM 模型,但 Vue 在设计上收到了启发,因此对于 vm,ViewModel
通常用于表示组件的实例。
vue.js 的官方文档是写的最为详细的框架文档之一,这与其vue.js发展之出的Laravel 社区文档出现了对比,如果按照通俗的话来讲就是“教你造车但不教你开车 ”,这也是vue.js如此成功的关键因素之一,其二就是由于vue.js是由国人所开发的,这也增加了vue.js在国内的受欢迎程度不同类框架第一影响更好。
对于学习我们可以直接使用最新的 Vue CDN 进行引入:<script src="https://unpkg.com/vue@next"></script>
MVVM
MVVM(Model-view-viewmodel)即表示 **view(视图)\viewModel(视图模型)\Model(模型)**,是一种软件的架构模式,其中 View 的主要作用就是向用户显示数据上下文中可用的数据,并与用户进行数据交互。
而之后的 ViewModel 是用于作为视图(VIew)和模型(Model)之间的桥梁,在 MVC 的软家架构模式中可以表示为 Controller
控制器,,MVVM 模式试图通过 MVC 所提供的数据绑定的优势通过框架尽可能的接近于应用程序模型,他使用绑定器以及视图模型。
MVVM 不同于 MVC,在MVVM 模式中将 ViewModel
层绑定到 View 曾后基本上不会使用点击事件,而是使用命令(Command)来控制,并通过 Binding 来绑定相关数据。
对于 Model 是指所需数据的对象建模,这通常用于数据库建模并直接进行映射到数据中,类似与 Laravel 以及 Sequelize 中的 Model
ViewModel
ViewModel 是 Vue 的核心框架也是一个 Vue 实例,作用与某一个 HTML 元素之上,通常为指定的 ID 元素。当创建了一个 ViewModel 后,最为核心的就是双向绑定,主要以 DOM Listeners(DOM 侦听器)和 Data Bindings(数据绑定) 为主。DOM Listeners 会检测 View 上的元素变化,如有变化则会更改 Model 中的数据; 当更改 Model 数据时, DataBingdings 则会更新页面中的 DOM 元素。因此最后的 app
元素下所绑定的 {{message}}
则会返回 hey,world
来将此渲染进 DOM 系统。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!DOCTYPE html> <html lang ="en" > <head > <meta charset ="UTF-8" > <title > index</title > <script src ="https://unpkg.com/vue@next" > </script > </head > <body > <div id ="app" > {{message}} </div > <script > var App = { data ( ) { return { message : 'hey,world!' } } } Vue .createApp (App ).mount ("#app" ) </script > </body > </html >
在 Vue3.0 版本中,Vue 应用都是通过 createApp
函数创建一个新的应用实例,如:
1 2 3 4 5 6 7 8 var App = { data ( ) { return { message : 'hey,world!' } } } Vue .createApp (App ).mount ("#app" )
但上述这种只是一种非常简单的写法,还有另一种写法是类似与更加符合 MVVM 模型的,Vue 的设计收到此启发但在文档中也会使用 vm(ViewModel)
进行缩写。
1 2 3 4 5 const RootComponent = { } const app = Vue .createApp (RootComponent )const vm = app.mount ('#app' )
Vue CLI 是一个由vue.js官方所发布的一个快速构建 vue 项目的脚手架,通过使用 vue-cli可以构建一个标准的 vue 项目。
安装 npm 安装 Vue 我们主要通过脚手架来进行,vue 为此提供了两种可需方案,分别为nmp install -g vue-cli
或使用cnpm install -g vue-cli
来进行安装,我们可以配置下全局安装 cnpm
cnpm 1 npm install cnpm -g --registry=https://registry.npm.taobao.org
当安装完成之后可以使用 vue --version
来查看是否安装成功,如安装成功之后则进行下一步。
构建 在vue-cli中,分别有两种方式,可使用vue create project-name
来构建一个 vue-cli项目,也可以通过使用 vue ui
及 web gui 的形式来进行构建。
运行 当构建完成一个 vue 项目之后,我们可以通过npm
脚手架来进行运行服务也可以通过使用 vue 进行,两者之间的区别就是通过使用 npm run serve
脚手架运行不需要安装@vue/cli-service-global
依赖,而 通过使用 vue serve
来运行会经过漫长的等待来安装依赖,但等待并不是没有用的,vue 的用户体验是很棒的。
目录
ID
DA
FA
build
项目构建时的相关代码
项目构建
build.js
生产环境构建代码
check-version.js
用于检查 node,npm 版本
utils.js
构建工具
vue-loader.conf.js
loader 配置
webpack.base.conf.js
webpack 基础配置
webpack.dev.conf.js
webpack 开发环境配置,用于构建本地服务器
webpack.prod.conf.js
webpack 生产环境配置
config
项目开发环境配置
项目配置
dev.env.js
开发环境变量
index.js
项目配置变量
prod.env.js
生产环境变量
src
源码目录
工作空间
components
公共组件
router
路由管理
App.vue
页面入口文件
main.js
程序入口文件
static
静态文件资源存放
.babelrc
ES6 语法编译配置
.editorconfig
定义代码格式
.gitignore
git 上传需要忽略的文件格式
.postcssrc
postcss 配置文件
README.md
说明文件
index.html
入口文件
package.json
项目基本信息 ,包依赖信息……
vue 中的路由并不同等与上述章节内容,如需要在Vue中使用路由需要引入或通过脚手架来安装 vue.js 所提供的官方CDN
或是 vue-router
,同样的本文依然使用 CDN 的方式进行演示:
https://unpkg.com/vue-router@2.0.0/dist/vue-router.js
创建组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id="button-counts"> <button-conters></button-conters> </div> <script> Vue.component('button-conters', { data: function() { return { count: 0 } }, template: '<button v-on:click="count += 1">增加 count {{ count }}</button>' }) new Vue({ el: '#button-counts' }) </script>
当创建完成组建之后,我们可以无限次的进行引用,而组件
中通常会带有一个名字,就比如上述创建的组件名称就是<button-conters>
并根据创建一个创建Vue根实例化将组件作为自定义元素进行使用 :
1 2 3 new Vue({ el: '#button-counts' })
之后直接在HTML
中直接引入刚刚创建的组件即可作为HTML元素进行使用如:
1 2 3 <div id="button-counts"> <button-conters></button-conters> </div>
复用组件 当组件创建完成之后我们可以在上述的基础上进行多次复用且独立,如:
1 2 3 4 5 6 <div id="button-counts"> <button-conters></button-conters> <button-conters></button-conters> <button-conters></button-conters> <button-conters></button-conters> </div>
当点击按钮的时候,上述的flag将会被证实,就因为每个组件都会各自独立并维护他的count
,每次使用<button-conters>
都会有一个新的实例
会被新建。
同步
当以往常一样通过data
直接定义且不通过data 函数
则可返回对象的独立访问,如:
1 2 3 4 5 6 7 8 9 10 11 12 var buttonRepeat = { count: 0 } Vue.component('button-conters', { data: function() { return buttonRepeat }, template: '<button v-on:click="count += 1">增加 count {{ count }}</button>' }) new Vue({ el: '#button-counts' })
由于每个count
是共享的所以当点击一个组件的同时,所有复用的组件都会被增加,所以正确的方式是通过使用独立函数进行编写组件,来不影响组件之间的复用:
1 2 3 4 5 6 7 8 9 10 11 Vue.component('button-conters', { data: function() { return { count: 0 } }, template: '<button v-on:click="count += 1">增加 count {{ count }}</button>' }) new Vue({ el: '#button-counts' })
组件的组织 通常一个应用会一一棵嵌套的组建树形式来组织,在vue当中,组件的注册需要让vue能够进行识别 ,所以注册主键一共分为两种类型,分别为全局注册
以及局部注册
,vue中所有的组件都是通过Vue.component
来进行注册。
而局部注册主要通过使用var ComponentOne {}
来进行注册,全局注册主要通过使用Vue.component('组件名', {})
来进行注册,这里两者的区别就是命名方式的不同 。
全局注册组件格式
1 2 3 Vue.component('组件名称' { // …… })
局部注册
1 2 3 var ComponentOne = { // …… }
Prop 向子组件传递数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  在官方文档中,Prop向子组件传递数据主要用于**向这个组件传递一个标题或者内容之类的展示数据**,Prop是你可以在组建上注册一些自定义的**属性**,当一个**值传递给一个 prop 属性**。 ```vue <div id="data-title"> <data-title title="Hello,world"></data-title> <data-title title="Hello,Vue"></data-title> </div> <script> Vue.component('data-title', { props: ['title'], template: '<h1>{{title}}</h1>' }) new Vue({el: '#data-title'}) </script>
除此之外我们还可以使用动态赋予一个变量的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div id="data-title"> <data-title v-for="post in posts" v-bind:key="post.id" v-bind:title="post.title"></data-title> </div> <script> new Vue({ el: '#data-title', data: { posts: [ { id: 1, title: 'Hello,world!'}, { id: 2, title: 'Hello,Vue!'}, { id: 3, title: 'Hello,Laravel!'}, ] } }) Vue.component('data-title', { props: ['title'], template: '<h4>{{title}}</h4>' }) new Vue({el: '#data-title'}) </script>
监听子组件事件 在开发<text-post
组件的时候,就会涉及到父级组件的协调来实现一个文字的放大效果以及默认字体大小。首先我们在父组件,即#text-posts-events
中添加一个postFontSize
数据属性来设置默认的字号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <div id="text-posts-events"> <div :style="{ fontSize: postFontSize + 'em' }"> <text-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post" v-on:enlarge-text="postFontSize += 0.1" > </text-post> </div> </div> <script> Vue.component('text-post', { props: ['post'], template: '\ <div class="text-post">\ <h3>{{post.title}}\ <button v-on:click="$emit(\'enlarge-text\')">\ 字体放大\ </button>\ <div v-html="post.content"></div>\ </div>\ ' }) new Vue({ el: '#text-posts-events', data: { posts: [ {id:1, title: 'Hello,vue!', content:'vue'}, {id:2, title: 'Hello,Laravel!', content:'laravel'} ], postFontSize: 1 } }) </script>
用法 vue 的表单处理主要使用v-model
指令,且仅仅限制于在<input>、<select>、<textarea>
等HTML表单元素中使用。v-model 可以根据HTML控件的类型来自动选取正确 的方法来进行更新。
需要值得注意的是v-model
指令会忽略所有的表单value、checked、selected
等属性的初始值,所以需在js
内的data
选项中声明初始值,其中元素所对应的属性对应为:
ID
DA
text & textarea
使用value 属性和input 事件
checkbox & radio
使用 checked 属性 和 change 事件
select
将以value 作为属性并和 change 事件
1 2 3 4 5 6 7 8 9 10 11 12 <div id="app"> <input v-model="message" placeholder="输入"> <p>当前输入的是: {{message}}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: 0 } }) </script>
textarea
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <style> .br { white-space: pre-line; } </style> <div id="app"> <textarea v-model="message" placeholder="输入"></textarea> <p class="br">当前输入的是: {{message}}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }) </script>
在上述的演示当中,<p>
标签是不会根据<textarea>
标签中并不会进行换行,所以我们需要使用style的white-space
属性。
checkbox
1 2 3 4 5 6 7 8 9 10 11 12 <div id="app"> <input type="checkbox" id="message" v-model="message"> <label for="message">{{message}}</label> </div> <script> var app = new Vue({ el: '#app', data: { message: false } }) </script>
复选框绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <div id="app"> <h2>Vue</h2> <input type="checkbox" id="vue" value="vue" v-model="message"><label>vue</label> <input type="checkbox" id="vue" value="vue" v-model="message"><label>vue</label> <h2>Laravel</h2> <input type="checkbox" id="laravel" value="laravel" v-model="message"><label>laravel</label> <h2>Less</h2> <input type="checkbox" id="less" value="less" v-model="message"><label>less</label> <hr/> <br> <label>共选择了 {{message}}</label> </div> <script> var app = new Vue({ el: '#app', data: { message: [] } }) </script>
radio
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <div id="app"> <input type="radio" id="vue" value="Vue" v-model="message"> <label for="vue">Vue</label> <input type="radio" id="laravel" value="Laravel" v-model="message"> <label for="vue">Laravel</label> <input type="radio" id="ejs" value="Ejs" v-model="message"> <label for="vue">Ejs</label> <hr/> <br> <label>选择了 {{message}}</label> </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }) </script>
当单选一个radio
类型的时候,将会根据其radio
类型中所设置的value
进行显示。
选择框
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id="app"> <select v-model="message"> <option disabled value="">类型</option> <option value="Vue 被选择了">Vue</option> <option value="Laravel 被选择了">Laravel</option> </select> <p>{{message}}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }) </script>
在上述的code当中,我们主要通过使用value
来设置option
被选择时的属性,除此之外我们还可以直接在 vue 中更加生动的进行绑定:
value 绑定
修饰符 在 vue中,不仅仅为前面几章提供了修饰符,自然而然的也为表单处理所加入了一些较为常用的修饰符,如.lazy、.number、.trim
,他们的详细用法是:
ID
DA
.lazy
当输入完成时在同步信息
.number
将输入的值自动转换为 number
类型
.trim
自动过滤首尾空白
.lazy vue 所提供的.lazy
修饰符的主要作用就是,当输入的时候并不会更新当前输入的内容 ,只有当结束输入的时候才会进行更新或同步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <style> .br { white-space: pre-line; } </style> <div id="app"> <textarea v-model.lazy="message" placeholder="输入"></textarea> <p class="br">当前输入的是: {{message}}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }) </script>
.number 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ```vue <style> .br { white-space: pre-line; } </style> <div id="app"> <input type="number" v-model.number="message" placeholder="输入"></input> <p class="br">当前输入的是: {{message}}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }) </script>
.trim
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ```vue <style> .br { white-space: pre-line; } </style> <div id="app"> <textarea v-model.trim="message" placeholder="输入"></textarea> <p class="br">当前输入的是: {{message}}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }) </script>
📖 more posts 📖