Vue.js 介绍
Vue.js 也称为 Vue,读音类似 view。
Vue 有以下特点:
- 是一个构建用户界面的框架
- 是一个轻量级 MVVM(Model-View-ViewModel)框架,和 angular、react 类似
- 数据驱动 + 组件化的前端开发(核心思想)
- 通过简单的 API 实现响应式的数据绑定和组合的视图组件
- 更容易上手、小巧
参考:官网文档
第一个 vue 程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div id="main"> {.{msg}.} </div>
<script src="./js/vue.js"></script> <script> new Vue({ el: '#main', data: { msg: 'hello Vue.js' }, methods:{ } }) </script>
|
以上就是一个非常简单的 vue 程序。绑定元素这里不但可以使用 id 选择器,我们还可以使用类选择器或者标签选择器。但是,vue2.0 中不允许将 vue 实例挂在到 html 或者 body 元素上。
常用指令
指令用来扩展 HTML 功能。vue 内置了很多指令。
v-model
实现双向数据绑定,实时监控数据变化,一般用于表单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div id="main"> <input type="text" v-model="content"> <br> {.{ content111 }.} </div>
<script src="./js/vue.js"></script> <script> new Vue({ el: '#main', data: { content: '' } }) </script>
|
在这里,使用v-model
指令将输入框的值与 vue 实例中的 content 进行绑定。此后,二者中的任一值发生变化,另一个值都会跟随变化。
v-for
用于遍历数组、对象等。
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
| <div id="main"> <ul> <li v-for="item in arr"> //遍历数组 {.{item}.} </li> </ul> <ul> <li v-for="item in obj"> //遍历对象 {.{item}.} </li> </ul> <ul> <li v-for="(value,key) in obj"> //键值循环,数组也适用,注意key在后面 {.{key}.}----{.{value}.} </li> </ul> </div>
<script src="./js/vue.js"></script> <script> new Vue({ el: '#main', data: { arr: [1, 2, 3, 4, 5, 6], obj: { name: 'hedawei', age: 22, gender: 'man' } } }) </script>
|
v-on
用于绑定事件,用法:v-on: 事件 =“函数”。
示例:点击事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <div id="main"> <button type="button" v-on:click="showHello()">点击显示</button> <br> {.{msg}.} </div>
<script src="./js/vue.js"></script> <script> new Vue({ el: '#main', data: { msg:'' }, methods: { showHello() { this.msg = 'Hello Vue.js'; } } }) </script>
|
this
指向当前 vue 实例,由此可获取实例的其他属性。除了点击事件外还有很多其他事件,具体参考官网 API。
v-show
用来显示或隐藏元素,v-show 是通过 display 实现。当v-show的值为 true 时显示,为 false 时隐藏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div id="main"> <button type="button" v-on:click="change()">隐藏</button> <div style="width:100px;height:100px;background:red" v-show="flag"></div> </div>
<script src="./js/vue.js"></script> <script> new Vue({ el: '#main', data: { flag: true }, methods: { change() { this.flag = !this.flag; } } }) </script>
|
事件
之前说了一些关于事件的指令,这里详细学习一下事件的相关知识。
事件简写
之前的事件都是这样的写法:v-on:click="showHello()"``,vue 提供了一种简写方式:
@click=“showHello()”`
事件对象 $event
我们可以通过事件对象取得事件相关信息,如事件源、事件类型、偏移量。
下面这个例子通过事件对象取得按钮的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div id="main"> <button type="button" @click="print($event)">点击显示按钮的值</button> <br> {.{msg}.} </div>
<script src="./js/vue.js"></script> <script> new Vue({ el: '#main', data: { msg: '' }, methods: { print(e) { this.msg = e.target.innerHTML; } } }) </script>
|
事件冒泡与事件默认行为
这里需要讨论阻止事件冒泡与阻止默认行为,原生 js 阻止事件冒泡首先得取得事件对象,然后调用事件对象的stopPropagation
方法。在 vue 里,则不需要依赖于事件对象,只需要调用相应的事件修饰符stop即可:
阻止事件默认行为和阻止事件冒泡基本一致,在 vue 里也有十分便利的操作方法:
1
| @click.prevent = "print()"
|
键盘事件
vue 里内置了一些键盘事件,便于开发者操作。语法如下:
1 2
| @keydown.13 = "print()" @keydown.enter = "print()"
|
除了回车事件外,还有很多其他键盘事件,例如下:@keydown.38="print()"
。还有一些其他键盘事件,具体参考官方文档。
默认没有 @keydown.a/b/c… 事件,可以全局自定义键盘事件,也称为自定义键码或自定义键位别名:
1 2 3 4 5 6 7 8 9
| Vue.config.keyCodes = { v: 86, f1: 112, mediaPlayPause: 179, "media-play-pause": 179, up: [38, 87] }
|
除了stop
、prevent
、keyCode
这些事件修饰符以外,还有一些比较常用:
- .native - 监听组件根元素的原生事件。
- .once - 只触发一次回调。
属性
vue 提供了绑定属性的方法:v-bind:属性名=""
,这样我们即可动态的改变属性值。
属性简写
属性和事件一样,也有简写方式::属性名=""
class 属性和 style 属性
绑定 class 和 style 属性时的语法比较复杂。
变量形式
html 部分:
1
| <p :class="myClass">Hello vue.js</p>
|
对应的 vue 的 data 部分:
1 2 3
| data:{ myClass:className }
|
数组形式,同时引入多个类
html 部分:
1
| <p :class="[myClass1,myClass2]">Hello vue.js</p>
|
对应的 vue 的 data 部分:
1 2 3 4
| data:{ myClass1:className1, myClass2:className2, }
|
JSON 形式(常用)
html 部分:
1
| <p :class="{className1:true,className2:false}">Hello vue.js</p>
|
变量引用 JSON 形式
html 部分:
1
| <p :class="myClass">Hello vue.js</p>
|
对应的 vue 的 data 部分:
1 2 3 4 5
| data:{ myClass:{ className:true } }
|
style 的用法和 class 的用法基本一致,但是不常用。
模板
Vue.js 使用基于 HTML 的模板语法,可以将 DOM 绑定到 Vue 实例中的数据。模板就是{.{ }.}
,用来进行数据绑定,显示在页面中,也称为 Mustache 语法。
数据绑定的方式
双向数据绑定
使用v-model
指令,前面已经学习过。
单向数据绑定
使用两对大括号 {.{}.}
这个在之前也经常使用,但是有一个缺点,就是 vue 实例需要长时间编译时会在页面中出现{.{}.}
(闪烁现象)。vue 提供了一个解决办法:使用v-cloak
配合 css。
1 2 3 4 5 6 7 8 9
| //html内容 <div id="app" v-cloak> {.{msg}.} </div>
//css内容 [v-cloak] { display: none; }
|
使用指令 v-text、v-html
v-text
也可达到与使用v-cloak
相同的效果。
1 2 3
| //html内容 <div id="app" v-text="msg"> </div>
|
v-html
会将文本中的 html 解析为 html 标签,然后渲染到页面中。
1 2 3 4 5 6 7 8
| //html内容 <div id="app" v-html="msg"> </div>
//vue实例中data部分内容 data: { msg: 'hello<mark>vue.js<mark>' },
|
这里的 vue.js 会有一个黄色的背景颜色。
过滤器
过滤器用来过滤模型数据,在显示之前进行数据处理和筛选。语法:{.{ data | filter1(参数) | filter2(参数)}.}
。
vue1.0 中内置了很多过滤器,但是在 2.0 中全部删除了。使用过滤器我们可以通过使用第三方库:lodash、date-fns 日期格式化、accounting.js 货币格式化。或者我们可以自定义过滤器。
自定义过滤器
过滤器分为全局过滤器和局部过滤器。
全局过滤器
使用全局方法 Vue.filter(过滤器ID,过滤器函数)。
示例:
1 2 3 4 5
| <p>{.{8|addZero}.}</p>//数据会自动作为传过去
Vue.filter('addZero', data => { return data > 10 ? data : '0' + data; });
|
有时过滤器也要传递自己的参数:
1 2 3 4 5
| <p>{.{12.3456|number(3)}.}</p>
Vue.filter('number', (data,n) => { return data.toFixed(n); });
|
局部过滤器
局部过滤器的使用方法与全局过滤器的使用方法一致。
不过过滤器写在 vue 实例中 filters 选项中。
1 2 3 4 5 6 7 8 9
| new Vue({ el:'#app', data:{}, filters:{ number:data => { //具体操作 } } })
|
vue 生命周期
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
| beforeCreate(){ //组件实例刚刚创建,还未进行数据观测和事件配置 }, created(){ //实例已经创建完成,并且已经进行数据观测和事件配置 }, beforeMount(){//模板编译之前,还没挂载 }, mounted(){ //模板编译之后,已经挂载,此时才会渲染页面,才能看到页面上数据的展示 }, beforeUpdate(){//组件更新之前 }, updated(){//组件更新之后 }, beforeDestroy(){//组件销毁之前 }, destroyed(){ //组件销毁之后 }
|
这几个钩子中,最常用的是created()
与mounted()
。
计算属性
计算属性也是用来存储数据,但具有以下几个特点:
- 数据可以进行逻辑处理操作
- 对计算属性中的数据进行监视
基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div id="app"> {.{addZero}.} </div> new Vue({ el: '#app', data: { num: 8 }, computed: { //这是计算属性的get方法,用于取值 addZero() { return this.num > 10 ? this.num : '0' + this.num; } } })
|
这里的addZero
和num
一样,都是属性。不过addZero
是依赖于num
、进行计算后的值。一旦num
的值发生变化,addZero
的值也会随之变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <div id="app"> {.{num}.}----{.{addZero}.} <br> <button type="button" @click="change">点击改变num</button> </div> new Vue({ el: '#app', data: { num: 8 }, methods: { change: () => { this.num++; } }, computed: { addZero:() => { return this.num > 10 ? this.num : '0' + this.num; } } })
|
一旦我们点击按钮改变num
的值,那么因为计算属性实时监测依赖项,addZero
也会跟着发生变化。
计算属性 vs 方法
将计算属性的 get 函数定义为一个方法也可以实现和计算属性类似的功能。那么二者之间有什么区别?
- 区别一:计算属性是基于它的依赖进行实时更新的,方法则是调用才更新
- 区别二:计算属性是有缓存的,只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行。操作一个没有依赖项的值也是如此。
官方文档给出了下面这个例子:
1 2 3 4 5
| computed: { now: function () { return Date.now() } }
|
计算属性存在缓存,这里的now
值不会发生变化。
get 和 set
计算属性由两部分组成:get 和 set,分别用来获取计算属性和设置计算属性。默认只有 get,如果需要 set,要自己添加。
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"> {.{num}.}----{.{addZero}.} <br> <button type="button" @click="change(5)">点击改变num</button> </div> new Vue({ el: '#app', data: { num: 8 }, methods: { change(newNumber) { this.addZero = newNumber; } }, computed: { addZero: { get() { return this.num > 10 ? this.num : '0' + this.num; }, set(newNum) { this.num = newNum } } } })
|
我们再change
方法中改变addZero
属性的值的时候会自动调用它的 set 方法。
实例属性和方法
vue 中给实例和属性提供了若干属性和方法。
属性
获取属性的语法:实例名.属性名
以下是常用的属性:
- vm.$el: 获取 vue 实例关联的元素 DOM,进而可以对其进行操作
- vm.$data: 获取数据对象 data
- vm.$options:获取选项,自定义的选项也可以在这里获取。
- vm.$refs:获取所有添加 ref 属性的元素 dom 对象,进而可以对其进行操作
方法
vm.$mount()
手动挂载 vue 实例
1 2 3 4 5
| var vm=new Vue({ data:{ msg:'Hello vue.js' } }).$mount('#app');
|
vm.$destroy()
销毁实例
1
| vm.$destroy(); //销毁实例所占的内存空间
|
vm.$nextTick(callback)
在 DOM 更新完成后再执行回调函数,一般在修改数据之后使用该方法,以便获取更新后的 DOM
1 2 3 4 5 6 7 8 9 10 11 12 13
| var vm=new Vue({ data:{ msg:'Hello vue.js' } }).$mount('#app'); //修改数据 vm.msg='foo'; console.log(vm.$refs.title.textContent); //Hello vue.js vm.$nextTick(function(){ console.log(vm.$refs.title.textContent); //foo });
|
DOM 还没更新完,Vue 实现响应式并不是数据发生改变之后 DOM 立即变化,需要按一定的策略进行 DOM 更新,需要时间!使用$nextTick
方法等 DOM 更新完再获取数据。
vm.$set(target,key,value)
通过 vue 实例的 $set 方法为对象添加属性,可以实时监视。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <div id="app"> {.{user.name}.}<br> {.{user.age}.} <br> <button type="button" @click="addAge">添加属性</button> </div> var vm = new Vue({ data: { msg: 'Hello vue.js', user: { name: 'hedawei', gender: 'man' } }, methods: { addAge() { /* this.user.age = 22; */ this.$set(this.user, 'age', 22); } } }).$mount('#app');
|
方法中使用原始的添加属性方法的话不会在模板中显示。使用$set
方法会实时监控数据,然后添加。
vm.$watch(监听的属性,callback)
监控 vue 实例的变化
1 2 3
| vm.$watch('msg', (newValue, oldValue) => { console.log('msg被修改啦,原值:' + oldValue + ',新值:' + newValue); });
|
如果需要监控深度数据变化(例如监控一个对象中的某个属性),则需要在选项中添加{deep:true}
自定义指令
自定义指令分为自定义全局指令和自定义局部指令。
自定义全局指令
使用全局方法 Vue.directive
(指令ID,定义对象)。注:使用指令时必须在指名名称前加前缀 v-,即`v-指令名称``。
简单示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Vue.directive('hello',{ bind(){ //常用!! alert('指令第一次绑定到元素上时调用,只调用一次,可执行初始化操作'); }, inserted(){ alert('被绑定元素插入到DOM中时调用'); }, update(){ alert('被绑定元素所在模板更新时调用'); }, componentUpdated(){ alert('被绑定元素所在模板完成一次更新周期时调用'); }, unbind(){ alert('指令与元素解绑时调用,只调用一次'); } });
|
这里定义了一个名为hello
的指令,指令定义函数提供了几个钩子函数,分别在不同的时期生效。我们像下面这样使用这个指令:
1
| <p v-hello>hello vue.js</p>
|
大多数情况下,我们只需要使用bind
与update
钩子函数。vue 里提供了函数的简写形式:
1 2 3
| Vue.directive('hello', function () { alert("hello vue.js"); })
|
钩子函数有两个常用的参数el
和binding
。el
是绑定的 DOM 对象,binding
是一个对象,包含若干属性。
拿到 DOM 对象,我们就可以对 DOM 进行一些操作。
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
| <p v-hello="msg">hello vue.js</p>
Vue.directive('hello', function (el,binding) { el.style.color = "red"; //属性name是指令的名字(不带v-) console.log(binding.name); //hello //属性value是传递给指令的值 console.log(binding.value); //alice //属性expression是指令值的字符串形式(个人感觉就是类似变量名) console.log(binding.expression); //msg //属性arg是传递给指令的参数(和传值写在一起容易令初学者困惑,下面分开写 //合在一起写的写法是<p v-hello:123="msg">hello vue.js</p>) //<p v-hello:123>hello vue.js</p> console.log(binding.arg); //123 //属性modifiers是一个包含修饰符的对象。 //与传参传值合在一起的写法是 <p v-hello:123.bar="msg">hedawei</p> //<p v-hello.bar>hello vue.js</p> console.log(binding.modifiers); //{bar:true} })
var vm = new Vue({ el: '#app', data: { msg: 'alice' } })
|
局部自定义指令
局部自定义指令写在实例的directives
选项中。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var vm = new Vue({ el: '#app', data: { msg: 'alice' }, methods: { }, directives: { word: function(el, binding) { console.log(binding.name); } } })
|
其他用法与全局自定义指令一致。
过渡(动画)
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。本质上还是使用 CSS3 动画:transition、animation 属性。
基本用法
使用 transition 组件,将要执行动画的元素包含在该组件内:
1 2 3
| <transition name="fade"> 运动的元素 </transition>
|
我们需要为其定义一个name属性,以便后面为其添加 css 样式。
动画有 6 个 CSS 类名,下面结合的例子说明:
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
| <style> button { display: block; margin: 20px auto; } p { width: 100px; height: 100px; background-color: red; margin: 0 auto; } .fade-enter-active, .fade-leave-active { //定义整个过渡期间的效果 transition: all 2s ease; } .fade-enter-to { //定义过渡进入的最终效果 opacity: 1; width: 100px; height: 100px; } .fade-leave-to { //定义过渡离开的最终效果 opacity: 0; width: 50px; height: 50px; } .fade-enter { //定义过渡进入的开始效果 opacity: 0; width: 50px; height: 50px; } </style> <div id="app"> <button type="button" @click="flag = !flag">点 击</button> <transition name="fade"> <p v-show="flag"> </p> </transition> </div> <script> new Vue({ el: '#app', data: { flag: false } }); </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
| <transition name="fade" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave"> <p v-show="flag"> </p> </transition> new Vue({ methods: { beforeEnter(el) { alert('动画进入之前'); }, enter(el) { alert('动画进入'); }, afterEnter(el) { alert('动画进入之后'); }, beforeLeave(el) { alert('动画离开之前'); }, leave(el) { alert('动画离开'); }, afterLeave(el) { alert('动画离开之后'); } } });
|
在这不同的时期,我们可以取到过渡元素的 DOM 对象,从而对其进行操作。
多元素过渡
上面的标签只适用于单元素过渡。若要对多元素进行过渡,则需要使用标签,并且绑定key属性,设置不同的值。
1 2 3 4 5 6 7
| <button type="button" @click="flag = !flag">点 击</button> <transition-group name="fade"> <p v-show="flag" :key="1"> </p> <p v-show="flag" :key="2"> </p> </transition-group>
|
结合第三方库一起使用(animate.css)
我们可以使用 vue 的自定义过渡类名结合第三方动画库实现自定义动画效果。这六个自定义类名和 vue 内置的类名类似:
- enter-class
- enter-active-class
- enter-to-class
- leave-class
- leave-active-class
- leave-to-class
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| p { width: 300px; height: 300px; background-color: red; margin: 0 auto; }
<div id="app"> <button type="button" @click="flag = !flag">点 击</button> <transition enter-active-class="animated tada" leave-active-class="animated bounceOutRight"> <p v-show="flag"> </p> </transition> </div>
<script> new Vue({ el: '#app', data: { flag: false } }); </script>
|
组件
什么是组件
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码组件是自定义元素(对象)。
创建组件的两种方式
官方推荐组件标签名是使用-连接的组合词,例如:<my-hello></my-hello>
。
使用构造器创建组件
使用这种方式创建组件首先需要使用Vue.extend()
创建一个组件构造器,然后使用Vue.component(标签名,组件构造器)
,根据组件构造器来创建组件。
1 2 3 4 5 6 7 8 9 10 11
| //1.创建构造器 var MyComponent=Vue.extend({ template:'<h3>Hello World</h3>' }); //2.创建组件 Vue.component('my-hello',MyComponent);
//3.使用组件 <div id="app"> <my-hello></my-hello> </div>
|
这种创建组件的方式比较麻烦,使用的较少。
直接创建组件
使用`Vue.component(标签名,组件模板)``,根据组件构造器来创建组件。
1 2 3 4 5 6 7 8 9
| //1.创建组件 Vue.component('my-world', { template: '<h2>hello vue.js</h2>' }); //2.使用组件 <div id="app"> <my-world></my-world> </div>
|
组件的分类
组件分为全局组件和局部组件。
全局组件
使用Vue.component()
创建的组件都是全局组件。这样的组件在任何组件内都能使用。上面我们创建就是全局组件。
局部组件
局部组件一般都是定义在实例的选项中,称为实例的子组件。相应的,实例也被称为父组件。
1 2 3 4 5 6 7 8 9 10 11 12 13
| //1.定义组件 new Vue({ el: '#app', components: { dawei: { template: '<h2>my name is dawei</h2>' } } }); //2.使用组件 <div id="app"> <dawei></dawei> </div>
|
引用模板
很多时候我们的template
模板中需要存放很多标签内容,这样的话写起来会很麻烦。这时候我们可以使用template
标签。
用法如下:
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
| <template id="wbs"> //使用template标签 <div> <h2>hello {.{msg}.}</h2> <ul> <li v-for="value in arr"> {.{value}.} </li> </ul> </div> </template> new Vue({ el: '#app', components: { 'my-dawei': { template: '#wbs', //选择template标签 data() { return { msg: 'vue.js', arr: ["a", "b", "c", "d"] } } } } });
|
这里涉及到的几个知识点得着重提一下:
- 在
template
模板中,所有的元素必须放置在一个根元素中,要不然会报错。例子中我们将元素放置在了<div>
标签中。
- 组件中的
data
选项必须是一个函数类型,使用return
返回所有的数据。
动态组件
很多时候项目中需要在某一个地方动态的使用不同的组件,这时候就需要使用动态组件。
动态组件的使用需要绑定is属性:
1
| <component :is="flag"></component>
|
简单示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| //点击按钮显示不同的组件 <div id="app"> <button type="button" @click="flag='my-a'">显示a组件</button> <button type="button" @click="flag='my-b'">显示b组件</button>
<component :is="flag"></component> //传入flag </div>
new Vue({ el: '#app', data: { flag: 'my-a' //给flag赋值 }, components: { 'my-a': { template: '<p>我是a组件</p>', }, 'my-b': { template: '<p>我是b组件</p>' } } });
|
keep-alive 组件
使用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
| <keep-alive> <component :is="flag"></component> </keep-alive>
<div id="app"> <button type="button" @click="flag='my-x'">x</button> <button type="button" @click="flag='my-y'">y</button> <keep-alive> <component :is="flag"></component> </keep-alive> </div> new Vue({ el: '#app', data: { flag: 'my-x' }, components: { 'my-x': { template: '<p>{.{x}.}</p>', data() { return { x: Math.random() } } }, 'my-y': { template: '<p>{.{y}.}</p>', data() { return { y: Math.random() } } } } });
|
这样的话,第一次产生的随机数就会被缓存,再次切换的时候也不会发生改变。
组件间数据传递
父子组件
在一个组件内部定义另一个组件,那么这对组件称为父子组件。子组件只能在父组件内部使用。默认情况下,每个组件实例的作用域是独立的,子组件无法访问父组件中的数据,同样,父组件也无法访问子组件中的数据。
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
| <div id="app"> <my-a></my-a> </div>
<template id="a"> <div> <p>{.{msg}.}</p> <my-b></my-b> </div> </template>
<template id="b"> <div> <p>{.{mydata}.}</p> </div> </template>
<script> new Vue({ el: '#app', components: { "my-a": { template: "#a", data() { return { msg: '我是父组件', } }, components: { "my-b": { template: "#b", data() { return { mydata: "我是子组件" } } } } } } }); </script>
|
组件间数据传递(通信)
子组件访问父组件的数据
步骤:
- a、调用子组件时,绑定想要获取的父组件中的数据
- b、在子组件内部,使用 props 选项声明获取的数据,即接收来自父组件的数据
改进上面的例子:
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
| <div id="app"> <my-a></my-a> </div>
<template id="a"> <div> <p>{.{msg}.}</p> <p>这是要传递给子组件的值:{.{myname}.}</p> <my-b :name="myname"></my-b> </div> </template>
<template id="b"> <div> <p>{.{mydata}.}</p> <p>这是父组件传递过来的数据:{.{name}.}</p> </div> </template>
<script> new Vue({ el: '#app', data: {}, components: { "my-a": { template: "#a", data() { return { msg: '我是a组件', myname: '子组件b你好,我是父组件a' } }, components: { "my-b": { template: "#b", data() { return { mydata: "我是b组件" } }, props: ["name"] } } } } }); </script>
|
父组件访问子组件的数据
步骤:
- a 在子组件中使用 vm.$emit(事件名, 数据) 触发一个自定义事件,将数据发送给父组件,事件名自定义
- b 父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| //子组件‘my-b’内部 methods:{ send(){//使用$emit()触发一个事件,发送数据,this指当前子组件实例 this.$emit('e-world', this.senddata); } }
//在调用子组件的地方监听子组件触发的事件,调用自己的方法获取数据 <my-b @e-world="getData"></my-b>
methods: { getData(data) { //参数是子组件传递过来的数据 this.revicedata = data; } }
|
单向数据流
props 是单向数据绑定的,当父组件数据发生变化时,将传递给子组件,但是不会反过来。而且不允许子组件直接修改父组件中的数据,强制修改会报错。
解决方案:
- 如果子组件想把它作为局部数据来使用,可以将数据存入另一个变量中再操作,不影响父组件中的数据
- 如果子组件想修改数据并且同步更新到父组件,两个方法:
- 使用
.sync
显式地触发一个更新事件(1.0 版本中支持,2.0 版本中不支持,2.3 版本又开始支持)
1 2 3 4 5
| //使用.sync <my-b :name.sync="myname"></my-b> //子组件修改父组件传入的值name,触发update更新事件 this.$emit('update:name', "vuejs");
|
- 可以将父组件中的数据包装成对象,然后在子组件中修改对象的属性 (因为对象是引用类型,指向同一个内存空间),推荐使用这种方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| data() { return { //将要传递的数据放入message对象中 message: { hello: '子组件b你好,我是父组件a' } } }
<my-b :message="message"></my-b> //传递这个对象给子组件
methods: { //在子组件内部修改这个值,这样就会同步传递给父组件。 edit() { this.message.hello = "hahahahh"; } }
|
非父子组件间的通信
非父子组件间的通信,可以通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现非父子组件间的通信。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var Event = new Vue(); //空vue实例
methods: { send() { //触发emit事件 Event.$emit("hello", this.asmsg); } } mounted() { //在子组件的钩子函数中监听该事件 Event.$on('hello', data => { //获取值 this.bsmsg = data; }) }
|
slot 内容分发
用来获取组件中的原内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var vm = new Vue({ el: '#app', components: { 'my-hello': { template: '#hello' } } });
<div id="app"> <my-hello>hello vue.js</my-hello> </div>
<template id="hello"> <div> <slot>如果没有原内容,则显示该内容</slot> </div> </template>
|
如果组件标签中没有内容就会显示 slot 中的内容,这也就是所谓的单个插槽。
还可以对显示的内容进行分组,这就是具名插槽,可以操作标签组中的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <div id="app"> <my-hello> <ul slot="s1"> <li>aaa</li> <li>bbb</li> <li>ccc</li> </ul> <ol slot="s2"> <li>111</li> <li>222</li> <li>333</li> </ol> </my-hello> </div>
<template id="hello"> <div> <slot name="s2"></slot> //为插槽指定名称 将名为s2的内容放置在这里 <p>hello vue.js</p> <slot name="s1"></slot> //将名为s1的内容放置在这里 </div> </template>
|
这样,就可以对组件中的内容实时操作。
vue-router
简介
我们经常使用 vue 开发单页面应用程序(SPA)。在开发 SPA 过程中,路由是必不可少的部分,vue 的官方推荐是 vue-router。单页面应用程序看起来好像是一个页面,其实是在一个页面中切换不同的 html 部分,从而达到所谓的单页面, 在这切换之中,就需要使用路由来实现不同的页面内容的展现。
基本用法
使用步骤
vue-router 的基本使用步骤如下:
- 定义需要切换的组件
- 配置路由,规定路径到组件的映射关系
- 创建路由实例
- 将路由挂载到 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
| //1.定义组件,用于路由切换 var Home = { template: '<div>我是主页</div>' } var News = { template: '<div>我是新闻</div>' }
//2.配置路由 const routes = [{ path: '/home', component: Home },{ path: '/news', component: News },{ //这一路由配置用于首次访问或者找不到所请求路由,自动跳转home页 path: '*', redirect: '/home' }];
//3.创建路由实例 var router = new VueRouter({ routes //传入配置好的路由信息 });
//4.挂载路由到根组件 new Vue({ el: '#app', router });
|
这样我们就配置好了一个完整的路由。在切换组件的时候会根据路由加载不同的组件。我们使用类似 a 标签的<router-link to="url"></router-link>
触发组件的切换,to
属性存放的是路径。使用<router-view></router-view>
来显示所切换组件。
1 2 3 4 5 6
| <div id="app"> <router-link to="/home">主页</router-link> <router-link to="/news">新闻</router-link>
<router-view></router-view> </div>
|
这样我们就可以实现主页和新闻组件间的切换。
参数传递
可能我们需要向所切换组件传递参数。vue 提供了两种向组件传递参数的方式。
- 查询字符串的形式
- /home?name=dawei&pwd=666
- 在组件内部使用
{.{$route.query}.}
接收参数
- rest 风格
- /news/param1/param2
- 在组件内部使用
{.{$route.params}.}
接收参数
路由嵌套
路由还可以多层嵌套使用,使用children
属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| { path:'/user', component:User, children:[ { path:'login', component:Login }, { path:'regist', component:Regist } ] }
|
子路由项路径不要使用/
开头,以/
开头的嵌套路径会被当作根路径。
在组件中就可以使用该路由:
1 2 3 4 5 6 7 8
| <div> <h3>用户信息</h3> <ul> <router-link to="/user/login">用户登陆</router-link> <router-link to="/user/regist">用户注册</router-link> </ul> <router-view></router-view> </div>
|
注意路径的写法。
路由实例的方法
这里学习两个路由实例的方法:router.push()
和router.replace()
。
- router.push():添加路由,功能上与相同
- router.replace(): 替换路由,不产生历史记录
1 2
| router.push({path:'home'}) router.replace({path:'user'})
|
路由结合动画
路由结合动画使用很简单,我们可以用 组件给它添加一些动画效果:
1 2 3
| <transition> <router-view></router-view> </transition>
|
单文件组件
.vue 文件
.vue
文件称为单文件组件,是 Vue.js 自定义的一种文件格式,一个. vue 文件就是一个单独的组件,在文件内封装了组件相关的代码:html、css、js 代码。
.vue
文件由三部分组成:<template>
、<style>
、<script>
:
1 2 3 4 5 6 7 8 9 10 11
| <template> //html </template>
<script> //js </script>
<style> //css </style>
|
vue-loader
浏览器本身并不认识. vue 文件,此时需要 vue-loader 对. vue 文件进行加载解析,。类似的 loader 还有许多,如:html-loader、css-loader、style-loader、babel-loader 等。需要注意的是 vue-loader 是基于 webpack 的。
webpack
webpack 是一个前端资源模板化加载器和打包工具,它能够把各种资源都作为模块来使用和处理。实际上,webpack 是通过不同的 loader 将这些资源加载后打包,然后输出打包后文件。简单来说,webpack 就是一个模块加载器,所有资源都可以作为模块来加载,最后打包输出。
vue-cli
简介
vue-cli 是一个 vue 脚手架,可以帮助我们快速构造项目结构,减少开发人员开发阻力。vue-cli 集成了多种版本:
- simple :比较简单
- webpack :包含 ESLint 代码规范检查和 unit 单元测试等
- webpack-simple: 没有代码规范检查和单元测试
- browserify: 使用的也比较多
- browserify-simple
安装、操作步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| //安装vue-cli,配置vue命令环境 cnpm install vue-cli -g vue --version vue list
// 初始化项目,生成项目模板 vue init 模板名 项目名
//进入生成的项目目录,安装模块包 cd vue-cli-demo cnpm install
//运行 npm run dev //启动测试服务 npm run build //将项目打包输出dist目录,项目上线的话要将dist目录拷贝到服务器上
|
文件介绍
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
| . |-- build // 项目构建(webpack)相关代码 | |-- build.js // 生产环境构建代码 | |-- check-version.js // 检查node、npm等版本 | |-- dev-client.js // 热重载相关 | |-- dev-server.js // 构建本地服务器 | |-- utils.js // 构建工具相关 | |-- webpack.base.conf.js // webpack基础配置 | |-- webpack.dev.conf.js // webpack开发环境配置 | |-- webpack.prod.conf.js // webpack生产环境配置 |-- config // 项目开发环境配置 | |-- dev.env.js // 开发环境变量 | |-- index.js // 项目一些配置变量 | |-- prod.env.js // 生产环境变量 | |-- test.env.js // 测试环境变量 |-- src // 源码目录 | |-- components // vue组件 | |-- store // 状态管理 | |-- App.vue // 页面入口vue文件 | |-- main.js // 程序入口文件,加载各种公共组件 |-- static // 静态文件 | |-- data |-- .babelrc // ES6语法编译配置 |-- .editorconfig // 定义代码格式 |-- .gitignore // git上传需要忽略的文件格式 |-- README.md // 项目说明 |-- favicon.ico //网页图标 |-- index.html // 入口页面 |-- package.json // 项目配置信息 .
|
此列表拷贝自: 这里
Reference
This is the end of post