vue.js零基础入门到vue项目入土
- VUE2.0——VUE3.0系列第一章
- 1. 初识vue
- 2. Vue拦截原理
- 3.vue 模版语法
- 4. todolist 案例
- 5. v-html指令
- 6. 点击变色
- 7. vue2 class&style
- 8. Vue3支持动态增加属性的拦截
- 9. 条件渲染
- 10. 列表渲染
- 11. key 设置
- 12. 检测测数组变动
- 13. 模糊查询
- 14. 事件处理器
- 15. 事件修饰符
- 16. 按键修饰符
- 17. 表单控件绑定
- 18. 购物车案例
- 19. 表达修饰符
- 20. 计算属性
- 21. 改造案例—计算属性
- 22. watch 侦听器
- 23. fetch-get
- 24. fetch-post
- 25. fetch-应用
- 26. axios
- 27. 猫眼数据
- 28. filter 过滤器
- 29. 组件定义 Component
- 30. 全局&局部组件
- 31. 父传子
- 32. 属性验证&默认属性
- 33. 子传父场景
- 34. 子传父实现
- 35. 中间人模式
- 36. 中央事件总线
- 37. ref组件通信
- 38. 组件注意
- 39. 动态组件
VUE2.0——VUE3.0系列第一章
1. 初识vue
Vue (读音Nju/,类似于view)是-套用于构建用户界面的渐进式框架。与其它大型框架不同的是,
Vue被设计为可以自底向上逐层应用。Wue 的核心库只关注视图层,不仅易于上手,还便于与第三方
库或既有项目整合。另-方面,当与现代化的工具链以及各种支持类库结合使用时,Wue 也完全能
够为复杂的单页应用提供驱动。
Vue.js 起步
每个 Vue 应用都需要通过实例化 Vue 来实现。
语法格式如下:
var vm = new Vue({
// 选项
})
引入Vue
状态案例:
<div class="box">
{{10+20}}
</div>
<div>
{{10+20}}
</div>
<script>
new Vue({
el:"box"
data:{
myname:"kerwin" //状态
}
})
</script>
可以看到在 Vue 构造器中有一个el 参数,它是 DOM 元素中的 id。在上面实例中 id 为 box,在 div 元素中:
<div id = "box"></div>
这意味着我们接下来的改动全部在以上指定的 div 内,div 外部不受影响。
data 用于定义属性
{{ }} 用于输出对象属性和函数返回值。
2. Vue拦截原理
如何追踪变化:
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
2.1 Object.defineProperty
注意: vue3的变化
Object.defineProperty有以下缺点。
- 1、无法监听es6的Set、Map变化;
- 2、无法监听Class类型的数据;
- 3、属性的新加或者删除也无法监听;
- 4、数组元素的增加和删除也无法监听。
针对0bject.defineProperty的缺点,ES6 Proxy都能够完美得解决,它唯一的缺
点就是,对正不友好,所以vue3在检测到如果是使用E的情况下(没错,IE11都不
支持Proxy)。会自动降级为0bject.defineProperty的数据监听系统。
案例:
<div class="box">
</div>
<script>
var obj ={}
var obox = document.getElementById("box")
Object.defineProperty(obj,"myname",{
get(){//访问时,走get
console.log("get")
return obox.innerHTML
},
set(){//修改时,走set
console.log("set",value)
obox.innerHTML = value
}
})
</script>
3.vue 模版语法
Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。
在底层机制中,Vue 会将模板编译成高度优化的 JavaScript 代码。结合响应式系统,当应用状态变更时,Vue 能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的 DOM 操作。
methods 用于定义的函数,可以通过 return 来返回函数值。
3.1 @事件
<div class="box">
{{myname}}- {{myage}}
<button @click="handleChange()">change</button>
</div>
<script>
new Vue({
el:"#box",
data:{
myname:"kerwin",
myage:100
},
//方法
mythods:{
handeleChannge(){
console.log("handleChange",this)
this.myname="tiechui"
this.myage = "18"
}
}
})
</script>
点击后,
3.2 指令
在Vue中,可以使用v-bind指令来实现动态绑定。因为这个指令使用的较多,所有Vue也为我们提供了语法糖,v-bind的语法糖为:
。通过v-bind绑定的属性即和 data中的属性相绑定。
指令用于在表达式的值改变时,将某些行为应用到 DOM 上。
指令:是带有V-前缀的特殊属性
v-bind动态绑定属性
v-if动态创建/删除
v-show动态显示/隐藏
v-on:click绑定事件
v-for遍历
v-model双向绑定表单
(3)缩写
v-bind:src => :src
v-on:click => @click
3.3 :class
:class
(v-bind:class 的缩写) 传递一个对象来动态切换 class
v-bind
可以动态的绑定属性,那么我们就可以把标签的class属性与data里面的某个属性绑定起来,后期可以通过函数的方式,增加或者减少样式。对象里面的数据都是键值对的形式,因此我们也可以通过键值对的新式来决定我们的样式,键:即我们的类型 值:这里是布尔值。即决定这个类是否加入到这个标签中。而后面的值我们又可以通过 data 里面的属性来决定真假。
<div class="box">
{{myname}}- {{myage}}
{{10>20?'aaa':'bbb'}}
<div :class="whichcolor">切换背景色111</div>
<div :class="isColor?'red':'yellow'">切换背景色222</div>
<button @click="handleChange()">change</button>
</div>
<script>
new Vue({
el:"#box",
data:{
myname:"kerwin",
myage:100,
whichcolor:'red',
isColor:true
},
//方法
mythods:{
handeleChannge(){
console.log("handleChange",this)
this.myname="tiechui"
this.myage = "18"
this.whichcolor = "yellow"
this.isColor= !this.isColor
}
}
})
</script>
定义了handleChange()方法事件,通过点击可以触发方法里的,动态切换 class——三目运算符,以此达到颜色切换的效果。
3.4 v-show:根据表达值的真假,切换元素的显示和隐藏
- ◆v-show指令的作用是:根据真假切换元素的显示状态
- ◆原理是修改元素的display,实现显示隐藏
- ◆指令后面的内容最终都会解析为布尔值
- ◆值为true元素显示,值为false元素隐藏
- ◆数据改变之后,对应元素的显示状态会同步更新
v-show 本质是切换元素的 display
<div id="app">
<input type="button" value="切换显示状态" @click="changeIsShow"><br>
<img v-show="isShow" src="img/monkey.png" alt="">
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isShow: false,
},
methods: {
changeIsShow: function () {
this.isShow =! this.isShow;
}
}
})
</script>
3.5 v-if
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。
v-if指令的作用是:根据表达式的真假切换元素的显示状态
本质是通过操纵dom元素来切换显示状态
表达式的值为true,元素存在于dom树中,为false,从dom树中移除
频繁的切换v-show,反之使用v-if,前者的切换消耗小
<div id="app">
<input type="button" value="切换显示" @click="toggleIsShow">
<p v-if="isShow">兮动人</p>
<p v-show="isShow">兮动人 v-show 修饰</p>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isShow: false
},
methods: {
toggleIsShow: function () {
this.isShow = !this.isShow;
}
}
})
</script>
点击切换
3.6 v-for
循环使用 v-for 指令。
v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组并且 site 是数组元素迭代的别名。
v-for 可以绑定数据到数组来渲染一个列表:
<div id="app">
<ol>
<li v-for="site in sites">
{{ site.name }}
</li>
</ol>
</div>
<script>
new Vue({
el: '#app',
data: {
sites: [
{ name: 'Runoob' },
{ name: 'Google' },
{ name: 'Taobao' }
]
}
})
</script>
也可以提供第二个的参数为键名或索引,当第二个是键名时提供第三个的参数为索引。
3.7 v-model 双向绑定表单
v-model作为双向绑定指令也是vue两大核心功能之一,使用非常方便,提高前端开发效率。在view层,model层相互需要数据交互,即可使用v-model。
v-model指令的原理是什么?
- v-bind绑定一个value属性
- v-on监听当前元素的input事件,当数据变化时,将值传递给value实时更新数据
v-model和v-bind:value有什么区别?
自定义组件中,必定会使用v-bind指令来实现组件之间值的传递,所以在我还是菜鸟的那段时间,我一直有个疑惑,既然有的v-bind指令,为什么还需要在自定义的组件中实现v-model指令呢?
v-model既能够实现值的传递,也能够实现页面数据的实时变化,而v-bind只是实现值的传递,如果需要实现实时变化的效果,需要使用另外的方法修改变量的值
- v-model实现视图和数据的双向绑定,一者变化另一者也会同时变化
- v-bind只会在初始化的时候将数据绑定到视图上,后续视图变化不会影响数据
4. todolist 案例
<script src="./vue.js/vue2.js "></script>
<div id="box">
<!--双向绑定了一个输入框的value -->
<input type="text" v-model="mytext" />
<!-- {{mytext}} -->
<button @click="handleAdd()">add</button>
<ul v-show="datalist.length">
<li v-for="(data,index) in datalist">
{{data}}
<button @click="handeleDel()">del</button>
</li>
</ul>
<!-- 当被删除完之后显示空空如也-->
<div v-show="!datalist.length">待办事项空空如也</div>
</div>
<script>
var vm = new Vue({
el: "#box",
data: {
datalist: ["1111", "2222", "3333"],
mytext: "aaaaa"
},
methods: {
handleAdd() {
// console.log("获取value",this.mytext)
this.datalist.push(this.mytext)
//清空输入框的value
this.mytext = " "
},
handeleDel(index) {
console.log("del", index)
this.datalist.splice(index, 1)//删除数组元素
}
}
})
</script>
5. v-html指令
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,需要使用 v-html 指令:
<div id="box">
{{mytext}}
</div>
<div v-html = "mytext"></div>
<script>
new Vue({
el:"#box"
data:{
mytext:"<b>加粗的</b>"
}
})
</script>
注意,不能使用 v-html 来复合局部模板,因为 Vue 不是基于字符串的模板引擎。反之,对于用户界面 (UI),组件更适合作为可重用和可组合的基本单位。
站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
6. 点击变色
思路:通过当前点击事件,利用三目运算符,current和每一项的索引进行对比,每次改变都会进行重新对比一遍。
注意:一点要加:
,实现动态
<style>
*{
margin:0;
padding:0;
}
ul{
display:flex;
list-style:none;
}
li{
flex:1;
height:50px;
line-height:50px ;
text-align:center;
}
.active{
background:green;
}
</style>
<div id="box">
<ul>
<li v-for = "(data,index) in datalist" :class="current === index?'active':'' " @click = "handleClick(index) ">
{{data}}
</li>
</ul>
</div>
<script>
new Vue({
el:"#box"
data:{
datalist:["首页","列表","我的"],
current:0
},
methods:{
handeleClick(index){
conosle.log(index)
this.current = index
}
}
})
</script>
7. vue2 class&style
7.1 动态切换:class-对象写法
多元class的填入和删除的切换
<style>
.red{
background:red;
}
.yellow{
background: yellow;
}
.aa{}
.bb{}
.cc{}
.dd{}
</style
<div id="box">
<div :class="classobj">动态切换class-1-对象</div>
</div>
<script>
var nm = new Vue({
el:"box",
data:{
classobj:{
aa:true,
bb:true,
cc:false
}
}
})
</script>
添加初始化属性之外的dd
但是vue不会管后期加上的属性,所以不会拦截去使用
vue2 解决方案:Vue.set(对象,属性,true)
通过set方法拦截新加的
vue2 的bug——无法侦听到某个对象中的某个属性临时加上或者临时被删掉,侦听不到就无法进行更新操作
vue3 支持动态增加属性的拦截
7.2 动态切换:class-数组写法
<style>
.red{
background:red;
}
.yellow{
background: yellow;
}
.aa{}
.bb{}
.cc{}
.dd{}
</style
<div id="box">
<div :class="classobj">动态切换class-1-对象</div>
<div :class="classarr">动态切换class-2-数组</div>
</div>
<script>
var nm = new Vue({
el:"box",
data:{
classobj:{
aa:true,
bb:true,
cc:false
},
classarr:["aa","bb"]
}
})
</script>
这实际上是重写了数组,是侦听不到添加的
7.3 动态切换:style-对象写法
<style>
.red{
background:red;
}
.yellow{
background: yellow;
}
.aa{}
.bb{}
.cc{}
.dd{}
</style
<div id="box">
<div :class="classobj">动态切换class-1-对象</div>
<div :class="classarr">动态切换class-2-数组</div>
<div :style="styleobj">动态切换class-2-数组</div>
</div>
<script>
var nm = new Vue({
el:"box",
data:{
classobj:{
aa:true,
bb:true,
cc:false
},
classarr:["aa","bb"],
styleobj:{
background:red;
}
}
})
</script>
不是初始化的属性,添加不上
解决方案:
和上面解决动态切换class对象的一样
7.4 动态切换:style-数组写法
<style>
.red{
background:red;
}
.yellow{
background: yellow;
}
.aa{}
.bb{}
.cc{}
.dd{}
</style
<div id="box">
<div :class="classobj">动态切换class-1-对象</div>
<div :class="classarr">动态切换class-2-数组</div>
<div :style="styleobj">动态切换class-2-对象</div>
<div :style="styleobj">动态切换class-2-数组</div>
</div>
<script>
var nm = new Vue({
el:"box",
data:{
classobj:{
aa:true,
bb:true,
cc:false
},
classarr:["aa","bb"],
styleobj:{
background:red;
},
stylearr:[{backgroundColor:"yellow"}]
}
})
</script>
解决同理上面class的数组
8. Vue3支持动态增加属性的拦截
支持动态增加属性的拦截
语法:Vue.createApp(obj).mout(“#box”)
<div id="box">
{{10+20}}
{{myname}}
{{mytext}}
<input type="text" v-model="mytext">
<button @click="handleAdd">add</button>
<div :class="classobj">动态切换class-对象</div>
</div>
<script src="E:\vue.js\vue.global.js"></script>
<script>
//vue2
// new Vue({
// el:"#box"
// data:{myname:"zzy"}
// }) vue 不是一个构造函数
//vue3
var obj = {
data() {
//函数式,防止互相影响,当有两个组件时可以定义相同的名字
return {
myname: "van",
mytext: "",
classobj: {
aa: true,
bb: true,
cc: false,
}
}
},
methods: {
handleAdd() {
console.log("add", this.mytext)
this.classobj.dd = true
}
}
}
Vue.createApp(obj).mount("#box")
</script>
9. 条件渲染
v-if :当满足条件的时候进行表达
v-else-if :未达到之前的条件,如果达到这个条件就执行这段代码
v-else:前面的条件都未达到就执行该代码
<script src="E:\vue.js\vue2.js"></script>
<h2>所有订单</h2>
<ul>
<li v-for="item in datalist">
{{item.title}}--
<span v-if="item.state===0">未付款</span>
<span v-if="item.state===1">待发货</span>
<span v-if="item.state===3">已发货</span>
</li>
</ul>
<script>
var vm = new Vue({
el:"#box",
data:{
isCreated:false,
datalist:[
{
title:"11111",
state:0
},
{
title:"22222",
state:1
},
{
title:"33333",
state:2
}
]
}
})
</script>
9.1 template:包装元素,不会真正创建在页面上
当template消失或出现时,也不会影响box的结构
<script src="E:\vue.js\vue2.js"></script>
<div id="box">
<template v-if="isCreated">
<div>1111111111</div>
<div>2222222222</div>
<div>3333333333</div>
</template>
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
isCreated:false
}
})
</script>
10. 列表渲染
在进行对象渲染的时候,要用 Vue.set(obj,属性,true),不用这个网页就获取不到结点
1.
<div id="box">
<ul>
<li v-for="item of datalist">
{{item}}
</li>
</ul>
<ul>
<li v-for="(item,key) of obj">
{{key}}--{{item}}
</li>
</ul>
<ul>
<li v-for="item in 10">
{{item}}
</li>
</ul>
</div>
<script>
new Vue({
el: "#box",
data: {
datalist: ["111", "222", "333"],
obj:{
name:"van",
age:"100",
location:"dalian"
}
}
})
</script>
11. key 设置
创建一个真dom的代价——会有很多用不到的属性,当数据庞大时,代价就更加可怕
而虚拟dom就可以抽出需要的属性进行使用
创建虚拟dom节点,每个key值对应删除,以最小的代价:
用索引值删除的话,如果数据需要从中间删除,那么索引删除就要从头开始
<ul>
<li v-for='item in datalist' :key="item.id">
{{item.title}}--
<span v-if="item.state===0">未付款</span>
<span v-if="item.state===1">待发货</span>
<span v-if="item.state===3">已发货</span>
</li>
</ul>
<script>
var vm = new Vue({
el:"#box",
data:{
isCreated:false,
datalist:[
{
id :1,
title:"11111",
state:0
},
{
id:2,
title:"22222",
state:1
},
{
id:3,
title:"33333",
state:2
}
]
}
})
</script>
12. 检测测数组变动
vue3可以通过返回数组的方式实现
<script src="E:\vue.js\vue3.js"></script>
<div id="box">
<ul>
<li v-for="(item,index) of datalist" :key="item">
{{item}}--{{index}}
</li>
</ul>
<ul>
<li v-for="(item,key) of obj">
{{key}}--{{item}}
</li>
</ul>
<ul>
<li v-for="item in 10">
{{item}}
</li>
</ul>
</div>
<script>
var vm = Vue.createApp({
data() {
return {
datalist: ["111", "222", "333"],
obj: {
name: "van",
age: "100",
location: "dalian"
}
}
}
}).mount("#box")
</script>
13. 模糊查询
一、用老数组复制新数组,过滤老数组
老数组永远不会受到影响
缺点:占内存
<script src="E:\vue.js\vue2.js"></script>
<div id="box">
<input type="text" @input="handleInput" v-model="mytext"/>
<ul>
<li v-for="data in datalist" :key="data">
{{data}}
</li>
</ul>
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
mytext:"",
datalist:["aaa","add","bbbb","ccdc","dbdd"],
originList:["aaa","add","bbbb","ccdc","dbdd"]
},
methods:{
handleInput(){
console.log("input",this.mytext)
this.datalist = this.originList.filter(item=>item.
includes(this.mytext))
}
}
})
</script>
二、v-for 中in表达式方法,返回过滤
text方法中用到mytext,因为mytext改变了,text()也会改变,由于拦截,方法就会重新执行一遍。
当a来时,就重新过滤出a
<script src="E:\vue.js\vue2.js"></script>
<div id="box">
<input type="text" v-model="mytext"/>
<ul>
<li v-for="data in test()" :key="data">
<!-- 在遍历中放test()表达式,表达式返回datalist -->
{{data}}
</li>
</ul>
<!-- {{test()}} -->
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
mytext:"",
datalist:["aaa","add","bbbb","ccdc","dbdd"]
},
methods:{
console.log("input",this.mytext)
test(){
return this.datalist.filter(item=>item.includes
(this.mytext))
}
}
})
</script>
14. 事件处理器
监听事件
我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click=“methodName” 或 @click=“handler”。
事件处理器的值可以是:
- 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与 onclick 类似)。
- 方法事件处理器:一个指向组件上定义的方法的属性名或是路径。
14.1 内联事件处理器
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>
data() {
return {
count: 0
}
}
14.2 方法事件处理器
随着事件处理器的逻辑变得愈发复杂,内联代码方式变得不够灵活。因此 v-on 也可以接受一个方法名或对某个方法的调用。
<!-- `greet` 是上面定义过的方法名 -->
<button @click="greet">Greet</button>
data() {
return {
name: 'Vue.js'
}
},
methods: {
greet(event) {
// 方法中的 `this` 指向当前活跃的组件实例
alert(`Hello ${this.name}!`)
// `event` 是 DOM 原生事件
if (event) {
alert(event.target.tagName)
}
}
}
方法事件处理器会自动接收原生 DOM 事件并触发执行。在上面的例子中,我们能够通过被触发事件的 event.target.tagName 访问到该 DOM 元素。
14.3 在内联处理器中调用方法
除了直接绑定方法名,你还可以在内联事件处理器中调用方法。这允许我们向方法传入自定义参数以代替原生事件:
<button @click="say('hello')">Say hello</button>
<button @click="say('bye')">Say bye</button>
methods: {
say(message) {
alert(message)
}
}
14.4 在内联事件处理器中访问事件参数
有时我们需要在内联事件处理器中访问原生 DOM 事件。你可以向该处理器方法传入一个特殊的 $event 变量,或者使用内联箭头函数:
<!-- 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
<!-- 使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
Submit
</button>
methods: {
warn(message, event) {
// 这里可以访问 DOM 原生事件
if (event) {
event.preventDefault()
}
alert(message)
}
}
15. 事件修饰符
Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。
顺序很重要
Vue.js 通过由点 . 表示的指令后缀来调用修饰符。
.stop - 阻止冒泡
.prevent - 阻止默认事件
.capture - 阻止捕获
.self - 只监听触发该元素的事件
.once - 只触发一次
.left - 左键事件
.right - 右键事件
.middle - 中间滚轮事件
.passive 告诉浏览器你不想阻止事件的默认行为。
// 阻止单击事件继续传播(阻止冒泡,传到父元素)
<a v-on:click.stop="doThis"></a>
//提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
//串联 -->
<a v-on:click.stop.prevent="doThat"></a>
//<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
//<!-- 添加事件监听器时使用事件捕获模式 -->
//<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
//<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
//<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
顺序问题
用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
16. 按键修饰符
keyup
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
系统修饰键
用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
.meta ——在 Windows 系统键盘 meta 对应 Windows 徽标键
.exact 修饰符
允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>
鼠标按钮修饰符
修饰符会限制处理函数仅响应特定的鼠标按钮。
.left
.right
.middle
<button @click.left="alert('你按了鼠标左击键')">按钮</button>
<button @click.middle="alert('你按了鼠标滚轮')">按钮</button>
<button @click.right="alert('你按了鼠标右击键')">按钮</button>
17. 表单控件绑定
v-model
Vue的双向绑定可以实现: 数据变化的时候, 页面会自动刷新, 页面变化的时候,数据也会自动变化.
可以用 v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元。
v-model 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是 将 Vue 实例的数据作为数据来源你应该通过 JavaScript 在组件的 data 选项中声明初始值。
v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 元素使用 value property 和 input 事件;
- checkbox 和 radio 使用 checked property 和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件。
- 文本框/单选按钮/textarea, 绑定的数据是字符串类型
- 单个复选框, 绑定的是boolean类型
- 多个复选框, 绑定的是数组
- select单选对应字符串,多选对应也是数组
18. 购物车案例
<style>
li {
display: flex;
justify-content: space-around;
padding: 10px;
}
li img {
width: 150px;
}
</style>
<script src="E:\vue.js\vue3.js"></script>
<div id="box">
<input type="checkbox" v-model="isAll" @change="handleAllChecked"/>全选/全不选
<ul>
<li v-for="(item,index) in datalist" :key="item.id"><!-- key值选中每个图片 -->
<input type="checkbox" v-model="checkList"
:value="item" @change="handleItemChecked"/><!-- value这个值当成变量,就动态绑定勾中哪一个,之前不绑定因为是手写添加的 -->
<!-- 一定要动态绑定 -->
<img :src="item.pic" />
<div>
<div>{{item.name}}</div>
<div style="color:red">¥{{item.price}}</div>
</div>
<div>
<button @click = "item.number--" :disabled="item.number===0">-</button>
<span>{{item.number}}</span>
<button @click = "item.number++" :disabled="item.number===item.limit">+</button>
<!-- 这样写的好处:改变了每个数据列表的number,同时也刷新了每个数据对象,所以当勾选checkbox、修改number时,总金额会重新计算 -->
</div>
<div>
<button @click="handleDeleteClick(index,item.id)">delete</button>
</div>
</li>
</ul>
<div>总金额:{{sum()}}</div>
{{checkList}}
</div>
<script type="text/javascript">
var obj = {
data() {
return {
isAll:false,
checkList: [],//勾选购物车的数据
datalist: [{
name: "商品1",
number: 1,
price: 10,
id: 1,
limit: 5,//限购
pic: "https://gw.alicdn.com/imgextra/i1/69161977/O1CN01d4WK4m1QTVpTFNAgA_!!69161977-0-alimamacc.jpg_300x300q90.jpg_.webp"
},
{
name: "商品2",
number: 2,
price: 20,
id: 2,
limit: 10,
pic: "https://gw.alicdn.com/imgextra/i4/1600687454/O1CN01zEwJAu24vz5Dfi8Wh_!!0-item_pic.jpg_Q75.jpg_.webp"
},
{
name: "商品3",
number: 3,
price: 30,
id: 3,
limit: 15,
pic: "https://g-search3.alicdn.com/img/bao/uploaded/i4/i3/3017094217/O1CN01ODeYOe1h1R16GpeMV_!!0-item_pic.jpg_580x580Q90.jpg_.webp"
}
]
}
},
methods: {
//累加计算checkList数组的每一项的价格*数量
sum() {
var total = 0
this.checkList.forEach(item => {
total += item.price * item.number
})
return total
},
handleDeleteClick(index,id){
// conosle.log(index)
//删除的是datalist-靠索引
this.datalist.splice(index,1)
//这样利用索引值删掉了item,但是无法用相通的索引值匹配checklist,所以总金额无法也做到删除
// console.log(id)
//删除checkList - 靠item的id
this.checkList = this.checkList.filter(item=>item.id!==id)
//过滤,当删除的是2,id传过来2,item.id与2对比。当有item.id不为2的时,过滤出来,刷新不为2的。剩下与2匹配的checklist倒霉蛋就被删去了
//同步一下状态
this.handleItemChecked()
},
//全选
handleAllChecked(){
if(this.isAll){
this.checkList = this.datalist
}else{
this.checkList=[]
}
},
//每项选择
handleItemChecked(){
if(this.checkList.length===this.datalist.length){
// console.log("全选")
this.isAll = true
}else{
// console.log("未全选")
this.isAll = false
}
}
}
}
Vue.createApp(obj).mount("#box")
</script>
19. 表达修饰符
- .lazy 失去焦点时显示输入的
- .number 把传出来的字符串换成数字(最后只有数字)
- .trim 去除首尾空格
20. 计算属性
<div id="box">
{{ myname.substring(0,1).toUpperCase() + myname.substring(1) }}
{{ myComputedName }}
{{ myComputedName }}
{{ myComputedName }}
{{ myMethodName() }}
{{ myMethodName() }}
{{ myMethodName() }}
</div>
<script>
//计算属性(防止模板过重,难以维护),负责逻辑放在计算属性中来写。
// 计算属性 有缓存, 基于依赖的缓存
var vm = new Vue({
el: "#box",
data: {
myname: "van",
},
//方法:
methods: {
myMethodName() {
console.log("myMethodName-方法")
return this.myname.substring(0, 1).toUpperCase() + this.myname.substring(1)
}
},
//计算的
computed: {
myComputedName() {
console.log("myMethodName-计算属性")
return this.myname.substring(0, 1).toUpperCase() + this.myname.substring(1)
}
}
})
/*
</script>
- data => 状态,被拦截。
- 方法==》 事件绑定, 逻辑计算。可以不用return,没有缓存
- 计算属性(重视结果)=》 解决模板过重问题,必须有return ,只求结果 ,有缓存,同步。
- watch (重视过程), 监听一个值的改变。 不用返回值 ,异步同步
21. 改造案例—计算属性
var app = new Vue({
el:"#app",
//计算属性必须放在Vue的computed中
computed:{
//定义计算属性
属性名(){
return "返回值";
}
}
});
<style>
li {
display: flex;
justify-content: space-around;
padding: 10px;
}
li img {
width: 150px;
}
</style>
<script src="E:\vue.js\vue3.js"></script>
<div id="box">
<input type="checkbox" v-model="isAll" @change="handleAllChecked" />全选/全不选
<ul>
<li v-for="(item,index) in datalist" :key="item.id"><!-- key值选中每个图片 -->
<input type="checkbox" v-model="checkList" :value="item"
@change="handleItemChecked" /><!-- value这个值当成变量,就动态绑定勾中哪一个,之前不绑定因为是手写添加的 -->
<!-- 一定要动态绑定 -->
<img :src="item.pic" />
<div>
<div>{{item.name}}</div>
<div style="color:red">¥{{item.price}}</div>
</div>
<div>
<button @click="item.number--" :disabled="item.number===0">-</button>
<span>{{item.number}}</span>
<button @click="item.number++" :disabled="item.number===item.limit">+</button>
<!-- 这样写的好处:改变了每个数据列表的number,同时也刷新了每个数据对象,所以当勾选checkbox、修改number时,总金额会重新计算 -->
</div>
<div>
<button @click="handleDeleteClick(index,item.id)">delete</button>
</div>
</li>
</ul>
<div>总金额:{{computedSum()}}</div>
{{checkList}}
</div>
<script type="text/javascript">
var obj = {
computedSum() {
//累加计算checkList数组的每一项的价格*数量
var total = 0
this.checkList.forEach(item => {
total += item.price * item.number
})
return total
},
data() {
return {
isAll: false,
checkList: [],//勾选购物车的数据
datalist: [{
name: "商品1",
number: 1,
price: 10,
id: 1,
limit: 5,//限购
pic: "https://gw.alicdn.com/imgextra/i1/69161977/O1CN01d4WK4m1QTVpTFNAgA_!!69161977-0-alimamacc.jpg_300x300q90.jpg_.webp"
},
{
name: "商品2",
number: 2,
price: 20,
id: 2,
limit: 10,
pic: "https://gw.alicdn.com/imgextra/i4/1600687454/O1CN01zEwJAu24vz5Dfi8Wh_!!0-item_pic.jpg_Q75.jpg_.webp"
},
{
name: "商品3",
number: 3,
price: 30,
id: 3,
limit: 15,
pic: "https://g-search3.alicdn.com/img/bao/uploaded/i4/i3/3017094217/O1CN01ODeYOe1h1R16GpeMV_!!0-item_pic.jpg_580x580Q90.jpg_.webp"
}
]
}
},
methods: {
handleDeleteClick(index, id) {
// conosle.log(index)
//删除的是datalist-靠索引
this.datalist.splice(index, 1)
//这样利用索引值删掉了item,但是无法用相通的索引值匹配checklist,所以总金额无法也做到删除
// console.log(id)
//删除checkList - 靠item的id
this.checkList = this.checkList.filter(item => item.id !== id)
//过滤,当删除的是2,id传过来2,item.id与2对比。当有item.id不为2的时,过滤出来,刷新不为2的。剩下与2匹配的checklist倒霉蛋就被删去了
//同步一下状态
this.handleItemChecked()
},
//全选
handleAllChecked() {
if (this.isAll) {
this.checkList = this.datalist
} else {
this.checkList = []
}
},
//每项选择
handleItemChecked() {
if (this.checkList.length === this.datalist.length) {
// console.log("全选")
this.isAll = true
} else {
// console.log("未全选")
this.isAll = false
}
}
}
}
Vue.createApp(obj).mount("#box")
</script>
22. watch 侦听器
Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
- watch可以监听简单属性值及其对象中属性值的变化.
- watch类似于onchange事件,可以在属性值修改的时候,执行某些操作.
<div id="box">
<!-- input change事件区别 -->
<input type="text" v-model="mytext" />
<ul>
<li v-for="data in datalist" :key="data">
{{data}}
</li>
</ul>
</div>
<script>
var vm = new Vue({
el: "#box",
data: {
mytext: "",
datalist: ["aaa", "add", "bbb", "bbc", "ccc", "ddd", "eee", "ade"],
originList: ["aaa", "add", "bbb", "bbc", "ccc", "ddd", "eee", "ade"]
},
watch: {
mytext(newval) {
console.log("改变了", newval)
setTimeout(() => {
this.datalist = this.originList.filter(item => item.includes(newval))
}, 1000)
}
}
})
</script>
23. fetch-get
<script src="./vue.js/vue2.js"></script>
<div id="box">
<button @click="handleFetch">ajax-fetch</button>
</div>
<script>
new Vue({
el: "#box",
data: {
},
methods:{
handleFetch(){
//http://127.0.0.1:5500/json/text.json
//在同一个端口号,同一个域名下可以省略
fetch("./json/text.json")
.then(res=>{
// console.log(res)拿到是是状态码,响应头,拿不到真正的数据
return res .text()
}).then(res=>{
console.log(JSON.parse(res))
})
.catch(err=>{
console.log(err)
})
}
}
})
</script>
2.用text()方法时,要JOSN.parse()化,不然得到的是字符串
24. fetch-post
get url路径 ?name=kerwin&age=100
post body请求体,
(1) x-www-formurlencoded , name=kerwin&age=100
(2) json ,{“name”:“kerwin”,age:100}
25. fetch-应用
Fetch请求默认是不带cookie的,需要设置fetch(url, {credentials:‘include’})
<script src="./vue.js/vue2.js"></script>
<style>
li{
list-style: none;
overflow: hidden;
padding: 10px;
}
li img{
float: left;
width: 100px;
}
</style>
<div id="box">
<button @click="handleFetch">ajax-fetch11</button>
<ul>
<li v-for="data in datalist" :key="data.filmId">
<img :src="data.poster"/>
{{data.name}} <br>
{{data.grade}}
</li>
</ul>
</div>
<script>
new Vue({
el:"#box",
data:{
datalist:[]
},
methods:{
handleFetch() {
fetch("./json/maoyan.json")
.then(res=>res.json())
.then(res=>{
console.log(res.data.films)
this.datalist = res.data.films
})
.catch(err=>{
console.log(err)
})
}
}
})
</script>
26. axios
26.1 Axios是什么
Axios是一个基于promise的HTTP库(类似于jQuery的Ajax,用于HTTP请求)
可以用于浏览器和node.js(既可以用于客户端也可以用于node.js编写的服务端)
26.2 Axios有哪些特性
- 支持promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
Axios浏览器支持:
26.3 Axios基础用法
get:(一般用于)获取数据
post:提交数据(表单提交+文件上传)
put:更新(或编辑)数据(所有数据推送到后端(或服务端))
patch:更新数据(只将修改的数据推送到后端)
delete:删除数据
- (1)post:一般用于新建
- (2)put:一般用于更新(适合数据量比较少的更新)
- (3)patch:一般用于数据量比较大;假如一个表单的数据量很大,有很多项,使用put的话,全部数据推送一次是比较耗性能的,这个时候可以考虑用patch,只将修改的数据推送到后端
<div id="box">
<button @click="handleClick()">ajax - axios</button>
<ul>
<li v-for="data in datalist" :key="data.filmId">
<img :src="data.poster" />
<div>{{data.name}}</div>
<div>观众评分:{{data.grade}}</div>
</li>
</ul>
</div>
<script type="text/javascript">
new Vue({
el: "#box",
data: {
datalist: []
},
methods: {
handleClick() {
axios.get("./json/maizuo.json").then(res => {
// console.log()
this.datalist = res.data.data.films
})
}
}
})
/*
get url路径 ?name=zzy&age=18
post body请求体 ,
(1)x-www-formurlencoded , name=zzy&age=18
(2) json , `{"name":"zzy",age:18}`
axios.post("****","name=zzy&age=18") // (1)
axios.post("****",{name:"zzy",age:18}) //(2)
*/
</script>
27. 猫眼数据
27.1分析猫眼的请求
比如这里,获取猫眼在搜索一部电影时,自动返回匹配搜索字段的数据,通过分析,右侧蓝色为请求的部分,其中 search?kw… 开头的字段都是我在测试是否为实时请求数据的响应,可以看到 kw= 为你的输入值,cityId= 为你的城市值
双击这个请求可以打开具体的链接,这里我是用了 FE 这个插件来便于我们讲 json 数据解析,可以看到搜索栏就是我们要的答案
27.2 配置 vue.config.js 文件
在 vue 项目中要实现这个跨域,可以利用反向代理,这里要先配置 vue.config.js 文件
module.exports = {
devServer: {
proxy: {
// /ajax 为你请求的方式,理论上是后端暴露给你的,这里猫眼使用 /ajax 的方式
'/ajax': {
// target 为 url 中 /ajax 前面的请求网址的部分
target: 'https://m.maoyan.com/',
// 实现反向代理
changeOrigin: true
},
}
}
}
27.3 使用 axios 进行请求
vue 中常使用 axios 进行网络请求,newVal 为我实时搜索的数据,每次在输入框输入不同的值时,newVal 获取到这个值,传到我的请求中,就可以发起网络请求
this.axios.get(`/ajax/search?kw=${newVal}&cityId=1&stype=-1`).then((res)=>{
console.log(res);
})
案例:
<body>
<script src="E:\axios.js\axios.js"></script>
<div id="box">
<button @click="handleAjax">click-ajax</button>
<ul>
<li v-for="item in datalist" :key="item.id">
<img :src="handleImg(item.img)"/>
{{item.nm}}
</li>
</ul>
</div>
<script >
new Vue({
el:"#box",
data:{
datalist:[]
},
methods:{
handleAjax(){
axios.get("./json/maoyan.json").then(res=>{
console.log(res.data.movieList)
this.datalist = res.data.movieList
//for 处理
})
},
handleImg(url){
return url.replace('w.h/','')+'@1l_1e_1c_128w_180h'
}
}
})
</script>
</body>
28. filter 过滤器
vue3不支持
|
管道符
a|
b把a通过管道送到过滤器b里
定义过滤器
29. 组件定义 Component
组件可以扩展 HTML 元素,封装可重用的代码。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
tagName 为组件名,options 为配置选项。
注册后,我们可以使用以下方式来调用组件: 所有实例都能用全局组件。 prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。
组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成层层嵌套的树状结构:
这和我们嵌套 HTML 元素的方式类似,Vue 实现了自己的组件模型,使我们可以在每个组件内封装自定义内容与逻辑。
29.1 组件基础
组件是可复用的 Vue 实例,且带有一个名字。
组件把css、js、html包裹起来
组件注册
组件与其他是隔离的
css只能写在行内
一个组件的 data 选项
必须是一个函数
使用 kebab-case(短横线分隔命名),在html中
使用 pascalCase (驼峰 ),在js中
dom片段没有高亮,代码没有提示----用单文件组件解决
- // 1.起名字:js驼峰,html 链接符-
- // 2. dom片段没有代码提示没有高亮显示- vue单文件组件解决
- // 3. css只能写成行内。- vue单文件组件解决
- // 4. template包含一个根节点
- // 5.组件是孤岛,无法【直接】访问外面的组件的状态或者方法。-间接的组件通信来交流。
- // 6.自定义的组件data必须是一个函数,
- //7.所有的组件都在一起,太乱了— vue单文件组件解决
<script src="./vue.js/vue2.js"></script>
<div id="box">
<van-navbar></van-navbar>
<van-navbar></van-navbar>
<van-navbar></van-navbar>
</div>
<script>
//定义一个全局的组件
Vue.component("vanNavbar", {
//dom,js,css
template:
`<div style="background:red;">
aaaa
<button @click="handleLeft">left</button>
猫眼电影-{{myname}}
<button @click="handleRight">right</button>
</div>`,
methods: {
handleLeft() {
console.log("left")
},
handleRight() {
console.log("right")
}
},
computed:{},
watch:{},
//data必须是函数写法
data(){
return{
myname:"1111"
}
}
})
new Vue({
el: "#box",
})
</script>
30. 全局&局部组件
全局注册
定义组件vue.component(“名字” ,{})
组件名是 Vue.component 的第一个参数。
<script src="./vue.js/vue2.js"></script>
<div id="box">
<van-navbar></van-navbar>
<child></child>
</div>
<script>
//定义一个全局的组件
Vue.component("vanNavbar", {
//dom,js,css
template:
`<section style="background:red;border:5px solid black;">
<button @click="handleLeft">left</button>
猫眼电影-{{myname}}
<button @click="handleRight">right</button>
<child></child>
<van-child></van-child>
</section>`,
methods: {
handleLeft() {
console.log("left")
},
handleRight() {
console.log("right")
}
},
computed: {},
watch: {},
//data必须是函数写法
data() {
return {
myname: "1111"
}
},
//局部
components: {
"vanChild": {
template: `
<div>child-{{myname}}</div>
`,//报错原因是定成了局部的了,里面用没问题,但是外面用就不行
data(){
return {
myname:"child-1111"
}
}
}
}
})
//也是全局的组件
Vue.component("child", {
template: `
<div style="background:yellow">公司标语</div>
`
})
//根组件
new Vue({
el: "#box",
data: {
}
})
</script>
31. 父传子
在 Vue 中,父子 组件 的关系可以总结为 prop 向下传递,事件向上传递。 父 组件 通过 prop 给子 组件 下发数据,子 组件 通过事件给父 组件 发送消息。
1.
<script src="./vue.js/vue2.js"></script>
<div id="box">
<div style="background: yellow;">根组件标题</div>
<navbar myname="电影" :myright="false"></navbar>
<navbar myname="影院" :myright="true"></navbar>
</div>
<script>
Vue.component("navbar",{
props:["myname","myright"],//孩子接受myname属性, this.myname
template:`
<div>
<button>left</button>
<span>{{myname}}</span>
<button v-show="myright">right</button>
</div>
`
})
new Vue({
el:"#box"
})//创建根组件
</script>
2.
<script src="./vue.js/vue2.js"></script>
<div id="box">
<div style="background: yellow;">根组件标题</div>
<navbar myname="电影" :myright="false" :myparent="parent"></navbar>
<navbar myname="影院" :myright="true" :myparent="parent"></navbar>
</div>
<script>
Vue.component("navbar",{
// props:["myname","myright"],//孩子接受myname属性, this.myname
// props:{
// myname:String,
// myright:Boolean
// },//接受myname属性,属性验证
props:{
myname:{
type:String,
default:""
},
myright:{
type:Boolean,
default:true
},
myparent:{
type:String,
default:""
}
},//接受myname属性,属性验证,默认属性
template:`
<div>
<button>left</button>
<span>{{myname}}--{{myparent}}</span>
<button v-show="myright">right</button>
</div>
`
})
new Vue({
el:"#box",
data:{
parent:"1111111111"
}
})//创建根组件
</script>
32. 属性验证&默认属性
自定义属性验证值
v-bind来管理的属性后面跟着的双引号中写数字才能正确的表示数字类型,没有被Vue管理的属性,无论写什么内容都一定是string类型。
<script src="./vue.js/vue2.js"></script>
<div id="box">
<div style="background: yellow;">根组件标题</div>
<navbar myname="电影" :myright="false"></navbar>
<navbar myname="影院" :myright="true"></navbar>
</div>
<script>
Vue.component("navbar",{
// props:["myname","myright"],//孩子接受myname属性, this.myname
// props:{
// myname:String,
// myright:Boolean
// },//接受myname属性,属性验证
props:{
myname:{
type:String,
default:""
},
myright:{
type:Boolean,
default:true
}
},//接受myname属性,属性验证,默认属性
template:`
<div>
<button>left</button>
<span>{{myname}}</span>
<button v-show="myright">right</button>
</div>
`
})
new Vue({
el:"#box"
})//创建根组件
</script>
33. 子传父场景
vue子组件向父组件传值的方法:
1、子组件主动触发事件将数据传递给父组件。
2、子组件中绑定ref,且定义一个父组件可直接调用的函数,父组件注册子组件后绑定ref,调用子组件的函数获取数据。
<script src="./vue.js/vue2.js"></script>
<div id="box">
<navbar ></navbar>
<sidebar v-show="isShow" ></sidebar>
</div>
<script>
Vue.component("navbar", {
template: `
<div style="background-color: red;">
<button @click="handleClick()">点击</button>-导航栏
</div>
`,
methods:{
handleClick(){
console.log("子传父, 告诉父组件 ,取反您的isShow")
}
}
})
Vue.component("sidebar", {
template: `
<div style="background-color: yellow;" >
<ul>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
</ul>
</div>
`
})
new Vue({
el: "#box",
data: {
isShow: true
}
})
</script>
34. 子传父实现
在vue中,“$ emit”用于触发当前实例上的事件,附近参数都会传给监听器回调;子组件可以利用“$emit”触发父组件的自定义事件,语法为“vm. $ emit (event, args])”。
<script src="./vue.js/vue2.js"></script>
<div id="box">
<!-- 自定义了一个事件 -->
<navbar @myevent="handleEvent"></navbar>
<sidebar v-show="isShow"></sidebar>
</div>
<script>
Vue.component("navbar", {
template: `
<div style="background-color: red;">
<button @click="handleClick()">点击</button>-导航栏
</div>
`,
methods: {
handleClick() {
// console.log("子传父, 告诉父组件 ,取反您的isShow")
this.$emit("myevent",52000)
}
}
})
Vue.component("sidebar", {
template: `
<div style="background-color: yellow;" >
<ul>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
</ul>
</div>
`
})
new Vue({
el: "#box",
data: {
isShow: true
},
methods:{
handleEvent(data){
console.log("父组件的定义事件",data)
this.isShow = !this.isShow
}
}
})
</script>
35. 中间人模式
中间人模式就是两个组件通过子传父, 把数据传送给根组件, 然后根组件在把数据通过父传子传送给需要的子组件 就是 组件A和组件B通信, 组件A把数据对象data传送给根组件, 根组件接收到后, 再把数据data 传送给组件B, 根组件在这个通信过程中就叫中间人.
<script src="./vue.js/vue2.js"></script>
<style>
.item {
overflow: hidden;
padding: 10px;
width: 400px;
border: 1px solid red;
}
.item img {
width: 100px;
float: left;
}
.film {
border: 1px solid black;
height: 1500px;
}
.filminfo {
width: 300px;
min-height: 200px;
background: yellow;
position: fixed;
right: 50px;
top: 100px;
border: 1px solid blue;
}
</style>
<div id="box">
<button @click="handleAjax">ajax</button>
<film-item v-for="item in datalist" :key="item.filmId" :mydata="item" @event="handleEvent"></film-item>
<!-- {{filmData}} -->
<film-detail :film-data="filmData"></film-detail>
</div>
<script>
Vue.component("filmItem", {
props: ["mydata"],
template: `
<div class="item">
<img :src="mydata.poster"/>
{{mydata.name}}
<div>
<button @click="handleClick">详情</button>
</div>
</div>
`,
methods: {
handleClick() {
// console.log(this.mydata.synopsis)
this.$emit("event", this.mydata.synopsis)
}
}
})
Vue.component("filmDetail", {
props: ["filmData"],
template: `
<div class="filminfo">
{{filmData}}
</div>
`
})
new Vue({
el: "#box",
data: {
datalist: [],
filmData: ""
},
mounted() {
fetch("./json/maoyan.json")
.then(res => res.json())
.then(res => {
console.log(res.data.films)
this.datalist = res.data.films
})
},
methods: {
handleAjax() {
fetch("./json/maoyan.json")
.then(res => res.json())
.then(res => {
console.log(res.data.films)
this.datalist = res.data.films
})
},
//自定义事件处理器
handleEvent(data) {
console.log("父组件定义", data)
this.filmData = data
}
}
})
</script>
36. 中央事件总线
1.bus:订阅发布模式
2.vuex
组件通讯
父子组件之间传递数据子组件通过props来接受父组件传递的数据,在兄弟组件之间传递数据的话可以使用框架vuex,对于不是庞大的单页面应用就不太适合使用了,
vue 官网提供了一种方法叫做 中央事件总线
组件前进刷新,后退不刷新
vue官网给出的一个方法是通过keep-alive将router-view包住就能实现组件不刷新显示原来的数据,但是在组件中一般都是前进更新数据返回的时候不刷新保留原来的数据,增加用户体验,通过搜索发现了一个方法
<script src="./vue.js/vue2.js"></script>
<style>
.item {
overflow: hidden;
padding: 10px;
width: 400px;
border: 1px solid red;
}
.item img {
width: 100px;
float: left;
}
.film {
border: 1px solid black;
height: 1500px;
}
.filminfo {
width: 300px;
min-height: 200px;
background: yellow;
position: fixed;
right: 50px;
top: 100px;
border: 1px solid blue;
}
</style>
<div id="box">
<button @click="handleAjax">ajax</button>
<film-item v-for="item in datalist" :key="item.filmId" :mydata="item" ></film-item>
<film-detail ></film-detail>
</div>
<script>
var bus = new Vue()
//bus.$on
//bus.$emit
Vue.component("filmItem", {
props: ["mydata"],
template: `
<div class="item">
<img :src="mydata.poster"/>
{{mydata.name}}
<div>
<button @click="handleClick">详情</button>
</div>
</div>
`,
methods: {
handleClick() {
// console.log(this.mydata.synopsis)
bus.$emit("van", this.mydata.synopsis)
}
}
})
Vue.component("filmDetail", {
//组件刚刚创建好,就开始订阅
data(){
return{
info:""
}
},
//生命周期
mounted(){
//console.log("当前组件上树后触发")
bus.$on("van",(data)=>{
console.log("111111",data)
this.info = data
})
},
template:`
<div class="filminfo">
{{info}}
</div>
`
})
new Vue({
el: "#box",
data: {
datalist: [],
filmData: ""
},
mounted() {
fetch("./json/maoyan.json")
.then(res => res.json())
.then(res => {
console.log(res.data.films)
this.datalist = res.data.films
})
},
methods: {
handleAjax() {
fetch("./json/maoyan.json")
.then(res => res.json())
.then(res => {
console.log(res.data.films)
this.datalist = res.data.films
})
},
//自定义事件处理器
handleEvent(data) {
console.log("父组件定义", data)
this.filmData = data
}
}
})
</script>
37. ref组件通信
ref 是被用来给元素或子组件注册引用信息的。引用信息将会注册在父组件的 $refs 对象上
打破组件间的隔离状态
ref -绑定dom节点,拿到的就是dom对象
ref -绑定组件,拿到的就是组件对象
<script src="./vue.js/vue2.js"></script>
<div id="box">
<input type="text" ref="mytext"/>
<input type="password" ref="mypassword"/>
<div ref="mydiv">111111</div>
<button @click="handleAdd">add</button>
<child ref="mychild"></child>>
</div>
<script>
Vue.component("child",{
data(){
return{
myname:"child-1111111"
}
},
template:`
<div>
child--{{myname}}
</div>
`
})
new Vue({
el:"#box",
methods:{
handleAdd(){
console.log(this.$refs.mytext,this.$refs.mypassword,this.$refs.mydiv)
console.log(this.$refs.mychild.myname)
this.$refs.mychild.myname="child-222222"
}
}
})
</script>
38. 组件注意
props修改
- 属性-父组件传给你的属性,只有父组件可以重新传,但不允许子组件随意修改。
- 状态–组件内部的状态,可以随意修改
v-once
39. 动态组件
定义:
多个组件挂载到同一个组件上,通过参数动态的切换不同组件就是动态组件。
书写形式:
<component :is="which"></component>
该方法主要是当点击谁,谁就变为了这个动态码
内置组件:
component:是vue里面的一个内置组件。
<style>
*{
margin: 0;
padding: 0;
}
html,body{
width: 100%;
height: 100%;
}
footer ul{
display: flex;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 40px;
}
footer ul li{
flex: 1;
text-align: center;
list-style: none;
height: 40px;
line-height: 40px;
background: gray;
}
</style>
<script src="./vue.js/vue2.js"></script>
<div id="box">
<!-- <home v-show=" which=== 'home' "></home>
<list v-show=" which=== 'list' "></list>
<shopcar v-show=" which=== 'shopcar' "></shopcar> -->
<keep-alive>
<component :is="which"></component>
</keep-alive>
<footer>
<ul>
<li @click=" which='home' ">
首页
</li>
<li @click=" which='list' ">
列表
</li>
<li @click=" which='shopcar' ">
购物车
</li>
</ul>
</footer>
</div>
<script type="text/javascript">
Vue.component("home", {
template: `
<div>
home
<input type="search"/>
</div>
`
})
Vue.component("list", {
template: `
<div>
list
</div>
`
})
Vue.component("shopcar", {
template: `
<div>
shopcar
</div>
`
})
var vm = new Vue({
el: "#box",
data: {
which: 'home'
}
})
</script>
39.1 keep-alive
keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能,由于是一个抽象组件,所以在v页面渲染完毕后不会被渲染成一个DOM元素
<keep-alive>
<component :is="which"></component>
</keep-alive>
上文中keep-alive是为了保持切换选项卡时,搜索框的数据不随切换而切换