day 01
VUE
- Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
- 特点
- 声明式渲染
- 组件化
- 虚拟DOM(高效)
- 第三方社区
- 指令
- 前端路由
- 状态管理
- 轻量级
- 和jquery对比
- jquery:高效操作DOM
- vue :屏蔽DOM
- MVC 和MVVM
- Vue是MVVM形式的框架
- MVVM:
- M:model 数据
- V:view 视图
- VM: view-model 视图模型是 Model和 view的桥梁
- 官网:https://cn.vuejs.org/
- 对比其它框架https://cn.vuejs.org/v2/guide/comparison.html
vue 的使用
1.引入核心文件
2.准备挂载容器—{{}}
模板语法
3.实例化(vm 是Vue 的实例,参数是配置对象)
let vm=new Vue({
el:"#id名"(指定容器),
data:{(容器中被渲染的数据)}
})
- string,number,boolean,array,object被渲染为字符串
- undefined 和null 不渲染
- arr 可以通过下标访问
- object通过属性名访问
- 可以执行函数,不能定义(报错)
- 不能写流程控制
- 声明式渲染:eg:
- v-text=“渲染文本”
- v-cloak—{{渲染文本}}
- v-html=" "(慎用,不在表单域上使用)
- 响应式渲染:数据发生更新,视图自动更新:eg:
setTimeout(()=>{
vm.msg=‘hi web0717’
},1000) - v-else和v-if 之间不能有其它代码隔开,js表达式是boolean,true渲染该元素,false移除该元素
- v-show的js表达式是boolean,true渲染该元素,false:隐藏该元素
- 列表渲染:
- 被遍历项:名称自定义
- v-for="(被遍历项,索引) in 列表数据"
- v-for=“被遍历项 in 列表数据”
- v-for="(value,key,index) in 对象"
- key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。key必须是唯一的,使用index作为key不是推荐(,如果列表项时静态,可以使用)
- key 作用:作为列表项的唯一标识,提高辨识度,避免列表渲染出现复用渲染错误的问题。所有的列表项都必须有key
- 案例:九九乘法表
- 避免 v-if 结合v-for 使用
<div id="app">
<ul>
<!-- 避免 v-if 结合v-for 使用 -->
<li v-for="i in 9">
<span v-for="j in 9" v-if="j<=i" >{{j}}*{{i}}={{i*j}}</span>
</li>
<!-- v-for 可以嵌套使用 -->
<li v-for="i in 9" :key="i">
<!-- 避免 v-if 结合v-for 使用 -->
<span v-for="j in i" :key="j" >{{j}}*{{i}}={{i*j}}</span>
</li>
</ul>
</div>
- 动态属性—v-bind:属性名
- : 是 v-bind: 语法糖
- 动态属性class—:class
- 基础用法:直接js表达式(常用三元运算)
- 属性值的对象写法:
- key:动态类名
- value: 类名是否生效的boolean
- 数组写法:多个类名
- 动态属性style—:style
- 属性值的对象写法:
- key:css 样式名(驼峰写法)
- value: 样式值
- 数组写法:多个样式对象
- 属性值的对象写法:
- 下载 vue.js
- 代码:
<head>
<!-- 1.引入核心文件 -->
<script src="./js/vue.js"></script>
</head>
<body>
<!-- 2.准备挂载容器 -->
<!-- {{}} 模板语法 -->
<div id="app">
{{msg}}
</div>
<script>
// 3.实例化
// vm 是Vue 的实例
// 参数是配置对象
let vm = new Vue({
el:"#app",//指定容器
data:{
msg:"hello web0817"
},//容器中被渲染的数据
})
console.log(vm)//对象
</script>
</body>
- 模板语法:
<head>
<!-- 1.引入核心文件 -->
<script src="./js/vue.js"></script>
</head>
<body>
<!-- 2.准备挂载容器 -->
<!-- {{}} 模板语法 -->
<div id="app">
<p>{{msg}}</p>
<p>{{count}}</p>
<p>{{flag}}</p>
<p>{{und}}</p>
<p>{{nul}}</p>
<p>{{arr}}</p>
<p>{{arr[1]}}</p>
<p>{{obj}}</p>
<p>{{Math.random()}}</p>
<!-- <p>{{function(){}}}</p> -->
</div>
<script>
// 3.实例化
/
*string,number,boolean,array,object被渲染为字符串
* undefined 和null 不渲染
*arr 可以通过下标访问,object通过属性名访问
* 可以执行函数,不能定义
*不能写流程控制
/
let vm = new Vue({
el: "#app",//指定容器
data: {
msg: "hello web0817",
count: 1,
flag:true,
und:undefined,
nul:null,
arr:[1,2],
obj:{
age:20
}
},//容器中被渲染的数据
})
console.log(vm)
</script>
</body>
指令
- 带有特殊前缀
v-
的属性,属性名就是指令名称,属性值是js表达式,当数值值发生变化时,绑定指令的标签会做出对应变化(DOM改变) - v-text&&v-html
<!-- {{}} 模板语法 -->
<div id="app">
<!-- 渲染文本 -->
<p v-text="msg+'!'"></p>
<!-- 声明式渲染 -->
<p v-cloak>{{msg+'!'}}</p>
<!-- v-html慎用,不在表单域上使用 -->
<div v-html='child'></div>
</div>
<script>
let vm = new Vue({
el: "#app",//指定容器
data: {
msg: "hello web0817",
child:`
<h3>子元素</h3>`
},//容器中被渲染的数据
})
console.log(vm)
// 响应式,数据发生更新,视图自动更新
setTimeout(()=>{
vm.msg='hi web0717'
},1000)
</script>
- v-if
<div id="app">
<!-- 表达式是boolean,true渲染该元素,false:移除该元素 -->
<p v-if="flag">{{msg+'!'}}</p>
<p v-if="1==2?true:false">{{msg+'!'}}</p>
</div>
<script>
// 3.实例化
let vm = new Vue({
el: "#app",//指定容器
data: {
flag:true,
msg:"hello web"
},//容器中被渲染的数据
})
</script>
- v-show
- 表达式是boolean,true渲染该元素,false:隐藏该元素
<div id="app">
<!-- 表达式是boolean,true渲染该元素,false:隐藏该元素 -->
<p v-show="flag">{{msg+'!'}}</p>
<p v-show="1==2?true:false">{{msg+'!'}}</p>
</div>
<script>
let vm = new Vue({
el: "#app",//指定容器
data: {
flag:true,
msg:"hello web"
},//容器中被渲染的数据
})
</script>
- v-if vs v-show
- 相同之处:通过一个判断条件来决定元素是否显示
- 不同之处:
v-if
:通过DOM节点操作来移除和添加元素实现显示和隐藏,而v-show
通过css的display属性来实现的v-if
是真实的条件渲染,v-show
是css切换v-if
是惰性的(值为false元素不渲染),v-show
始终渲染该元素
- 使用场景:
- v-if: 决定初始的显示,后期不做切换
- v-show:频繁切换显示状态
列表渲染
- 列表渲染:被遍历项:名称自定义
- v-for="(被遍历项,索引) in 列表数据"
- v-for="被遍历项 in 列表数据"
- v-for="(value,key,index) in 对象"
<div id="app">
<ul>
<li v-for="(item,index) in list">{{index+1}}-{{item.title}}</li>
</ul>
<ol>
<li v-for="(item,key,index) in obj">{{item}}-{{key}}-{{index}}</li>
</ol>
<ol>
<li v-for="i in 9">{{i}}</li>
</ol>
</div>
<script>
// 3.实例化
let vm = new Vue({
el: "#app",//指定容器
data: {
list:[{
title:"标题1"
},{
title:"标题2"
}],
obj:{
name:"小李",
age:18,
sex:"male"
}
},//容器中被渲染的数据
})
</script>
key
<div id="app">
<ul>
<li v-for="(item,index) in list" :key="item.id"><span>{{item.title}}</span> <input type="text"></li>
<!-- <li v-for="(item,index) in list" :key="index"><span>{{item.title}}</span> <input type="text"></li> -->
</ul>
</ul>
</div>
<!-- key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。\
如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
key必须是唯一的,使用index作为key不是推荐(,如果列表项时静态,可以使用)
key 作用:作为列表项的唯一标识,提高辨识度,避免列表渲染出现复用渲染错误的问题。
所有的列表项都必须有key
-->
<script>
// 3.实例化
let vm = new Vue({
el: "#app",//指定容器
data: {
list: [{
id: 1,
title: "标题1"
}, {
id: 2,
title: "标题2"
}, {
id: 3,
title: "标题3"
}],
},//容器中被渲染的数据
})
console.log(vm)
// 响应式,数据发生更新,视图自动更新
setTimeout(() => {
vm.list.splice(1, 1)
}, 5000)
v-for 嵌套使用的问题
<div id="app">
<ul>
<!-- 避免 v-if 结合v-for 使用 -->
<!-- <li v-for="i in 9">
<span v-for="j in 9" v-if="j<=i" >{{j}}*{{i}}={{i*j}}</span>
</li> -->
<!-- v-for 可以嵌套使用 -->
<li v-for="i in 9" :key="i">
<!-- 避免 v-if 结合v-for 使用 -->
<span v-for="j in i" :key="j" >{{j}}*{{i}}={{i*j}}</span>
</li>
</ul>
</div>
动态属性
<!-- 1.引入核心文件 -->
<script src="./js/vue.js"></script>
<style>
span{
margin: 0 20px;
}
</style>
<body>
<!-- 2.准备挂载容器 -->
<!--
列表渲染:
被遍历项:名称自定义
v-for="(被遍历项,索引) in 列表数据"
v-for="被遍历项 in 列表数据"
v-for="(value,key,index) in 对象"
-->
<div id="app">
<img v-bind:src="url" alt="">
<!--
: 是 v-bind: 语法糖
-->
<img :src="url" alt="">
<ul>
<li v-for="(item,index) in list" :key="index">
<img v-bind:src="item.url" alt="">
</li>
</ul>
</div>
<script>
// 3.实例化
let vm = new Vue({
el: "#app",//指定容器
data: {
url:"http://www.ujiuye.com/zt/bcjz/images/logo.png",
list:[{
url:"http://www.ujiuye.com/zt/bcjz/images/p3_1.jpg",
},{
url:"http://www.ujiuye.com/zt/bcjz/images/p3_2.jpg"
}]
},//容器中被渲染的数据
})
</script>
动态class
<!-- 1.引入核心文件 -->
<script src="./js/vue.js"></script>
<style>
.cls1{
color:red;
}
.ft{
font-size: 50px;
}
</style>
<!-- 2.准备挂载容器 -->
<!--
动态class 可以结合普通class 使用
-->
<div id="app">
<!-- <p v-for="i in 4" :class="i%2==0?'cls1':''" :key="index">动态class</p> -->
<!-- 基础用法 -->
<h3>基础用法</h3>
<p v-for="i in 4" :class="i%2==0?c1:''" class="ft" :key="index">动态class</p>
<h3> 对象写法</h3>
<!--
对象写法:
key:动态类名
value: 类名是否生效的boolean
-->
<p v-for="i in 4" :class="{cls1:i%2==1}" :key="index">对象写法</p>
<h3>数组写法</h3>
<!-- 数组写法 -->
<p v-for="i in 4" :class="[i%2==0?c1:'','ft']" :key="index">对象写法</p>
</div>
<script>
// 3.实例化
let vm = new Vue({
el: "#app",//指定容器
data: {
c1:"cls1"
},//容器中被渲染的数据
})
</script>
动态style
<!-- 1.引入核心文件 -->
<script src="./js/vue.js"></script>
<div id="app">
<h3> 对象写法</h3>
<!--
对象写法:
key:css 样式名(驼峰写法)
value: 样式值
-->
<!-- <p v-for="i in 4" :style="{color:i%2==0?'red':'black'}" :key="i">对象写法</p> -->
<h3>数组写法</h3>
<!-- 数组写法 -->
<p v-for="i in 4" :style="[{color:i%2==0?'red':'black'},{fontSize:i%2==0?'30px':'50px'}]" :key="i">对象写法</p>
</div>
<script>
// 3.实例化
let vm = new Vue({
el: "#app",//指定容器
data: {
c1:"cls1"
},//容器中被渲染的数据
})
</script>
报错
- 不要在{{}} 写流程控制语句
- avoid using JavaScript keyword as property name
day 02
- v-once:绑定动态数据,后期无法修改减少不必要的更新,提高渲染效率
<p v-once>{{msg}}</p>
- 绑定事件:v-on: 事件类型 = “js表达式” || v-on: 事件类型 = “函数”(函数可以带上小括号)
- 语法糖: @替换 v-on:
- 实例中使用的函数放入配置参数methods中,this->当前的vue实例
- tab切换:
- 点击,按钮的索引赋值給活跃索引(@click=“activeIndex=index”)
- 内容索引和活跃索引相同的元素显示(v-show=“index==activeIndex”)
- 活跃索引在data中定义:activeIndex:0,
- 事件传参:可传0个或多个
- $event: vue 中的事件对象(@click=“fn( $event)”)
- 事件修饰符:辅助去处理 DOM 事件细节(@:事件类型.修饰符)
- stop: 阻止事件冒泡
- prevent: 组件默认事件
- once:只触发一次
- self: 只响应事件源是自己的事件
- capture: 捕获阶段触发
- 鼠标修饰符:left,right,middle:对应点击事件三个鼠标按钮
- 定义list数据进行列表渲染(数据驱动的概念)
- 双向绑定:v-model
- < p >{{msg}}</ p>< input type=“text” v-model=“msg”>
- 是< input type=“text” :value=“msg” @input=“msg=$event.target.value”>的语法糖
- 数据挟持
<div id="app">
<div>{{msg}}</div>
</div>
<script>
let obj = {
msg:"hello"
}
Object.defineProperty(obj,"msg",{
// 赋值时触发 val 被赋值时触发
set(val){
console.log("setter",val)
document.getElementById("app").innerHTML =`<div>${val}</div>`;
},
get(){
console.log("getter")
document.getElementById("app").innerHTML =`<div>hello</div>`;
return "hello"
}
})
console.log(obj)
console.log(obj.msg)
obj.msg = "hi"
setTimeout(()=>{
obj.msg = "new data"
},2000)
</script>
- v-model单选框:v-model 绑定值如果和单选框value一致就会被选中
- 语文: < input type=“radio” name=“cate” v-model=“catename” :value=“1”>
- 数学: < input type=“radio” name=“cate” v-model=“catename” :value=“2”>
- 数学: < input type=“radio” name=“cate” @change=“catename=2” :checked=“catename==2” :value=“2” >
- v-model列表渲染
- 不要把列表项直接作为v-model绑定的值
- 数组的成员最好是对象,数组成员没有set 和get ,导致数据发生更新,但是页面不更新的bug
- vue中数据发生更新,页面不更新的问题(直接访问了数组项,对象成员带有set,get)
- 通过下标访问(错误写法)(this.list1[0] = “hello every”;,this.$forceUpdate()):强制更新(不推荐)
- 能被vue监听的操作 splice, push pop,shift,unshift(this.list1.splice(0,1,“hello every”))
- 官方推荐的写法 ,实例内 this.$set(this. $set(this.list1,0,“hello erverone”);)
- @params1:被更新的数据
- @params2:被更新的项索引(对象的key)
- @params3:更新后的值
- 实例外写法:Vue.set(vm.list1,0,“hello erverone”)
- 删除:this.$delete(this.list1,0);
- 多选,v-model 绑定 值是数组,如果选中 value会被推入到数组
- 选中状态:v-model绑定选中状态,true 选中,false不选中
- 收集数据:多选,v-model 绑定 值是数组,如果选中 value会被推入到数组
事件绑定
- methods中的this执行当前组件实例
<script src="./js/vue.js"></script>
<div id="app">
<!--
绑定事件
v-on: 事件类型 = "js表达式"
v-on: 事件类型 = "函数"
函数可以带上小括号
语法糖: @替换 v-on:
-->
<p >{{msg}}</p>
<div><button v-on:click="msg='new data'">表达式</button></div>
<div><button v-on:click="fn">函数</button></div>
<div><button v-on:click="fn()">函数</button></div>
<div><button @click="fn()">语法糖</button></div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
msg:"old data"
},
// 实例中使用的函数
methods:{
fn(){
// console.log("clicked")
// vm.msg='new data'
// console.log(this==vm); this->当前的vue实例
this.msg='new data'
}
}
})
</script>
事件传参
- 函数后面的小括号中带上参数 ,参数的个数没有限制
<script src="./js/vue.js"></script>
<style>
.con {
width: 200px;
height: 200px;
border: 1px solid #f00;
}
</style>
<div id="app">
<div>
<!-- 点击,按钮的索引 赋值給 活跃索引 -->
<button v-for="(item,index) in 3" :key="item" @click="fn(index)">btn{{item}}</button>
</div>
<div>
<!-- 内容索引和活跃索引相同的元素显示 -->
<div v-show="index==activeIndex" class="con" v-for="(item,index) in contents" :key="index">{{item.content}}
</div>
</div>
</div>
<script>
let vm = new Vue({
el: "#app",
data: {
// 活跃索引
activeIndex: 0,
contents: [{ content: "con1" }, { content: "con2" }, { content: "con3" }]
},
// 实例中使用的函数
methods: {
// @i:传入的参数
fn(i) {
this.activeIndex = i;
}
}
})
</script>
event对象
- event对象可以以$event形式传入
<div id="app">
<p >{{msg}}</p>
<!-- $event: vue 中的事件对象 -->
<div @click="outer"><button @click="fn($event)">语法糖</button></div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
msg:"old data"
},
// 实例中使用的函数
methods:{
outer(){
this.msg = "outer data";
},
// e:事件对象
fn(e){
this.msg='new data'
console.log(e)
e.stopPropagation();
}
}
})
</script>
结合参数和event对象
<div id="app">
<div>
<!-- 点击,按钮的索引 赋值給 活跃索引 -->
<button v-for="(item,index) in 3" :key="item" @click="fn(index,$event)">btn{{item}}</button>
</div>
<div>
<!-- 内容索引和活跃索引相同的元素显示 -->
<div v-show="index==activeIndex" class="con" v-for="(item,index) in contents" :key="index">{{item.content}}
</div>
</div>
</div>
<script>
let vm = new Vue({
el: "#app",
data: {
// 活跃索引
activeIndex: 0,
contents: [{ content: "con1" }, { content: "con2" }, { content: "con3" }]
},
// 实例中使用的函数
methods: {
// @i:传入的参数
fn(i,e) {
this.activeIndex = i;
console.log(e)
}
}
})
</script>
事件修饰符
- 事件修饰符:辅助去处理 DOM 事件细节
<div id="app">
<!--
事件修饰符 辅助去处理 DOM 事件细节
@事件类型.修饰符
stop: 阻止事件冒泡
prevent: 组件默认事件
once:只触发一次
self: 只响应事件源是自己的事件
capture: 捕获阶段触发
鼠标修饰符
left,right,middle:对应点击事件三个鼠标按钮
-->
<p >{{msg}}</p>
<!-- $event: vue 中的事件对象 -->
<div @click="outer"><button @click.stop="fn()">语法糖</button></div>
<div @contextmenu.prevent="fn1">阻止默认事件</div>
<div ><button @click.once="fn2()">once</button></div>
<div @click.self="fn3()"><button>self</button></div>
<div @click.capture="outer"><button @click="fn()">capture</button></div>
<div @click.right="fn4">right</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
msg:"old data"
},
// 实例中使用的函数
methods:{
outer(){
console.log("outer")
this.msg = "outer data";
},
fn(){
console.log("fn")
this.msg='new data'
},
fn1(){
console.log("右键")
},
fn2(){
console.log("once")
},
fn3(){
console.log("self")
},
fn4(){
console.log("右键")
}
}
})
</script>
双向绑定
- model的数据通过vm渲染到视图view中,反之vm监听视图中的事件可以修改model的数据
- v-model
- 输入框:
- v-model 和value挂钩:
- 输入框:
<div id="app">
<h3>双向绑定</h3>
<p >{{msg}}</p>
<div>
<!--
model 的数据通过vm 渲染到 view 层
用户在 view 中的操作可以修改 model的数据
-->
<input type="text" v-model="msg">
</div>
<div>
<!--
model 的数据通过vm 渲染到 view 层
用户在 view 中的操作可以修改 model的数据
-->
<input type="text" :value="msg" @input="msg=$event.target.value">
</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
msg:"data"
}
})
</script>
- 单选:是否被选中: v-model和value挂钩
<div id="app">
<h3>双向绑定</h3>
<p >{{catename}}</p>
<!-- 单选框,v-model 绑定 值如果和 单选框value一致就会被选中 -->
<div>
语文: <input type="radio" name="cate" v-model="catename" :value="1">
数学: <input type="radio" name="cate" v-model="catename" :value="2">
<!-- 数学: <input type="radio" name="cate" @change="catename=2" :checked="catename==2" :value="2" > -->
</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
catename:1
}
})
</script>
- 多选:获取选中值:v-model 绑定的值是value构成的数组
<div id="app">
<h3>双向绑定</h3>
<p >{{catename}}</p>
<!-- 多选,v-model 绑定 值是数组,如果选中 value会被推入到数组 -->
<div>
语文: <input type="checkbox" v-model="catename" :value="1">
数学: <input type="checkbox" v-model="catename" :value="2">
</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
catename:[1]
}
})
</script>
- 选中状态:v-model 和boolean挂钩
<div id="app">
<h3>双向绑定</h3>
<p >{{catename}}</p>
<!-- 选中状态
v-model绑定选中状态,true 选中,false不选中
-->
<div>
全选:<input type="checkbox" v-model="allSelected">
<p>{{allSelected}}</p>
</div>
<!-- 收集数据:多选,v-model 绑定 值是数组,如果选中 value会被推入到数组 -->
<div>
语文: <input type="checkbox" v-model="catename" :value="1">
数学: <input type="checkbox" v-model="catename" :value="2">
</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
catename:[1],
allSelected:true
}
})
</script>
- 下拉:多选和单选都可以
<div id="app">
<h3>双向绑定</h3>
<p >{{catename}}</p>
<p >{{catename1}}</p>
<!-- 下拉单选 -->
<select name="" id="" v-model="catename">
<option :value="1">语文</option>
<option :value="2">数学</option>
</select>
<!-- 下拉多选 -->
<select name="" id="" v-model="catename1" multiple>
<option :value="1">语文</option>
<option :value="2">数学</option>
</select>
<div>
语文: <input type="radio" name="cate" v-model="catename" :value="1">
数学: <input type="radio" name="cate" v-model="catename" :value="2">
<!-- 数学: <input type="radio" name="cate" @change="catename=2" :checked="catename==2" :value="2" > -->
</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
catename:1,
catename1:[1,2]
}
})
</script>
表单修饰符
- v-model
.number
=“count”(绑定值转换为数值型) - v-model
.trim
=“msg”(去除绑定值首尾空格) - v-model
.lazy
=“txt”(触发事件变成change事件(失去焦点时赋值))
<div id="app">
<h3>number</h3>
<p >{{count+1}}</p>
<div>
<!--
number: 绑定值转换为数值型
-->
<input type="text" v-model.number="count">
<input type="text" :value="count" @input="count=Number($event.target.value)">
</div>
<h3>trim</h3>
<p >{{msg.length}}</p>
<div>
<!--
trim: 去除绑定值首尾空格
-->
<input type="text" v-model.trim="msg">
</div>
<h3>lazy</h3>
<p >{{txt}}</p>
<div>
<!--
lazy: 触发事件变成change事件(失去焦点时赋值)
-->
<input type="text" v-model.lazy="txt">
</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
count:1,
msg:"hi",
txt:"hello"
}
})
</script>
day 03
- 键盘修饰符:按下对应按键,事件函数才会执行
- 键盘事件类型.别名:esc ,left,right,top,bottom, enter,space,alt
- 或者是键盘事件类型.键码值:13->enter,37->left
@keydown.13 = "search($event)"
生命周期
- 生命周期钩子:回调函数,在生命周期的某个节点执行的函数,给了开发在实例生命周期中添加自己代码的机会。
- 生命周期:实例创建,数据观测,挂载到更新、销毁的过程
- 初始期:一个周期只执行一次: beforeCreate()–created()–beforeMount()–mounted()
- 更新期:虚拟DOM 描述真实DOM结构的js对象,使用虚拟DOM可以减少更新页面时的性能损耗:beforeUpdate()–updated()
- 销毁期:beforeDestroy()–destroyed()
<body>
<div id="app">
<p >{{msg}}</p>
<div>
<input type="text" v-model="msg">
</div>
</div>
<button id="des">销毁</button>
<script>
//虚拟DOM 描述真实DOM结构的js对象,使用虚拟DOM可以减少更新页面时的性能损耗,更新时操作js对象,最后进行页面渲染
let vnode = {
type:"div",
attrs:{
id:"app"
},
children:[{
type:'p',
data:"msg"
},{
type:'div',
}]
}
function render(vn){
let el = document.createElement(vn.type);
for(key in vn.attrs){
el.setAttribute(key,vn.attrs[key])
}
return el;
}
render(vnode);
console.log(render(vnode));
let vm = new Vue({
el:"#app",
data:{
msg:"hi",
},
//在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
beforeCreate() {
console.log(this)
console.log(this.msg);//undefined
},
//在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用。
created(){
this.timer = setInterval(()=>{
console.log("time")
},1000)
// 可以访问数据
console.log(this.msg)
console.log(this.$el);// undefined
},
// 挂载:使用模板编译DOM,页面中模板DOM替换成编译后的DOM过程
//在挂载开始之前被调用:相关的 render 函数首次被调用。
beforeMount() {
// 获取$el
console.log(this.$el)
document.querySelectorAll("input")[0].style.borderColor ="red"
},
//实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。
mounted(){
console.log(this.$el)
// document.querySelectorAll("input")[0].style.borderColor ="red"
},
// 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器
beforeUpdate() {
console.log(this.msg)
},
//当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。
updated() {
console.log(this.msg)
},
//实例销毁之前调用。在这一步,实例仍然完全可用。
beforeDestroy() {
clearInterval(this.timer);
this.timer = null;
},
//实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
destroyed() {
},
})
document.querySelector("#des").onclick=function(){
vm.$destroy()
};
</script>
</body>
监听属性
- 方法名称是被监听的数据,监听的数据发生变化,函数就会自动执行
- 函数写法
<body>
<div id="app">
<p :style="{color:flag?'red':'black'}">{{msg}}</p>
<div>
<input type="text" v-model="msg">
</div>
<p>{{count}}</p>
<button @click="fn1">修改msg</button>
</div>
<!--
监听属性和methods之间的区别:
methods:需要手动调用,
watch:数据变化自动执行
watch:擅长处理一对多关系
-->
<script>
new Vue({
el: "#app",
data: {
msg: "abced",
flag: false,
count:1
},
watch: {
// 方法名称被监听的数据,监听的数据发生变化,函数就会自动执行
// @newValue:变化后的数据
// @oldValue:变化前的数据
msg(newValue,oldValue){
console.log(newValue,oldValue)
if(this.msg.length>=5){
this.flag = true;
}else{
this.flag =false;
}
this.count++;
}
},
methods: {
fn1() {
this.msg = "hello"
}
}
})
</script>
</body>
- 对象写法
watch: {
arr1:{
immediate:true,//立即执行
deep:true,//进行深度监听(监听的数据类型为引用时)
//监听函数
handler(newValue,oldValue){
// console.log("arr1")
this.getTotal();
this.getAllSelect();
}
}
}
- 可以做异步操作
<body>
<div id="app">
<div>
<input type="text" v-model="msg">
</div>
<ul>
<li v-for="(item,index) in list" :key="index">{{item}}</li>
</ul>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
msg:"",
list:""
},
// 可以在监听属性值之中进行异步操作(开销比较大的操作)
watch: {
//"http://suggestion.baidu.com/su?cb=cc&wd="
msg(){
$.ajax({
url:"http://suggestion.baidu.com/su",
data:{
cb:"cc",//指明回调函数
wd:this.msg,//关键字
},
dataType:"jsonp",//请求方式 Jsonp
})
}
},
})
function cc(data){
console.log(data);
vm.list = data.s;
}
</script>
</body>
监听属性和methods之间的区别?
- methods:需要手动调用,
- watch:数据变化自动执行
- watch:擅长处理一对多关系,可以在监听属性值之中进行异步操作,开销比较大的操作
计算属性
- 计算:依赖数据,自动计算一个结果(做复杂运算)、
- 计算属性值(返回值)可以当作data数据来使用
<body>
<div id="app">
<ul>
<li v-for="(item,index) in list1" :key="index">{{item.txt}}</li>
</ul>
<button @click="add">add</button>
</div>
<script>
let vm = new Vue({
methods: {
add(){
this.list.push({txt:"4"},{txt:"5"})
}
},
el:"#app",
data:{
msg:"",
list:[{txt:"1"},{txt:"2"},{txt:"3"}]
},
computed: {
list1(){
let newList = this.list.filter((item,index)=>index%2==0);
console.log(newList)
return newList;
}
},
})
</script>
</body>
- 设置计算属性
computed: {
total(){
let total = 0;
// 根据是否被选中进行总价累加
this.arr1.map(item=>{
if(item.selected){
total+=item.price*item.cartNum
}
});
// 保留 2为小数点
return total.toFixed(2);
},
// allSelected(){
// return this.arr1.every(item=>item.selected);
// }
// 计算属性的对象写法(需要设置计算属性值时使用)
allSelected:{
// 获取计算结果
get(){
return this.arr1.every(item=>item.selected);
},
// 设置计算属性值:val 设置值
set(val){
console.log(val);
this.arr1.map(item=>item.selected = val)
}
}
},
计算属性和监听属性对比?
- 计算属性:进行复杂运算(多个数据变化得到一个计算结果,计算属性的结果会被缓存)
- 监听属性:异步操作和开销较大的操作(一个数据变化影响多个数据)
使用计算属性实现日期的格式化,只显示年月日?
computed: {
time1(){
// 2020-11-25
let d1 = new Date(this.time)
console.log(d1)
let y = d1.getFullYear();
let m = d1.getMonth()+1;
let d = d1.getDate();
return `${y}-${m}-${d}`;
}
},
过滤器
- Vue中过滤器如何定义和使用?
- 可以批量格式化数据
- 使用过滤器:被过滤的数据 | 过滤器名称(reg)
- 注册过滤器
- 全局:Vue.filter(“过滤器名称”, function (被过滤的数据,reg){ }
- vue实例中配置:filters: {
过滤器名称(被过滤的数据){
}
<div id="app">
<!-- 过滤器:可以批量格式化数据 -->
<!-- 使用过滤器
被过滤的数据 | 过滤器名称
-->
<p>{{time | dateFormat("yyyy年mm月dd日")}}</p>
<p>{{t2 | dateFormat}}</p>
</div>
<script>
// 注册过滤器,
// timestamp:被过滤的数据
// reg:传入的参数
Vue.filter("dateFormat", function (timestamp,reg) {
console.log(timestamp,reg)
let d1 = new Date(timestamp)
let y = d1.getFullYear();
let m = d1.getMonth() + 1;
let d = d1.getDate();
// 返回过滤结果
// 没有传入参数
if(!reg){
return `${y}-${m}-${d}`;
}
if(reg=="yyyy年mm月dd日"){
return `${y}年${m}月${d}日`;
}
})
new Vue({
el: "#app",
data: {
time: 1606293682295,
t2: 1606823682295
},
//使用计算属性实现日期的格式化,只显示年月日?
/* computed: {
time1(){
// 2020-11-25
let d1 = new Date(this.time)
console.log(d1)
let y = d1.getFullYear();
let m = d1.getMonth()+1;
let d = d1.getDate();
return `${y}-${m}-${d}`;
}
}, */
filters: {
// timestamp:被过滤的数据
/* dateFormat(timestamp){
let d1 = new Date(timestamp)
let y = d1.getFullYear();
let m = d1.getMonth()+1;
let d = d1.getDate();
// 返回过滤结果
return `${y}-${m}-${d}`;
} */
}
})
</script>
过渡
- 下列情形中,可以给任何元素和组件添加进入/离开过渡(过渡动画在什么场景下使用?有哪几个内置的类名(6个)?)
- 条件渲染 (使用 v-if)
- 条件展示 (使用 v-show)
- 动态组件
- 组件根节点
- 当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:
- 自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
- 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。
- 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)
- css 过渡
- 在进入/离开的过渡中,会有 6 个 class 切换。
- v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
- v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间duration,延迟delay和曲线函数。
- v-enter-to:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
- v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
- v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
- v-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
- 在进入/离开的过渡中,会有 6 个 class 切换。
- 案例
<style>
.box{
width: 200px;
height: 200px;
background-color: pink;
}
/* */
.v-enter{
opacity: 0;
height: 0;
}
/* 过程 */
.v-enter-active{
transition: 3s;
}
/* 最终状态 */
.v-enter-to{
opacity: 1;
}
.v-leave{
opacity: 1;
}
.v-leave-active{
transition: 1s;
}
.v-leave-to{
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<button @click="flag=!flag" >修改flag</button>
<transition>
<p v-if="flag" class="box">{{msg}}</p>
</transition>
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "hello",
flag: false
},
})
</script>
</body>
- 自定义类名:内置组件transition的name 属性:自定义过渡类名的前缀
.scroll-enter{
height: 0;
}
.scroll-enter-active{
transition: 2s;
}
.scroll-enter-to{
height: 200px;
}
<transition name="scroll">
<div class="box2" v-if="flag">box1</div>
</transition>
day 04
动画
- 在类名leave-active 或者enter-active 中定义动画样式
- 法一:自定义类名动画
.exit-leave-active{
animation: ani 2s;
}
@keyframes ani {
from{
transform: translateX(0);
}
to{
transform: translateX(200px);
}
}
<!-- name 属性: 自定义过渡动画类名的前缀 -->
<transition name='exit'>
<div class="box1" v-if="flag">box1</div>
</transition>
- 法二:指定动画类名
- leave-active-class:指定离开类名
- enter-active-class: 指定进入类名
.myani{
animation: ani 2s;
}
@keyframes ani {
from{
transform: translateX(0);
}
to{
transform: translateX(200px);
}
}
<transition leave-active-class="myani">
<div class="box1" v-if="flag" >box1</div>
</transition>
- 法三:使用动画库(animate.css)
<transition leave-active-class="animated bounceOut">
<div class="box1" v-if="flag" >box1</div>
</transition>
<transition leave-active-class="animated rotateOutDownLeft">
<div class="box1" v-if="flag" >box1</div>
</transition>
组件
- vue中的组件:可以被复用的vue实例,带有一个名字(作为自定义标签使用)。
- 组件: 封装一段带有==模板(template)、样式(style)和逻辑功能(script)==的代码。
- 组件优点:
- 提高开发效率
- 简化后期维护
- 多人协作
- 组件化:应用由组件树构成。
组件的定义
- 全局注册(定义)组件:Vue.component(“组件名”,{ 组件配置项 });
- 局部注册(定义)组件(只能在当前实例(组件中使用)):
- 在vue实例里定义:components:{
- 组件名:{
- 组件配置项
- }
- 组件名:{
- }
- 在vue实例里定义:components:{
<div id="app">
<!-- 作为自定义标签使用 -->
<mycom v-for="n in 3"></mycom>
</div>
<div id="app2">
<!-- <mycom></mycom> -->
<v-com></v-com>
</div>
<script>
// 全局定义组件:所有组件(实例)都可以使用
// 参数一:v-com :组件名称
// 参数二:组件配置项
Vue.component("v-com", {
template: `<div>
<h3>v-com</h3>
</div>`
})
new Vue({
el: "#app",
// 定义(注册)局部组件,只能在当前实例(组件中使用)
components: {
mycom: {
// 模板
template: `
<div>
<h3>box</h3>
<p>组件</p>
</div>
`
}
}
})
new Vue({
el: "#app2"
})
</script>
使用template标签定义模板内容
- 模板:使用id为 temp的template作为模板
<!-- 使用template标签定义模板内容 -->
<template id="temp">
<div>
<p>{{msg}}</p>
</div>
</template>
<script>
new Vue({
el: "#app",
components: {
mycom: {
// 模板:使用id为 temp的template作为模板
template: "#temp",
// 组件的data 项必须是函数返回对象的形式
//每一个组件都拥有 data 返回数据的独立数据,避免一个组件修改data,其他组件受到影响
data() {
return {
msg: "mycom 组件"
}
}
}
}
})
</script>
组件的相关问题:
- 可以使用template标签定义模板内容
组件的data问题:组件的data 项必须是函数返回对象的形式
每一个组件都拥有 data 返回数据的独立数据,避免一个组件修改data,其他组件受到影响
data 有作用域,只能在当前定义的组件中使用
- 组件的名称, 驼峰命名的命名的组件,需要用短横杠连接的写法使用
组件可以嵌套,形成父子组件的概念
组件的模板中 有且仅有唯一根元素
动态组件
- 内置组件component的 is属性可以声明动态组件渲染的组件名称
<div id="app">
<button @click='name="v-recommend"'>推荐</button>
<button @click='name="v-video"'>视频</button>
<!-- 动态组件:
is 属性可以声明动态组件渲染的组件名称
-->
<component :is="name"></component>
</div>
<!-- 使用template标签定义模板内容 -->
<template id="recommend">
<div>
推荐版块
</div>
</template>
<template id="video">
<div>
视频版块
</div>
</template>
<script>
new Vue({
el: "#app",
data:{
name:"v-recommend",//动态组件的名称
},
// 定义局部组件,只能在当前实例(组件中使用)
components: {
vRecommend:{
template:"#recommend"
},
vVideo:{
template:"#video"
}
}
})
</script>
组件缓存
- 动态组件渲染的组件切换状态后会被销毁,不会保持状态,根据需求,可以在动态组件外嵌套使用内置组件keep-alive,使原本应该销毁的组件被缓存,保持状态
- 属性include:指定被缓存的组件名称
- 属性exclude:指定不被缓存的组件名称
<div id="app">
<button @click='name="v-recommend"'>推荐</button>
<button @click='name="v-video"'>视频</button>
<!-- keep-alive:内置组件
使用组件可以使原本应该销毁的组件被缓存,保持状态
include:指定被缓存的组件名称
exclude:指定不被缓存的组件名称
-->
<keep-alive include="v-recommend">
<component :is="name"></component>
</keep-alive>
</div>
<!-- 使用template标签定义模板内容 -->
<template id="recommend">
<div>
<p>推荐版块</p>
<div><input type="text"></div>
</div>
</template>
<template id="video">
<div>
视频版块
</div>
</template>
<script>
new Vue({
el: "#app",
data:{
name:"v-recommend",//动态组件的名称
},
// 定义局部组件,只能在当前实例(组件中使用)
components: {
vRecommend:{
template:"#recommend",
created() {
console.log("推荐 created")
},
destroyed() {
console.log("推荐 destroyed")
},
//
deactivated(){
console.log("推荐 不活跃")
}
},
vVideo:{
template:"#video",
created() {
console.log("视频 created")
},
destroyed() {
console.log("视频 destroyed")
},
}
}
})
</script>
is特殊用法
- is 属性可以突破html嵌套规则(eg:table里面不能直接套组件,只能套tr)
<div id="app">
<table>
<!-- 突破html嵌套规则 -->
<!-- <tr-item></tr-item> -->
<tr is="tr-item"></tr>
</table>
</div>
<!-- 使用template标签定义模板内容 -->
<template id="tr-item">
<tr>
<td>1</td>
<td>2</td>
</tr>
</template>
<script>
new Vue({
el: "#app",
// 定义局部组件,只能在当前实例(组件中使用)
components: {
trItem:{
template:"#tr-item"
},
}
})
</script>
vue-cli 脚手架
- 安装:npm i vue-cli -g
- 使用指令查看版本 2.9.6:vue -V(–version)
- 创建项目:项目名称以字母开头:vue init webpack (项目名)
- yyyynnnny
- 运行项目
- cd <项目名>
- npm start
- 项目目录:
- build: webpack配置相关
- config:项目配置
- node_modules:项目依赖
- src: 源码
- assets 静态资源
- components 定义组件
- main.js 打开入口
- App.vue : 单文件组件
- static:服务器静态资源目录
- index.html :页面入口
使用组件
- 定义组件文件 src/components/layout.vue
<template>
<div class="layout">
<!-- 使用子组件 -->
<side-nav></side-nav>
<main-cont></main-cont>
</div>
</template>
<script>
//引入子(局部)组件
import sideNav from "./sideNav";
import mainCont from "./main";
export default {
//注册子组件
components: {
sideNav,
mainCont
},
};
</script>
<style>
.layout{
width: 100%;
height: 100%;
display: flex;
}
</style>
- 定义子组件:src/components/sideNav.vue
<template>
<div class="sideNav">
{{msg}}
</div>
</template>
<script>
export default {
data() {
return {
msg:"侧边导航栏"
}
},
}
</script>
<style>
.sideNav{
width: 200px;
height: 100%;
color: bisque;
background-color: #333;
}
</style>
- 定义子组件:src/components/sideNav.vue
<template>
<div class="main">
<!-- 使用子组件 -->
<main-top></main-top>
<main-bottom></main-bottom>
</div>
</template>
<script>
//引入子组件
import mainTop from "./mainTop";
import mainBottom from "./mainBottom";
export default {
// data() {
// return {
// msg:"主体内容"
// }
// },
//注册子组件
components:{
mainTop,
mainBottom
}
}
</script>
<style>
.main{
flex-grow:1;
height: 100%;
background-color: #eee;
display: flex;
flex-direction: column;
}
</style>
day 05
组件化和模块化的区别?
- 什么是组件和模块?
- 组件:把重复的代码提取出来合并成为一个个组件,组件最重要的就是重用(复用),位于框架最底层,其他功能都依赖于组件,可供不同功能使用,独立性强。
- 模块:分属同一功能/业务的代码进行隔离(分装)成独立的模块,可以独立运行,以页面、功能或其他不同粒度划分程度不同的模块,位于业务框架层,模块间通过接口调用,目的是降低模块间的耦合,由之前的主应用与模块耦合,变为主应用与接口耦合,接口与模块耦合。
- 模块就像有多个USB插口的充电宝,可以和多部手机充电,接口可以随意插拔。复用性很强,可以独立管理。
- 组件和模块的区别
- 组件:就像一个个小的单位,多个组件可以组合成组件库,方便调用和复用,组件间也可以嵌套,小组件组合成大组件。
- 模块:就像是独立的功能和项目(如淘宝:注册、登录、购物、直播…),可以调用组件来组成模块,多个模块可以组合成业务框架。
- 为什么要使用组件化和模块化?
- 开发和调试效率高:随着功能越来越多,代码结构会越发复杂,要修改某一个小功能,可能要重新翻阅整个项目的代码,把所有相同的地方都修改一遍,重复劳动浪费时间和人力,效率低;使用组件化,每个相同的功能结构都调用同一个组件,只需要修改这个组件,即可全局修改。
- 可维护性强:便于后期代码查找和维护。
- 避免阻断:模块化是可以独立运行的,如果一个模块产生了bug,不会影响其他模块的调用。
- 版本管理更容易:如果由多人协作开发,可以避免代码覆盖和冲突。
- 组件化和模块化一般情况是一起出现的,他们就像好兄弟,虽然可以分离但最好一起有个照应。
- eg:“我的淘宝”页调用了会员模块、物流模块、充值模块和运动模块,而且可以发现他们调用了同一个组件在“我的淘宝”来展示各自的模块。
组件通信
父子组件传值
- 父组件App.vue中:使用子组件的时候通过给子组件添加自定义属性,向子组件传递数据
<!-- 可以传递任意数据类型 -->
<v-box1 :info="info" :test="test"></v-box1>
data(){
return{
info:{
txt:"java",
pic:"http://www.ujiuye.com/zt/bcjz/images/p3_1.jpg"
}
}
},
- 子组件 box.vue:使用props接收父组件传过来的数据
- 单向数据流:组件只能由父组件向子组件传递数据
<template>
<div class="item-box">
<img :src="info.pic" alt="">
<p>{{info.txt}}</p>
<button><a href="http://www9.53kf.com/webCompany.php?kf_sign=jQ0MTMTYwNMyMjEwNTAyOTk5NzU5MDE0NzIxNTUyNzE%253D&arg=10155271&style=1">了解更多</a></button>
</div>
</template>
<script>
export default {
// 子组件通过props 属性声明接受的自定义数据
// 数组写法,每一个成员都是一个自定义属性名称的字符串
props:["info"],
mounted(){
console.log(this.txt);
// 不要在子组件中直接修改父组件的prop
// 单向数据流:组件只能由父组件向子组件传递数据
// this.txt = 'aaa'
}
}
</script>
结合v-for 向组件传递props
<v-box1 v-for="(item,index) in infoList" :key="index" :info="item" :test="test"></v-box1>
infoList:[{
txt:"java",
pic:"http://www.ujiuye.com/zt/bcjz/images/p3_1.jpg"
},{
txt:"全栈开发",
pic:"http://www.ujiuye.com/zt/bcjz/images/p3_2.jpg"
}]
props进行验证:对象写法
- 直接验证数据类型
- 对象内配置
- 默认值default,
- 数据类型type,
- 必填项required,
- 自定义验证函数validator(val){// 返回值为true 验证成功,false失败
return val<5;
}
props:{
// props验证:对象写法
info:Object,//接受 info ,info的数据类型必须是对象
// count:String,
count:{
default:“0”,
// type:String, //字符串
type:[String,Number],
// 自定义验证函数,val:被验证的prop
validator(val){
// 返回值为true 验证成功,false失败
return val<5;
}
},
test:{
required:true,//必填
}
}
子父组件通信
- 数据流是单向的,想让 props 发生变化,唯一的办法是修改父组件的传入的prop
- 注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
- 父组件:给子组件绑定自定义事件,处理在子组件上绑定的自定义事件的事件处理函数修改父组件的数据
<template>
<div id="app">
<p>父组件的count:{{count}}</p>
<!--1. 给 box 子组件定义自定义事件 add -->
<v-box :count="count" :num="num" @add="addFn"></v-box>
<button @click='count++'>父组件count+1</button>
</div>
</template>
<script>
import vBox from "./components/box"
export default {
data(){
return{
count:1,
num:{
count:1
}
}
},
name: 'App',
components: {
vBox
},
methods:{
// 自定义事件add的事件处理函数,修改父组件中的count
addFn(){
this.count++;
}
}
}
</script>
- 子组件:触发自定义事件,接收新的prop值
<template>
<div class="item-box">
<p>父组件传入的prop-count:{{count}}</p>
<p>父组件传入的num.count:{{num.count}}</p>
<button @click="count++">子组件count+1</button>
<!-- 通过点击,触发自定义事件 -->
<button @click="clickFn">子组件通知父组件count+1</button>
<button @click="num.count++">子组件num.count+1</button>
</div>
</template>
<script>
export default {
props: {
count: Number,
num: Object
},
methods: {
// 触发自定义事件add
clickFn() {
// 触发自定义事件
this.$emit("add");
}
}
};
</script>
- 传值:子组件触发自定义事件,第二个参数就是传入的值:this.$emit(“push”,this.msg);
- 父组件中接收值:
<template>
<div id="app">
<v-box :list="list"></v-box>
<v-wrapper @push="pushFn"></v-wrapper>
</div>
</template>
<script>
import vBox from "./components/box"
import vWrapper from "./components/wrapper"
export default {
data(){
return{
list:["a","b"]
}
},
name: 'App',
components: {
vBox,
vWrapper
},
methods:{
// val:自定义事件触发传递的数据
pushFn(val){
this.list.push(val)
}
}
}
</script>
兄弟组件
- bus.js:空的vue实例,作为自定义事件的载体
import Vue from "vue"
let bus = new Vue();
console.log(bus)
export default bus;
- 接收数据的组件中给bus注册自定义事件
<script>
import bus from "./../bus"
export default {
mounted(){
// 在列表组件中给bus 注册自定义事件
bus.$on("push",(val)=>{
this.list.push(val)
})
},
data(){
return{
list:["a","b"]
}
}
};
</script>
- 传递数据的组件,触发bus 上的自定义事件
<script>
import bus from "./../bus"
export default {
data() {
return {
msg: ""
};
},
methods: {
add() {
bus.$emit("push",this.msg)
}
}
};
</script>
- 改进写法:
- main.js
import bus from "./bus"
Vue.prototype.$bus = bus;
- 组件中通过this.$bus 获取bus
ref
- 通过给子组件和标签添加ref属性,可以访问子组件实例(访问数据和调用方法)和标签对象
<template>
<div id="app">
<button @click="fn" ref="btn">显示对话框</button>
<v-box ref="list"></v-box>
<!-- 给组件添加ref -->
<v-wrapper ref="alert"></v-wrapper>
<p v-for="n in 3" :key="n" ref="ops">{{n}}</p>
</div>
</template>
<script>
import vBox from "./components/box"
import vWrapper from "./components/wrapper"
export default {
created(){
console.log(this.$refs.btn);//undefined
},
mounted(){
// 获取标签
console.log(this.$refs.btn);
console.log(this.$refs.ops);
},
data(){
return{
}
},
name: 'App',
components: {
vBox,
vWrapper
},
methods:{
fn(){
// 在父组件中获取子组件实例
// console.log(this.$refs.alert.isShow)
this.$refs.alert.open();
}
}
}
</script>
jquery 使用
- 1 放在static,在index.html中引入< script src="./static/js/jquery.js"></ script>
- 2 放在assets,在main.js中:import “./assets/js/jquery”
- 3 使用npm 进行下载使用(推荐使用):npm i jquery --save
- main.js
- import $ from “jquery”
- Vue.prototype.$ = $
- main.js
vue-awesome-swiper(vue定制版的swiper轮播图插件)
- 安装:==npm i swiper@5.3.6 vue-awesome-swiper ==
- main.js
import VueAwesomeSwiper from 'vue-awesome-swiper'
// import style
import 'swiper/css/swiper.css'
Vue.use(VueAwesomeSwiper, /* { default options with global component } */)
- 组件中使用:(结合npm对应插件文档和swiper官方API使用)
<template>
<div class="box">
<swiper ref="mySwiper" :options="swiperOptions">
<swiper-slide>
<div class="my-slide">1</div>
</swiper-slide>
<swiper-slide><div class="my-slide">2</div></swiper-slide>
<swiper-slide><div class="my-slide">3</div></swiper-slide>
<swiper-slide><div class="my-slide">4</div></swiper-slide>
<swiper-slide><div class="my-slide">5</div></swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
</swiper>
</div>
</template>
<script>
export default {
name: "carrousel",
data() {
return {
swiperOptions: {
pagination: {
el: ".swiper-pagination",
clickable:true
},
autoplay: {
delay: 2000,//延迟时间
stopOnLastSlide: false,
disableOnInteraction: true
}
}
};
},
mounted() {}
};
</script>
<style>
.box {
margin: 0 auto;
background: #e3e3e3;
width: 300px;
height: 300px;
}
.my-slide{
width: 300px;
height: 300px;
}
</style>