三、组件
组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML
元素,封装可重用的代码。
定义组件
Vue自定义组件分为两种:全局注册和局部注册,全局组件可以在任何地方引用,局部组件只能在当前Vue实例使用。
全局注册
使用Vue.component(tagName, options)来定义:
/*定义全局组件*/
Vue.component('my-component',{
template:'
我是自定义组件
'});
注意,HTML
特性是不区分大小写的,所有在定义组件时尽量使用中划线"-"来指定组件名。即使,使用了驼峰标示命名如:myComponent,在页面引用时仍然要使用
2)局部注册
在Vue实例中使用components属性来定义:
var app = new Vue({
el:'#app',
//使用components关键字
components:{
'inner-component':{
template:'我是局部注册组件
'
}
}
});
2、使用组件
完整代码:
3、is属性
在table标签中直接使用自定义组件,无法正常显示。DOM解析时会解析到
DOM解析:
原因是:table/ol/ul/select
这种html标签有特殊的结构要求,不能直接使用自定义标签。他们有自己的默认嵌套规则,比如:
table> tr> [th, td];
ol/ul > li;
select > option
解决上述问题,可以使用is进行标签转换,形式:
< is="my-component">
完整代码:
4.模板
当模板的html结构比较复杂时,直接在template属性中定义就不现实了,效率也会很低,此时我们可以使用模板,定义模板的四种形式:
直接使用字符串定义
使用
使用标签
使用.vue组件,需要使用模块加载机制
在使用直接字符串模板时、x-template和.vue组件时,不需要is进行转义。
直接字符串
var temp = '直接字符串
';
Vue.component('my-component1',{
template:temp
});
2)x-template模板
Vue.component('my-component2',{
template:'#template2'
});
3)template标签
- a
- b
Vue.component('my-component3',{
template:'#template3'
});
4)单标签引用
5)省略is
Vue.component('my-component6',{
template:'#template5'
});
除了模板,其他的都可以直接嵌套,不用is指定。
5、data属性
通过data属性指定自定义组件的初始数据,要求data必须是一个函数,如果不是函数就会报错。
Vue.component('my-component',{
template:'',
data: function () {
return{count:0}
}
});
综合例子:
6.prop属性
组件可以嵌套使用,叫做父子组件。那么父组件经常要给子组件传递数据这叫做父子组件通信。父子组件的关系可以总结为 prop向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。看看它们是怎么工作的:
1)声明prop
Vue.component('child', {
//声明props
props:['a','b'],
//使用父组件传递的数据
template:'{{a}} == {{b}}'
});
2)父组件
var app = new Vue({
el:'#app',
data:{
msg:'来自父组件的消息',
greetText:'你好Child'
}
});
3)用指定prop传递数据
4)完整代码
7.prop校验
子组件在接收父组件传入数据时,
可以进行prop校验,来确保数据的格式和是否必传。可以指定一下属性:
1) type: 指定数据类型 String Number Object
...注意不能使用字符串数组,只能是对象大写形式
2) required: 指定是否必输
3) default: 给默认值或者自定义函数返回默认值
4) validator: 自定义函数校验
形式如下:
Vue.component('example', {
props: {
// 基础类型检测 (`null` 指允许任何类型)
propA: Number,
// 可能是多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数值且有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
})
完整代码:
8、非prop属性
引用子组件时,非定义的prop属性,自动合并到子组件上,class和style也会自动合并。
9、自定义事件
父组件给子组件传值使用props属性,
那么需要子组件更新父组件时,要使用自定义事件$on和$emit:
$on监听: 不能监听驼峰标示的自定义事件,
使用全部小写(abc)或者-(a-b-c)$emit主动触发: $emit(事件名,传入参数)
1)声明父组件
var app = new Vue({
el:'#app',
data:{
count:0
},
methods:{
//定义计数方法
changeCount:function(value){
console.log(value);
//计数
this.count += 1;
}
}
});
2)自定义事件
{{count}}
在事件v-on:update-count中的update-count就是自定义事件的名字,不要使用驼峰标示,html不区分大小写,会导致子元素无法主动触发父组件的自定义事件。
3)定义子组件
Vue.component('child', {
template:'',
methods:{
update: function () {
console.log('update');
//主动触发事件执行
this.$emit('update-count', '子组件参数');
}
}
});
子组件child中定义的update方法,内部通过$emit('update-count')主动触发父元素事件的执行。
完整代码:
{{count}}
4)主动挂载
自定义事件不仅可以绑定在子组件,也可以直接挂载到父组件,使用$on绑定和$emit触发。
var app = new Vue({
el:'#app',
data:{
count:0
},
methods:{
changeCount:function(value){
console.log(value);
//计数
this.count += 1;
}
}
});
//主动挂载
app.$on('update-count', function(value){
console.log(value);
//计数
this.count += 1;
});
app.$emit('update-count',123);
四、插槽分发
父子组件使用时,有时需要将父元素的模板跟子元素模板进行混合,这时就要用到slot插槽进行内容分发,
简单理解就是在子模板中先占个位置
1、slot插槽
1)子组件插槽
我是子组件
{{msg}}
我是默认内容,父组件不传入时我显示
Vue.component('child', {
template:'#child-template',
props:['msg']
});
在子组件模板中使用
2)父组件分发
父组件模板
模板混入....
在引用
完整代码:
父组件模板
模板混入....
我是子组件
{{msg}}
我是默认内容,父组件不传入时我显示
2、具名插槽
具名插槽slot,
就是给插槽起个名字。在子组件定时可以定定义多个
1)定义具名插槽
我是子组件
{{msg}}
模板定义了两个插槽header和footer,分别使用name属性进行名称的指定。
2)父组件分发
头部
底部
通过slot属性,来确定内容需要分发到那个插槽里面。
完整代码:
头部
底部
我是子组件
{{msg}}
3、slot-scope
作用域插槽slot-scope,父组件通过
子组件也可以通过slot作用域向插槽slot内部传入数据,使用方式:
1)子组件定义
在slot标签中指定属性值,类似于prop属性的使用。
2)父组件使用
{{msgText}}
{{props.text}}
引用时用template标签指定,slot-scope属性指定接收数据的变量名,就可以使用花括号形式取值了。
完整代码:
{{msgText}}
{{props.text}}
3)版本更新
在2.5+之后,可以不局限于,
任何元素都可以,同时可以使用解构赋值的方式进行数据解析。
子组件:
父组件使用:
子组件数据: {{props.text}} {{fa}}
{{props.text}} == {{props.value}}
{{text}} == {{title}}
js部分:
Vue.component('child', {
template:'#child-template'
});
var app = new Vue({
el:'#app',
data:{
fa:'father 数据'
}
});
五、动态组件
使用
1、使用方式
1)定义多个子组件
Vue.component('index', {
template:'首页
'
});
Vue.component('news', {
template:'新闻页
'
});
Vue.component('login', {
template:'登陆页
'
});
2)使用component引用
3)指定导航
/ 首页
/ 新闻
/ 登陆
4)完整代码
2、keep-alive
如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。为此可以添加一个 keep-alive 指令。
使用keep-alive嵌套component。
Vue.component('index', {
template:'首页
',
mounted: function () {
console.log('挂载...首页');
}
});
Vue.component('news', {
template:'新闻页
',
mounted: function () {
console.log('挂载...新闻页');
}
});
Vue.component('login', {
template:'登陆页
',
mounted: function () {
console.log('挂载...登陆页');
}
});
用生命周期中的mounted(挂载)钩子函数进行组件渲染监听,当组件第一次被渲染后就保存在内存中,下次切换不会被重新渲染。
3、refs
使用ref
给每个组件起一个固定的名字,方便后续直接引用操作,在父组件中使用$refs访问子组件。
六、动画过渡
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。
包括以下工具:
在 CSS 过渡和动画中自动应用 class
可以配合使用第三方 CSS 动画库,如 Animate.css
在过渡钩子函数中使用 JavaScript 直接操作 DOM
可以配合使用第三方 JavaScript 动画库,如 Velocity.js
Vue组件添加动画效果使用
标签
v-enter: 显示动画初始状态
v-enter-active: 显示动画执行状态
v-enter-to: 显示动画结束状态
v-leave: 隐藏动画初始状态
v-leave-active: 隐藏动
v-leave-to: 隐藏动画结束状态
1、基本使用
1)使用动画
{{greetText}}
定义class
js部分
var app = new Vue({
el:'#app',
data:{
show:true,
greetText:'Hello Vue!'
}
});
5)使用css动画
2.自定义过渡类名
可以手动指定过渡类名:
enter-class
enter-active-class
enter-to-class (2.1.8+)
leave-class
leave-active-class
leave-to-class (2.1.8+)
配合animate.css库一起使用:
{{greetText}}
3、初始过渡
通过 appear 特性设置节点的在初始渲染的过渡
{{greetText}}
4、过渡状态
通过mode属性可以指定动画切换效果先后顺序:
in-out:新元素先进行过渡,完成之后当前元素过渡离开。
out-in:当前元素先进行过渡,完成之后新元素过渡进入。
1)指定过渡状态
2)定义css
3)js部分
/****
* 初始过渡 appear:
* mode: in-out out-in
* */
var app = new Vue({
el:'#app',
data:{
show:true
}
});
5、列表过渡
内部元素需要提供唯一的 key 属性值。
css:
html:
{{i}}
js:
七、数据处理
1、watch属性
在Vue组件中,使用watch属性来监听数据的变化,同时可以指定监听那个属性。
例子中通过watch监听name属性的变化,回调函数中第一个参数是新值,第二个参数是旧值。
firstName:
lastName:
{{fullName}}
fullName由firstName和lastName共同决定,当改变firstName时需要重新计算fullName,改变lastName也一样。那么就需要监听这两个属性的变化去更新fullName,这时候就可以使用watch监听。
2.$watch
除了在组件内部使用watch也可以使用内部命令$watch进行属性监听。
$watch第一个参数是需要监听的属性,第二个是回调函数用法和watch一样。需要取消监听只需拿到监听对象的引用,这个引用是返回一个函数对象,执行该对象就可以取消监听。
同时监听多个属性,可以不指定属性:
3、computed属性
computed计算属性用于定义比较复杂的属性计算,比如上边计算fullName的时候,需要使用watch两个属性:firstName和lastName,比较繁琐,但是使用computed就很简单。
firstName:
lastName:
{{fullName}}
此时注意,不在data中定义fullName而是在computed属性中指定,回调函数返回值就是fullName的值,这样不管firstName和lastName谁发生变化都会更新fullName。
computed和methods区别:
计算属性使用computed定义, 方法使用methods定义
计算属性使用时不加括号执行符
计算属性是基于它们的依赖进行缓存的,计算属性只有在它的相关依赖发生改变时才会重新求值。否则返回之前计算好的值,性能更高!
修改之前的代码
{{fullName}}
改为:
{{fullName()}}
在methods中定义fullName,使用效果和使用computed一致:
fullName: function () {
return this.firstName+' '+this.lastName;//计算fullname
}
4.getter和setter
在computed中,同样可以指定setter进行数据更新。上述例子中都是通过firstName和lastName来计算fullName,那么也可以通过fullName来更新firstName和lastName。
fullName:
firstName: {{firstName}}
lastName: {{lastName}}
此时改变fullName就可以同步更新lastName和firstName。
八、生命周期
每个 Vue
实例在被创建之前都要经过一系列的初始化过程。例如需要设置数据监听、编译模板、挂载实例到
DOM、在数据变化时更新 DOM
等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,给予用户机会在一些特定的场景下添加他们自己的代码。
比如 created 钩子可以用来在一个实例被创建之后执行代码;
常用的生命周期钩子函数有:
1) created: 实例创建完成后被立即调用
2) mounted: 实例挂载完成后被立即调用
3) beforeUpdate: 实例需要渲染之前调用
4) updated: 实例更新后调用
5) destroyed: Vue 实例销毁后调用
{{name}}
九、自定义指令
除了默认设置的核心指令 (v-model 和 v-show),Vue 也允许注册自定义指令。
1、基本使用
1)定义
//自定义全局指令v-focus
Vue.directive('focus',{
//当绑定元素插入到DOM调用
inserted: function (el) {
//元素获取焦点
el.focus();
}
});
使用directive定义,第一个参数为指令名,使用时加上v-前缀才能生效。inserted属性指当绑定元素插入到DOM时调用。
定义局部指令使用directives:
var app = new Vue({
el:'#app',
directives:{
focus:{
inserted: function (el) {
//元素获取焦点
el.focus();
}
}
}
});
2)使用
2、钩子函数
指令定义函数提供了几个钩子函数 (可选):
bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
inserted:被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于
document 中)。update:所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode
更新之前。指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
。componentUpdated:所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
unbind:只调用一次,指令与元素解绑时调用。
钩子函数的参数有三个:
el:当前指令绑定元素
binding:当前指令绑定的所有信息对象,有以下属性:
name:指令名,不包括 v- 前缀。
value:指令的绑定值,例如:v-my-directive="1 + 1", value 的值是 2。
oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression:绑定值的字符串形式。例如 v-my-directive="1 +
1" ,expression 的值是 "1 + 1"。arg:传给指令的参数。例如 v-my-directive:foo,arg 的值是 "foo"。
modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar,
修饰符对象 modifiers 的值是 { foo: true, bar: true }。
3)vnode:Vue 编译生成的虚拟节点
4)oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated
钩子中可用。
3.实例图片懒加载
谷歌图片的加载做得非常优雅,在图片未完成加载前,用随机的背景色占位,图片加载完成后才直接渲染出来,用自定义指令可以非常方便的实现这个功能。
1)样式
2)自定义v-img指令
//定义全局自定义指令v-img
Vue.directive('img',{
bind: function (el,binding) {
//生成随机颜色
var color = parseInt(Math.random()*0xFFFFFF).toString(16);
//设置当前元素的背景,提前进行占位等待图片加载
el.style.background = '#'+color;
//setTimeout模拟图片加载的延时情况
setTimeout(function () {
//创建图片对象
var img = new Image();
//通过binding对象获取真实的图片url
img.src = binding.value;
//将图片元素插入DOM结构
el.appendChild(img);
//随机延时
},Math.random()*3000+500);
}
});
3)模拟数据
var app = new Vue({
el:'#app',
data:{
//定义模拟数据
imgs:[
{url:'img/01.jpg'},
{url:'img/02.jpg'},
{url:'img/03.jpg'},
{url:'img/04.jpg'}
]
}
});
4)使用
5)效果
十、过滤器
Vue允许自定义过滤器,可被用作一些常见的文本格式化。
过滤器可以用在两个地方:mustache 插值和 v-bind 表达式 (后者从 2.1.0+
开始支持)。
过滤器应该被添加在 JavaScript 表达式的尾部,由"管道"符指示:
{{ message | capitalize }}
过滤器可以串联:
{{ message | filterA | filterB }}
使用Vue.filter定义全局过滤器,filters在组件内指定局部过滤器。
{{name | upperCase | length | test('A-','-B')}}
十一、路由
随着(SPA)单页应用的不断普及,前后端开发分离,目前项目基本都使用前端路由,在项目使用期间页面不会重新加载。
优点:
用户体验好,和后台网速没有关系,不需要每次都从服务器全部获取,界面展现快。
可以再浏览器中输入指定想要访问的url路径地址。
实现了前后端的分离,方便开发。有很多框架都带有路由功能模块。
缺点:
对SEO不是很友好
在浏览器前进和后退时候重新发送请求,没有合理缓存数据。
初始加载时候由于加载所有模块渲染,会慢一点。
1、手动实现路由
前端路由目前主要有两种方法:
1)利用url的hash,就是常用的锚点(#)操作,类似页面中点击某小图标,返回页面顶部,JS通过hashChange事件来监听url的改变,IE7及以下需要轮询进行实现。一般常用框架的路由机制都是用的这种方法,例如Angualrjs自带的ngRoute和二次开发模块ui-router,react的react-route,vue-route...
2)利用HTML5的History模式,使url看起来类似普通网站,以"/"分割,没有"#",但页面并没有跳转,不过使用这种模式需要服务器端的支持,服务器在接收到所有的请求后,都指向同一个html文件,通过historyAPI,监听popState事件,用pushState和replaceState来实现。
由于使用hash方法能够兼容低版本的IE浏览器,简单的的自己搭建前端路由。
自定义路由
2.vue-router
vue-router是Vue官方提供的路由,用 Vue.js + vue-router
创建单页应用,是非常简单的。使用 Vue.js
,我们已经可以通过组合组件来组成应用程序,当你要把 vue-router
添加进来,我们需要做的是,将组件(components)映射到路由(routes),然后告诉
vue-router 在哪里渲染它们。下面是个基本例子:
vue-router
Hello App!
Go to index
Go to news
3.动态路由
vue-router
Hello App!
User12
User13
十二、Ajax
1、vue-resource介绍
vue-resource插件具有以下特点:
1. 体积小
vue-resource非常小巧,在压缩以后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比jQuery的体积要小得多。
2. 支持主流的浏览器
和Vue.js一样,vue-resource除了不支持IE
9以下的浏览器,其他主流的浏览器都支持。
3.
支持Promise API和URI
Templates
Promise是ES6的特性,Promise的中文含义为"先知",Promise对象用于异步计算。
URI Templates表示URI模板,有些类似于ASP.NET MVC的路由模板。
4. 支持拦截器
拦截器是全局的,拦截器可以在请求发送前和发送请求后做一些处理。
拦截器在一些场景下会非常有用,比如请求发送前在headers中设置access_token,或者在请求失败时,提供共通的处理方式。
2、使用规则
引入vue-resource后,可以基于全局的Vue对象使用http,也可以基于某个Vue实例使用http。
1)基于全局Vue对象使用http
Vue.http.get('/someUrl',[options]).then(successCallback, errorCallback);
Vue.http.post('/someUrl',[body],[options]).then(successCallback,errorCallback);
Vue.http.jsonp('/someUrl',[options]).then(successCallback,errorCallback);
2)在一个Vue实例内使用$http
this.$http.get('/someUrl',[options]).then(successCallback,errorCallback);
this.$http.post('/someUrl',[body],[options]).then(successCallback,errorCallback);
this.$http.jsonp('/someUrl', [options]).then(successCallback, errorCallback);
在发送请求后,使用then方法来处理响应结果,then方法有两个参数,第一个参数是响应成功时的回调函数,第二个参数是响应失败时的回调函数。
3)实例
Title