一、组键
1、定义组件
Vue自定义组件分为两种:全局注册和局部注册,全局组件可以在任何地方引用,局部组件只能在当前Vue实例使用。
1)全局注册
使用Vue.component(tagName, options)来定义:
1)局部注册
在Vue实例中使用components属性来定义:
注意:HTML 特性是不区分大小写的,所有在定义组件时尽量使用中划线“-”来指定组件名。
即使,使用了驼峰标示命名如:myComponent,在页面引用时仍然要使用进行引用。
2.is属性
在table标签中直接使用自定义组件,无法正常显示。DOM解析时会解析到
原因是:table/ol/ul/select 这种html标签有特殊的结构要求,不能直接使用自定义标签。他们有自己的默认嵌套规则,比如:
table> tr> [th, td];
ol/ul > li;
select > option
3.模板
当模板的html结构比较复杂时,直接在template属性中定义就不现实了,效率也会很低,此时我们可以使用模板,定义模板的四种形式:
1)直接使用字符串定义
2)使用
<!--2)使用<script type="text/x-template">-->
<script type="text/x-template" id="tpl3">
<ul>
<li>01</li>
<li>02</li>
</ul>
</script>
<!--3)使用<template>标签-->
<template id="tpl4">
<ul>
<li>011</li>
<li>022</li>
</ul>
</template>
3.data属性
通过data属性指定自定义组件的初始数据,要求data必须是一个函数,如果不是函数就会报错。
<div id="app">
<!--使用组件-->
<my-hello></my-hello>
<my-hello></my-hello>
<my-hello></my-hello>
</div>
4.props属性
Props属性
组件可以嵌套使用,叫做父子组件。那么父组件经常要给子组件传递数据这叫做父子组件通信。
父子组件的关系可以总结为 props 向下传递,事件向上传递。
父组件通过 props 给子组件下发数据,子组件通过事件给父组件发送消息。
1、在父组件中定义数据
2、在使用组件时,绑定父组件中的数据
3、在子组件中通过props属性声明父组件中传递过来的参数
4、在template属性中使用父组件中的参数
5.校验
子组件在接收父组件传入数据时, 可以进行props校验,来确保数据的格式和是否必传。可以指定一下属性:
- type: 指定数据类型 String Number Object …注意不能使用字符串数组,只能是对象大写形式
- required: 指定是否必输
- default: 给默认值或者自定义函数返回默认值
- validator: 自定义函数校验
非props属性
引用子组件时,非定义的props属性,自动合并到子组件上,class和style也会自动合并。
<div id="app">
<!--使用组件-->
<my-hello class="item" style="font-size: 30px;color:pink;" ></my-hello>
</div>
6.非props属性
子组件在接收父组件传入数据时, 可以进行 props 校验,来确保数据的格式和是否必
传。可以指定一下属性:
-
type: 指定数据类型 String Number Object …注意不能使用字符串数组,
只能是对象大写形式 -
required: 指定是否必输
-
default: 给默认值或者自定义函数返回默认值
-
validator: 自定义函数校验
<html> <head> <meta charset="UTF-8"> <title>props属性</title> <script type="text/javascript" src="../js/vue.js" ></script> </head> <body> <div id="app"> <!--使用组件--> <my-hello :txt1="msg" :txt2="txt" :txt3="msg2" :txt5="money"></my-hello> </div> </body> <script type="text/javascript"> /*定义组件需要在实例化vue之前*/ Vue.component("my-hello",{ // 声明父组件传递过来的参数 // props:["txt1","txt2"], // 数组不能做校验 // 对象可以做校验 props:{ // 基础类型检测 (`null` 指允许任何类型) txt1:[String, Number], // 可以支持多个 txt2:String, // 必传且是字符串 txt3:{ required:true, type:String }, // 数值且有默认值 txt4:{ type:Number, default: 100 }, // 自定义验证函数 txt5:{ validator:function(value){ return value > 10; } } }, template:"<div>{{txt1}}:{{txt2}}---{{txt3}}---{{txt4}}----{{txt5}}</div>" }); new Vue({ el:"#app", data:{ msg:"来自系统的消息", txt:"Hello Vue!", msg2:"Admin", num:10, money:19 } }); </script>
7.自定义事件
父组件给子组件传值使用props属性, 那么需要子组件更新父组件时,要使用自定义事件
o
n
和
on和
on和emit:
KaTeX parse error: Unexpected character: '' at position 48: …)或者-(a-b-c) ̲emit主动触发:
e
m
i
t
(
事
件
名
,
传
入
参
数
)
主
动
挂
载
自
定
义
事
件
不
仅
可
以
绑
定
在
子
组
件
,
也
可
以
直
接
挂
载
到
父
组
件
,
使
用
emit(事件名,传入参数) 主动挂载 自定义事件不仅可以绑定在子组件,也可以直接挂载到父组件,使用
emit(事件名,传入参数)主动挂载自定义事件不仅可以绑定在子组件,也可以直接挂载到父组件,使用on绑定和$emit触发。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自定义事件</title>
<script type="text/javascript" src="../js/vue.js" ></script>
</head>
<body>
<div id="app">
<my-hello v-on:update-count="changecount()"></my-hello>
{{count}}
</div>
</body>
<script type="text/javascript">
Vue.component("my-hello",{
template:"<button v-on:click='update'>子组件Child</button>",
methods:{
update:function(){
console.log("点击...");
this.$emit("update-count","自定义事件");
}
}
});
var app = new Vue({
el:"#app",
data:{
count:0
},
methods:{
changecount:function(){
this.count++;
}
}
});
// 主动挂载自定义事件
app.$on("update-count",function(value){
console.log(value);
this.count++;
});
// 触发自定义事件
app.$emit("update-count","这是自定义事件");
</script>
</html>
二、插槽分发
1.slot插槽
1)子组件插槽
<template id="child-template">
<div>
<div>我是子组件</div>
<div>{{msg}}</div>
<slot>我是默认内容,父组件不传入时我显示</slot>
</div>
</template>
Vue.component('child', {
template:'#child-template',
props:['msg']
});
2)父组件插槽
<div id="app">
<child :msg="msgText">
<h4>父组件模板</h4>
<h5>模板混入....</h5>
</child>
</div>
<template id="child-template">
<div>
<div>我是子组件</div>
<div>{{msg}}</div>
<slot>我是默认内容,父组件不传入时我显示</slot>
</div>
</template>
2.具名插槽
具名插槽slot, 就是给插槽起个名字。
在子组件定时可以定定义多个插槽,同时通过name属性指定一个名字,如:,父组件引用时使用< slot=‘header’>进行插槽选择。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>slot插槽</title>
<script type="text/javascript" src="../js/vue.js" ></script>
</head>
<body>
<div id="app">
<!--<my-hello></my-hello>-->
<my-hello>
<h3 slot="header">你好</h3>
<p slot="footer">这是p元素</p>
</my-hello>
</div>
<!--使用template标签-->
<template id="tpl1">
<div>
<slot name="header">如果没有传递数据,默认显示这段文本</slot>
<div>--------------------</div>
<!--插槽,占位-->
<slot name="footer">如果没有传递数据,默认显示这段文本</slot>
</div>
</template>
2.插槽作用域 作用域插槽slot-scope, 父组件通过插槽混入父组件的内容, 子组件也可以通过slot作用域向插槽slot内部传入数据,使用方式:, 父组件通过进行引用。
你好----{{props.msg}}----{{props.txt}}
<!--使用template标签-->
<template id="tpl1">
<div>
<div>--------------------</div>
<!--插槽,占位-->
<slot msg="你好啊" txt="Hello">如果没有传递数据,默认显示这段文本</slot>
</div>
</template>
</body>
<script type="text/javascript">
// 自定义组件
Vue.component("my-hello",{
template:"#tpl1",
});
var app = new Vue({
el:"#app"
});
</script>
</html>
三、动态组件
使用标签的is属性,动态绑定多个组件到一个挂载点,通过改变is绑定值,切换组件。
1.使用方式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动态组件</title>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<!--3、指定导航-->
/ <a href='#' @click.prevent="page='index'">首页</a>
/ <a href='#' @click.prevent="page='news'">新闻</a>
/ <a href='#' @click.prevent="page='login'">登陆</a>
<!--2、使用component引用-->
<component :is="page"> </component>
</div>
</body>
<script type="text/javascript">
// 1、定义组件
Vue.component('index', {
template:'<h5>首页</h5>'
});
Vue.component('news', {
template:'<h5>新闻页</h5>'
});
Vue.component('login', {
template:'<h5>登陆页</h5>'
});
new Vue({
el:"#app",
data:{
page:'index'
}
});
</script>
</html>
2.keep-alive
如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。为此可以添加一个 keep-alive 指令。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动态组件</title>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<!--3、指定导航-->
/ <a href='#' @click.prevent="page='index'">首页</a>
/ <a href='#' @click.prevent="page='news'">新闻</a>
/ <a href='#' @click.prevent="page='login'">登陆</a>
<!--2、使用component引用-->
<keep-alive>
<component :is="page"></component>
</keep-alive>
</div>
</body>
<script type="text/javascript">
// 1、定义组件
Vue.component('index', {
template:'<h5>首页</h5>',
// 当组件挂载时,触发(钩子函数)
mounted: function () {
console.log('挂载...首页');
}
});
Vue.component('news', {
template:'<h5>新闻页</h5>',
mounted: function () {
console.log('挂载...新闻页');
}
});
Vue.component('login', {
template:'<h5>登陆页</h5>',
mounted: function () {
console.log('挂载...登陆页');
}
});
new Vue({
el:"#app",
data:{
page:'index'
}
});
</script>
</html>
3.refs属性
使用ref 给每个组件起一个固定的名字,方便后续直接引用操作,在父组件中使用$refs访问子组件。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动态组件</title>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<index ref="ind"></index>
</div>
</body>
<script type="text/javascript">
// 1、定义组件
Vue.component('index', {
template:'<div>{{count}}</div>',
data:function(){
return {count:0};
}
});
var app = new Vue({
el:"#app",
});
// 通过refs属性得到指定的自定义组件,修改对应的组件中的值
app.$refs.ind.count=10;
</script>
</html>
四、数据处理
1.watch属性
在 Vue 组件中,使用 watch 属性来监听数据的变化,同时可以指定监听那个属性。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>watch属性</title>
<script type="text/javascript" src="../js/vue.js" ></script>
</head>
<body>
<div id="app">
<p>
firstName:
<input type="text" :value="firstName" @input="changeFirstName($event)">
</p>
<p>
lastName:
<input type="text" :value="lastName" @input="changeLastName($event)" >
</p>
<h4>{{fullName}}</h4>
</div>
</body>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
firstName:"Hello",
lastName:"Kitty",
fullName:"Hello Kitty"
},
methods:{
changeFirstName:function(e){
console.log(e.target.value);
this.firstName = e.target.value;
},
changeLastName:function(e){
this.lastName = e.target.value;
}
},
watch:{
firstName:function(newValue,oldValue){
this.fullName = newValue + " " + this.lastName;
},
lastName:function(newValue,oldValue){
this.fullName = this.firstName + " " + newValue;
}
}
});
</script>
</html>
2.
s
w
t
c
h
除
了
在
组
件
内
部
使
用
w
a
t
c
h
也
可
以
使
用
内
部
命
令
swtch 除了在组件内部使用 watch 也可以使用内部命令
swtch除了在组件内部使用watch也可以使用内部命令watch 进行属性监听。
$watch第一个参数是需要监听的属性,第二个是回调函数用法和watch一样。需要取消监听只需拿到监听对象的引用,这个引用是返回一个函数对象,执行该对象就可以取消监听。
同时监听多个属性,可以不指定属性:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>watch属性</title>
<script type="text/javascript" src="../js/vue.js" ></script>
</head>
<body>
<div id="app">
{{firstName}} {{lastName}}
</div>
</body>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
firstName:"Hello",
lastName:"Kitty"
}
});
// 监听指定属性
/*app.$watch("firstName",function(newVal,oldVal){
console.log(newVal,oldVal);
});*/
// 监听所有属性
app.$watch(function(){
return this.firstName + " " + this.lastName;
},function(newVal,oldVal){
console.log(newVal,oldVal);
});
</script>
</html>
3.Computed属性
computed计算属性用于定义比较复杂的属性计算
computed和methods区别:
计算属性使用computed定义, 方法使用methods定义
计算属性使用时不加括号执行符
计算属性是基于它们的依赖进行缓存的,计算属性只有在它的相关依赖发生改变时才会重新求值。否则返回之前计算好的值,性能更高!
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>computed属性</title>
<script type="text/javascript" src="../js/vue.js" ></script>
</head>
<body>
<div id="app">
<p>
firstName:
<input type="text" v-model="firstName">
</p>
<p>
lastName:
<input type="text" v-model="lastName" >
</p>
<h4>{{fullName}}</h4>
</div>
</body>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
firstName:"Hello",
lastName:"Kitty"
},
computed:{
fullName:function(){
return this.firstName + " " +this.lastName;
}
}
});
</script>
</html>
4.getter和setter
在 computed 中,同样可以指定 setter 进行数据更新。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>getter和setter</title>
<script type="text/javascript" src="../js/vue.js" ></script>
</head>
<body>
<div id="app">
<p>
fullName:
<input type="text" v-model="fullName">
</p>
<h4>firstName:{{firstName}}</h4>
<h4>lastName:{{lastName}}</h4>
</div>
</body>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
firstName:"Hello",
lastName:"Kitty"
},
computed:{
fullName:{
// getter 得到fullName的值
get:function(){
return this.firstName + " " + this.lastName;
},
set:function(val){
var arr = val.split(" ");
this.firstName = arr[0];
this.lastName = arr[1];
}
}
}
});
</script>
</html>
五、生命周期
每个 Vue 实例在被创建之前都要经过一系列的初始化过程。例如需要设置数据监听、
编译模板、挂载实例到 DOM、在数据变化时更新 DOM 等。同时在这个过程中也会运行一
些叫做生命周期钩子的函数,给予用户机会在一些特定的场景下添加他们自己的代码。
比如 created 钩子可以用来在一个实例被创建之后执行代码;
常用的生命周期钩子函数有:
-
created: 实例创建完成后被立即调用
-
mounted: 实例挂载完成后被立即调用
-
beforeUpdate: 实例需要渲染之前调用
-
updated: 实例更新后调用
-
destroyed: Vue 实例销毁后调用
getter和setter
六、自定义指令
1.自定义指令
全局指令:v-focus
局部指令:使用directive定义,第一个参数为指令名,使用时加上v-前缀才能生效。
inserted属性指当绑定元素插入到DOM时调用。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自定义指令</title>
<script type="text/javascript" src="../js/vue.js" ></script>
</head>
<body>
<div id="root">
<input type="text" v-focus />
<input type="text" v-focus2 />
</div>
</body>
<script>
//自定义全局指令v-focus
Vue.directive('focus',{
//当绑定元素插入到DOM调用
inserted: function (el) {
//元素获取焦点
el.focus();
}
});
var vm = new Vue({
el:'#root',
directives:{
focus2:{
inserted: function (el) {
//元素获取焦点
el.focus();
}
}
}
});
</script>
</html>
2.钩子函数
钩子函数的参数有三个:
1)el:当前指令绑定元素
2)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
钩子中可用。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自定义指令</title>
<script type="text/javascript" src="../js/vue.js" ></script>
</head>
<body>
<div id="root">
<input type="text" v-demo:str.a.ab="1+1"/>
</div>
</body>
<script>
//自定义全局指令v-focus
Vue.directive('demo',{
bind: function (el,binding) {
console.log(el);
console.log(binding);
}
});
var vm = new Vue({
el:'#root'
});
</script>
</html>
3.图片懒加载
在图片未完成加载前,用随机的背景色占位,图片加载
完成后才直接渲染出来,用自定义指令可以非常方便的实现这个功能。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自定义指令</title>
<script type="text/javascript" src="../js/vue.js" ></script>
<style>
.item, .item img{
width: 200px;
height: 120px;
float: left;
}
</style>
</head>
<body>
<div id="root">
<div class="item" v-for="img in imgs" v-img="img.url"></div>
</div>
</body>
<script>
//定义全局自定义指令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);
}
});
var vm = new Vue({
el:'#root',
data:{
//定义模拟数据
imgs:[
{url:'../img/01.jpg'},
{url:'../img/02.jpg'},
{url:'../img/03.jpg'},
{url:'../img/04.jpg'}
]
}
});
</script>
</html>
七、过滤器
八、Vue允许自定义过滤器,可被用作一些常见的文本格式化。
过滤器可以用在两个地方:mustache 插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。
过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>过滤器</title>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
{{msg | uppercase | length}}
<br />
{{msg | test("<--","--<")}}
</div>
</body>
<script type="text/javascript">
// 全局过滤器
Vue.filter("uppercase",function(val){
return val.toUpperCase();
});
var app = new Vue({
el:"#app",
data:{
msg:"hello"
},
// 定义局部过滤器
filters:{
length:function(val){
return val + " " + val.length;
},
test:function(val,a,b){
return a + val + b;
}
}
});
</script>
</html>