Vue4
vue什么vue?它是一套用于构建用户界面的渐进式框架,采用MVVM思想,Vue 的核心库只关注视图层,Vue也完全能够为复杂的单页应用提供驱动。安装vue下载地址起步<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="view...
vue
什么vue?
它是一套用于构建用户界面的渐进式框架,采用MVVM
思想,Vue
的核心库只关注视图层,Vue
也完全能够为复杂的单页应用提供驱动。
安装vue
起步
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>起步</title>
<script src="js/vue.js"></script>
</head>
<body >
<div id="app">
{{1+2*4}}
</div>
<script>
var app = new Vue({
el:'#app'
})
</script>
</body>
</html>
实例
创建根实例
var app = new Vue({
el: '#app',
data: {
}
})
el
:目标容器对象data
:初始化数据,里面存在一些变量,这些变量是被监测,并且可以响应的。
初始化一些数据
var app = new Vue({
el:'#app',
data: {
show: false,
price: 60,
msg: '文本',
arr: ['首页','关于','联系'],
obj: {
name: '张三',
age: 20
},
bool: true
},
})
也可以使用以下方式初始化一个根实例(new Vue
)
<div id="app"></div>
<script>
var app = new Vue({
template: `
<div>
<h1>{{msg}}</h1>
</div>
`,
data: {
msg: '星期一'
}
}).$mount('#app');
生命周期钩子函数
var app = new Vue({
el:'#app',
data: {
name: '张三'
},
beforeCreate(){
console.log('创建之前');
},
created(){
console.log('创建之后');
},
beforeMount(){
console.log('挂载之前');
},
mounted(){
console.log('挂载之后');
},
beforeUpdate(){
console.log('更新之前');
},
updated(){
console.log('更新之后');
},
beforeDestroy(){
console.log('销毁之前');
},
destroyed(){
console.log('销毁之后');
}
})
一打开页面就能执行的生命周期有那些?
beforeCreate
创建之前
创建之前不能获取data
中的变量值,这样我们可以让loading
显示或者检测页面授权。
created
创建之后
创建之后可以获取data中的变量,因此我们可以在这里发送http请求接口,从后端拿到数据,然后同步到页面中去。
var app = new Vue({
el:'#app',
data: {
list: []
},
created(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () =>{
if(xhr.readyState==4 && xhr.status==200){
var info = JSON.parse(xhr.responseText);
this.list = info;
}
}
xhr.open('GET','http://localhost:8282/list');
xhr.send();
console.log('创建之后', this.name);
}
})
beforeMount
挂载之前
挂载之前,模板中的插值{{name}}
或者一些指令v-for
、v-text
等还没有被解析出来(替换),所以如果生成的是一个html代码,那么你无法获取这个dom对象。
mounted
挂载之后
挂载之后,如果你的节点是动态添加的,那么你至少要在挂载之后才能获取的到。所以此钩子通常用于dom操作
模版语法
v-text
:相当于{{}}
另一种写法,可以防止因为网速慢,加载会有闪烁情况。v-once
:执行一次性绑定,接下来不再响应数据v-html
:可以让插值处输出html
代码,注意此名称存在一定的风险,比如XSS
攻击v-bind
:动态绑定html
特性(比如: class、style、id、checked),特别注意:大胡子语法不能用于html特性上v-on
:动态绑定事件{{}}
:插值,可以进行运算,但是注意每个绑定都只能包含单个表达式,还要小心造成数据更新死循环v-for
: 循环
布尔特性,它们的存在即暗示为true
,有那些默认为假?
- 数字
0
- 空字符串
''
null
NaN
undefined
false
修饰符
修饰符 (Modifiers) 是以半角句号. 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
stop
:阻止冒泡prevent
:阻止默认动作
<div id="app" >
<p v-on:click="fn">
<a href="http://www.163.com" v-on:click.stop.prevent="subfn">单击</a>
</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
msg: '文本'
},
methods: {
fn(){
console.log( 'p',this.msg );
},
subfn(){
console.log( 'a',this.msg );
}
}
});
</script>
计算属性和侦听器
计算属性
var app = new Vue({
el:'#app',
data: {
xing: '张',
ming: '三'
},
computed:{
getName(){
return this.xing + this.ming;
}
}
})
计算属性和方法有什么区别?
- 计算属性调用不需要括号(立即执行函数),方法需要括号
- 计算属性只是引用值,无法进行参数传递,方法可以传参
- 计算属性会缓存值,方法不会缓存值
- 当需要在数据变化时执行异步或开销较大时应该使用计算属性
- 当需要的数据是实时变化的,那么请使用方法
哪个生命周期最早可以获取计算属性和方法?
答:created()
钩子函数
计算属性和侦听器有什么区别?
- 计算属性需要返回值,并且会缓存
- 侦听器不需要返回值,并且可以的得到上一个值和最新值
- 侦听器支持深度监听,而计算属性不可以
<div id="app" >
<input v-model.lazy="val" type="text"> <br>
{{val}}
</div>
<script>
//计算属性和方法有什么区别?
var app = new Vue({
el:'#app',
data: {
min: 1,
max: 20,
val: 1
},
watch: {
val( now, old ){
if( isNaN(now) || now < this.min || now > this.max){
this.val = old || 1;
}
}
}
})
</script>
计算属性默认情况下只要getter
(取值),如果想要设置值(setter
),代码如下:
<div id="app" >
{{age}}
{{xueli}}
</div>
<script>
//计算属性和方法有什么区别?
var app = new Vue({
el:'#app',
computed:{
age(){
return 20;
},
xueli: {
get(){
return '本科';
},
set(val){
console.log( val );
}
}
}
})
</script>
注意watch
默认是浅侦听,如果需要深度监听则需要加上deep:true
参数
<div id="app" >
<input v-model="age" type="text" placeholder="年龄">
{{age}} <br><br>
<input v-model="info.xueli" type="text" placeholder="学历">
{{info.xueli}}
</div>
<script>
//计算属性和方法有什么区别?
var app = new Vue({
el:'#app',
data: {
age: 20,
info: {
xueli: '本科'
}
},
watch: {
age( now, old ){
console.log( '年龄',now );
},
info: {
handler(now, old) {
console.log( '信息', now );
},
immediate: true, //true立即执行,false发生改变后执行
deep: true //深度监听
}
}
})
</script>
Class 与 Style 绑定
绑定class
对象语法
<div v-bind:class="{类名:布尔特性}"> </div>
例如
<div id="app" >
<button class="btn" v-bind:class="btnClass">按钮</button>
<button v-on:click="primary=!primary">切换</button>
</div>
<script>
var app = new Vue({
el:'#app',
data:{
primary: false,
success: false
},
computed:{
btnClass(){
return {
primary: this.primary,
success: this.success
}
}
}
})
</script>
数组语法
我们可以把一个数组传给 v-bind:class
,以应用一个 class
列表
<div v-bind:class="[activeClass, errorClass]"></div>
绑定style
对象语法
<div v-bind:style="{属性:值}"> </div>
例如:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
示例:vue
拖拽效果
<style>
#box{
position: fixed;
background-color: red;
width: 300px;
height: 200px;
left: 150px;
}
</style>
<div id="app">
<div
id="box"
:style="boxStyle"
v-on:mousedown = "mousedown"
></div>
</div>
<script>
//计算属性和方法有什么区别?
var app = new Vue({
el:'#app',
data:{
left: 20,
top: 20,
width: 100,
height: 100
},
created(){
var box = document.getElementById('box');
this.left = box.offsetLeft || this.left;
this.top = box.offsetTop || this.top;
this.width = box.offsetWidth || this.width;
this.height = box.offsetHeight || this.height;
},
computed:{
boxStyle(){
return {
left: this.left+'px',
top: this.top+'px',
width: this.width+'px',
height: this.height+'px'
}
}
},
methods: {
mousedown(e){
var startX = e.clientX;
var startY = e.clientY;
var startLeft = this.left;
var startTop = this.top;
var maxLeft = window.innerWidth - this.width;
var maxTop = window.innerHeight - this.height;
document.onmousemove = e => {
var endX = e.clientX;
var endY = e.clientY;
var distX = endX - startX;
var distY = endY - startY;
var left = startLeft + distX;
var top = startTop + distY;
if(left <=0) left =0;
if(top <=0) top =0;
if(left >=maxLeft) left =maxLeft;
if(top >=maxTop) top =maxTop;
this.left = left;
this.top = top;
}
document.onmouseup = function(){
document.onmousemove = null;
document.onmouseup = null;
}
}
}
})
</script>
数组语法
注意:数组是有序的集合,后面的对象覆盖前面的对象
<div v-bind:style="[baseStyles, overridingStyles]"></div>
例如
<div id="app">
<div :style="[baseStyles, overridingStyles]"></div>
</div>
<script>
var app = new Vue({
el:'#app',
data:{
baseStyles: {
color: 'red',
fontSize: '26px'
},
overridingStyles: {
color: 'green',
'line-height': 3
}
}
})
</script>
条件渲染
v-if
在 Vue
中,我们使用 v-if
指令实现同样的功能:
它惰性解析,只有条件为true
,才会创建节点,重建事件监听,条件为false
,则什么也不错。
<h1 v-if="true">Yes</h1>
<h1 v-if="1>2">Yes</h1>
v-else
否则
<h1 v-if="1 > 2"> 1大于2 </h1>
<h1 v-else> 1小于2 </h1>
v-else-if
多条件
<div id="app">
<p v-if="score < 60">不及格</p>
<p v-else-if="score >= 60 && score < 80">良好</p>
<p v-else-if="score >= 80 && score < 90">优秀</p>
<p v-else>极好</p>
</div>
<script>
var app = new Vue({
el:'#app',
data: {
score: 100
}
})
</script>
注意:
v-else
元素必须紧跟在带v-if
或者v-else-if
的元素的后面,否则它将不会被识别。
template
template
模板标签不会被解析出来,这样就不用被迫额外加一个标签。
<div id="app">
<template v-if="show">
你好
</template>
</div>
<script>
var app = new Vue({
el:'#app',
data: {
show: true
}
})
</script>
key的意义
Vue
会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做使 Vue 变得非常快。
但这样也不总是符合实际需求,所以 Vue
为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们,那就是定义key
。
<div id="app">
<h1>登录方式</h1>
<button v-on:click="type = 'email'">邮箱</button>
<button v-on:click="type = 'mobile'">手机</button> <br><br>
<input v-if="type=='email'" type="email" placeholder="请使用邮箱登录" key="email">
<input v-else type="text" placeholder="请使用手机登录" key="mobile">
</div>
<script>
var app = new Vue({
el:'#app',
data: {
type: 'email'
}
})
</script>
v-show
另一个用于根据条件展示元素的选项是 v-show
指令。用法大致一样:
实际上就是控制style.display
的值
<h1 v-show="ok">显示</h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM
中。v-show
只是简单地切换元素的 CSS
属性 display
。
v-show
不支持<template>
元素,也不支持v-else
v-if 和 v-show 的区别
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if
有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
v-if和v-for一起使用
当 v-if
与 v-for
一起使用时,v-for
具有比 v-if
更高的优先级。
<div id="app">
<ul>
<template v-if="arr.length">
<li v-for="item in arr">
{{item}}
</li>
</template>
<li v-else>
抱歉,暂时没有数据
</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
arr:[]
}
})
</script>
列表渲染
v-for 数组
<div id="app">
<button
v-for="p in total"
:class="{active: p==page}"
v-on:click="goPage(p)"
>{{p}}</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
page: 5,
total: 10
},
methods:{
goPage(p){
this.page = p;
}
}
})
</script>
v-for 对象
<div id="app">
<p v-for="( val, key, index ) in person">
{{index}} -- {{key}} -- {{val}}
</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
person: {
name: '张三',
age: 20
}
}
})
</script>
按指定的字段排序
<div id="app">
<h1>{{flag}}</h1>
<button v-on:click="orderBy">按价钱排序</button>
<ul>
<li v-for="item in news">
{{item.title}} ---- {{item.price}}
</li>
</ul>
</div>
<script>
var news = [
{ id:1, title:'标题1', price: 10 },
{ id:2, title:'标题2', price: 30 },
{ id:3, title:'标题3', price: 25 },
{ id:4, title:'标题4', price: 32 },
{ id:5, title:'标题5', price: 40 }
];
var app = new Vue({
el: '#app',
data: {
flag: 'def',
news: [...news],
onews: [...news]
},
methods: {
orderBy(){
if(this.flag=='def'){
this.flag = 'asc';
this.news.sort(function( a, b ){
return a.price - b.price;
})
}else if(this.flag=='asc'){
this.flag = 'desc';
this.news.sort(function( a, b ){
return b.price - a.price;
})
}else if(this.flag=='desc'){
this.flag = 'def';
this.news = [...this.onews];
}
}
}
})
</script>
数组更新检测
数组变异方法(破坏原始数组)
pop
删除末尾成员shift
删除首个成员push
向数组末尾追加成员unshift
向数组开头追加成员reverse
反转数组sort
数组排序splice
集修改删除添加一体的数组操作
数组非变异方法(产生新数组,不破坏原始数组)
concat
连接多个数组slice
分割数组map
数组映射filter
数组过滤reduce
数组叠加
注意事项
由于 JavaScript
的限制,Vue
不能检测以下变动的数组:
- 当你利用索引直接设置一个项时,例如:
vm.items[1] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = 4
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
针对上面的问题我们可以使用以下方式解决
// Vue.set
Vue.set(要响应的数组, 数组索引值, 更新的值)
也可以使用
// Array.prototype.splice
要响应的数组.splice(数组索引值, 成员个数, 更新的值)
使用vue
数据分页和删除
<style>
.active{
background-color: red;
}
</style>
<div id="app">
<input type="search" placeholder="搜索" v-model="keyword">
<ul>
<li v-if="!pnews.length">抱歉,没有搜索到数据!</li>
<li v-else v-for="(item,index) in pnews">
{{item.title}} <button v-on:click="delItem(item.id)">删除</button>
</li>
</ul>
<button
v-for="p in totalpage"
v-bind:class="{active: p==page }"
v-on:click="goPage(p)"
>{{p}}</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
keyword: '',
page: 1,
perpage: 2,
news: [
{ id:1, title:'标题1', price: 10 },
{ id:2, title:'标题2', price: 30 },
{ id:3, title:'标题1', price: 25 },
{ id:4, title:'标题4', price: 32 },
{ id:5, title:'标题5', price: 40 },
{ id:6, title:'标题1', price: 24 },
{ id:7, title:'标题7', price: 36 }
]
},
computed: {
total(){
return this.search.length;
},
totalpage(){
return Math.ceil( this.total / this.perpage );
},
search(){
return this.news.filter( item => {
return item.title.indexOf(this.keyword) != -1;
})
},
pnews(){
var start = (this.page - 1) * this.perpage;
var end = start + this.perpage;
return this.search.slice( start, end);
}
},
methods: {
goPage( p ){
this.page = p;
},
delItem( id ){
if(confirm('您确定要删除此行信息吗?')){
this.news = this.news.filter( item =>{
return item.id != id;
})
//防止因为整页数据删除完,页码不同步
if( this.page > this.totalpage ){
this.page -= 1;
}
}
}
}
})
</script>
v-for 和 template
<template>
不会被解析出来
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider"></li>
</template>
</ul>
事件处理
<div id="app">
<button v-on:click="alert($event,'张三','李四')">{{count}}</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
count: 0
},
methods: {
alert( event, str1,str2 ){
console.log(event, str1, str2 )
this.count += 1;
}
}
})
</script>
.capture
将事件改为捕获模式?
<ul v-on:click.capture="alert('ul')">
<li v-on:click.capture="alert('li')">
<button v-on:click="alert('btn')">按钮</button>
</li>
</ul>
.self
只有单击到绑定的元素对象才能触发,冒泡过来的事件不会触发。
<ul v-on:click.self="alert('ul')">
<li>
<button >按钮</button>
</li>
</ul>
事件修饰符
鼠标修饰符
left
:左键,默认middle
:中键,滚轮right
: 右键
<button v-on:click.middle="count += 1">{{count}}</button>
键盘修饰符
.enter
:回车键.tab
:换行键.delete
:退格键.esc
:取消键.space
:空格键.up
:方向键上.down
:方向键下.left
:方向键左.right
:方向键右
表单输入绑定
v-model双向绑定,不过是下面的代码的语法糖
<div id="app">
<input type="text" v-bind:value="name" v-on:input="update">
{{name}}
</div>
<script>
var app = new Vue({
el:'#app',
data: {
name: '张三'
},
methods: {
update(e){
this.name = e.target.value;
}
}
})
</script>
单行文本框、多行文本框、单选下拉列表框
<div id="app">
<input v-model="form.username" type="text"> <br><br>
<select v-model="form.xueli">
<option value="">请选择</option>
<option value="本科">本科</option>
<option value="大专">大专</option>
</select> <br><br>
<textarea v-model="form.msg"></textarea>
<button v-on:click="submit()">提交</button>
</div>
<script>
var app = new Vue({
el:'#app',
data: {
form: {
username: '张三',
xueli: '大专',
msg: '没有任何信息'
}
},
methods: {
submit(){
console.log(this.form )
}
}
})
</script>
单选框、单选复选框、复选框、多选下拉列表框
<div id="app">
<input type="radio" value="男" v-model="form.sex"> 男
<input type="radio" value="女" v-model="form.sex"> 女 <br><br>
<input type="checkbox" v-model="form.check" true-value="1" false-value="0"> 审核 <br><br>
<input type="checkbox" value="篮球" v-model="form.habby"> 篮球
<input type="checkbox" value="足球" v-model="form.habby"> 足球
<input type="checkbox" value="排球" v-model="form.habby"> 排球 <br><br>
<select v-model="form.skill" multiple>
<option value="">请选择</option>
<option value="武术">武术</option>
<option value="跳舞">跳舞</option>
<option value="编程">编程</option>
</select> <br><br>
<button v-on:click="submit()">提交</button>
</div>
<script>
var app = new Vue({
el:'#app',
data: {
form: {
sex: '女',
check: true,
habby: ['篮球','排球'],
skill: ['武术','编程']
}
},
methods: {
submit(){
console.log(this.form )
}
}
})
</script>
值绑定
<div id="app">
<input type="text" v-bind:value="form.username"> <br><br>
<textarea v-bind:value="form.msg"></textarea> <br>
<select>
<option value="">请选择</option>
<option v-bind:value="item.value" v-for="item in form.xueli">{{item.label}}</option>
</select>
</div>
<script>
var app = new Vue({
el:'#app',
data: {
form: {
username: '张三',
msg: '个人说明',
xueli: [
{label:'本科',value:'benke'},
{label:'大专',value:'dazhuan'},
]
}
}
})
</script>
单选框的值绑定
<div id="app">
<template v-for="item in form.gender">
<input
type="radio"
v-model="form.sex"
v-bind:value="item.value"
> {{item.label}}
</template>
</div>
<script>
var app = new Vue({
el:'#app',
data: {
form: {
sex: 'women',
gender: [
{label:'男',value:'men'},
{label:'女',value:'women'}
]
}
}
})
</script>
复选框绑定值
<div id="app">
<template v-for="item in form.hobbyOptions">
<input
type="checkbox"
v-model="form.hobby"
v-bind:value="item.value"
> {{item.label}}
</template>
<br> <br>
{{form.hobby}}
</div>
<script>
var app = new Vue({
el:'#app',
data: {
form: {
hobby: ['篮球'],
hobbyOptions: [
{label:'篮球',value:'篮球'},
{label:'足球',value:'足球'},
{label:'排球',value:'排球'}
]
}
}
})
</script>
v-model的修饰符
.number
:转换为数字.trim
:去除首尾空格.lazy
:默认input
事件改为change
事件
组件系统
组件是构建web
系统界面中的最小单元。
组件类型
- 原生组件:
<button>
- 自定义组件:
<gx-button>
自定义组件类型
- 全局组件
- 局部组件
全局组件
怎么创建一个全局组件?
<div id="app">
<gx-count></gx-count>
<gx-count></gx-count>
</div>
<script>
Vue.component('gx-count',{
data: function(){
return {
total: 0
};
},
template:`<button @click="total += 1">{{total}}</button>`
})
var app = new Vue({
el:'#app'
})
</script>
每个子组件有自己独立的作用域,数据不共享。
注意:组件内部的data
属性值一定要是一个函数,并且这个函数返回一个对象
注意:组件内部的模板template
,必须要有一个根元素,并且这个根元素不能为template
。
props 向组件内部传参
从父作用域向组件内部传参,通过组件内部的props
属性注册
<div id="app">
<gx-page :page="1"></gx-page>
</div>
<script>
Vue.component('gx-page',{
props: ['page']
})
</script>
props
注意事项
- 从父作用域传进子组件内部的属性(变量),你可以读取,但是不要设置它的值。否则会引起数据流混乱。你应该在
data
中或者在computed
拷贝复制一份。 - 你通过props传进来的属性不能和本地
data
或者computed
中的变量重名
示例
<div id="app">
<gx-page :page="1" :totalpage="5"></gx-page>
</div>
<script>
Vue.component('gx-page',{
props: ['page','total','totalpage','perpage'],
data(){
return {
page_: this.page || 1,
perpage_: this.perpage || 10,
disabled: false
}
},
computed: {
totalpage_(){
return this.totalpage || Math.ceil(this.total/this.perpage_);
}
},
template:`
<ul class="gxpage">
<li
v-for="p in totalpage_"
:class="{ active: p == page_, disabled }"
@click="goPage(p)"
>{{p}}</li>
</ul>
`,
methods: {
goPage(p){
if(this.disabled)return;
this.page_ = p;
}
}
})
var app = new Vue({
el:'#app'
})
</script>
emit 子组件向父组件发送消息
emit
其实利用js冒泡的原理才实现
<div id="app">
{{page}}
<gx-page :page="page" @change="change"></gx-page>
</div>
<script>
Vue.component('gx-page', {
data(){
return {
page_: this.page || 1
}
},
template: `
<ul class="gxpage">
<li
v-for="p in totalpage_"
:class="{ active: p == page_ }"
@click="goPage(p)"
>{{p}}</li>
</ul>
`,
methods: {
goPage(p){
this.page_ = p;
this.$emit( 'change', p );
}
}
})
var app = new Vue({
el:'#app',
data: {
page: 1
}
methods: {
change(p){
this.page = p;
}
}
})
sync修饰符
不使用sync
的写法
<div id="app">
{{page}}
<gx-page :page="page" @update:page="page=$event"></gx-page>
</div>
<script>
Vue.component('gx-page', {
data(){
return {
page_: this.page || 1
}
},
template: `
<ul class="gxpage">
<li
v-for="p in totalpage_"
:class="{ active: p == page_ }"
@click="goPage(p)"
>{{p}}</li>
</ul>
`,
methods: {
goPage(p){
this.page_ = p;
this.$emit( 'update:page', p );
}
}
})
var app = new Vue({
el:'#app',
data: {
page: 1
}
})
使用sync
的写法,可以看到节省了 @update.page
<div id="app">
{{page}}
<gx-page :page.sync="page"></gx-page>
</div>
<script>
Vue.component('gx-page', {
data(){
return {
page_: this.page || 1
}
},
template: `
<ul class="gxpage">
<li
v-for="p in totalpage_"
:class="{ active: p == page_ }"
@click="goPage(p)"
>{{p}}</li>
</ul>
`,
methods: {
goPage(p){
this.page_ = p;
this.$emit( 'update:page', p );
}
}
})
var app = new Vue({
el:'#app',
data: {
page: 1
}
})
props属性验证
组件中使用props
数组形式在一些简单功能还好,但是这种方式以下场景存在不足:
- 不能明确属性的类型
type
- 没有必填选项
required
- 没有默认值选项
default
- 没有校验选项
validator
{
props: ['page','perpage']
}
在开发一些功能强大的组件props
应该使用对象的形式:
Vue.component('gx-list',{
props: {
page: {
type: Number,
default: 1
},
perpage: {
type: Number,
default: 10
},
totalpage: {
type: Number
},
total: {
type: Number
}
},
template: `
<div>验证</div>
`
})
非props属性
组件之插槽
匿名插槽(默认插槽)
匿名插槽支持多个,但是多个会被重复匹配
<slot></slot>
<slot></slot>
插槽都是支持默认值
<slot>默认</slot>
<div id="app">
<gx-button>
<img src="images/4.png" width="10" height="20">
按钮
</gx-button>
<gx-button label="我是朴素按钮"/>
</div>
<script>
Vue.component('gx-button', {
props: ['label'],
template: `
<div>
<button>
<slot>{{label}}</slot>
</button>
</div>
`
})
var app = new Vue({
el:'#app',
data:{
msg: ''
}
})
</script>
命名插槽
顾名思义,就给插槽去一个名字
在组件内部
{
template: `
<div>
<slot name="header">
命名插槽
</slot>
<slot>
默认插槽
</slot>
<slot name="header">
命名插槽
</slot>
</div>
`
}
父组件调用
<div id="app">
<gx-dialog>
<template slot="header">
命名插槽内容
</template>
</gx-dialog>
</div>
示例代码
<div id="app">
<gx-dialog>
<div slot="header">
会员登陆
</div>
我是内容
<div slot="footer">
<button>取消</button>
<button>确定</button>
</div>
</gx-dialog>
</div>
<script>
Vue.component('gx-dialog',{
template: `
<div class="gx-dialog">
<slot name="header">
头部
</slot>
<slot>主体</slot>
<slot name="footer">
脚部
</slot>
</div>
`
})
var app = new Vue({
el: '#app'
})
</script>
作用域插槽
可以把组件内部的数据,抛出到父作用域,父作用域可以拿到内部数据,进行逻辑处理
示例
<style>
li{
display: inline;
margin: 0 10px;
}
a{
color: inherit;
}
.active{
color: red;
}
</style>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<gx-nav :data="navs">
<template slot-scope="row">
<a :href="row.url">{{row.title}}</a>
</template>
</gx-nav>
</div>
<script>
Vue.component('gx-nav',{
props: {
index: {
type: Number,
default: 0
},
data: {
type: Array,
required: true
},
},
template: `
<ul>
<li
:class="{active: index == i }"
v-for="( item, i ) in data"
>
<slot v-bind="item">
{{item.title}}
</slot>
</li>
</ul>
`
})
var app = new Vue({
el: '#app',
data: {
navs: [
{id: 1, icon: '@', title:'首页', url:'#' },
{id: 2, icon: '$', title:'关于我们', url:'#' },
{id: 3, icon: '%', title:'联系我们', url:'#' },
]
}
})
</script>
更多推荐
所有评论(0)