Vue学习二之vue结合项目简单使用、this指向问题
本节目录
一 阶段性项目流程梳理
直接上图吧:
1.首页:
2.免费课程页
还有比如全部里面有个django框架学习,点击进去,具体的信息展示和课程套餐选择等功能
3.登陆页
还有购物车添加成功提示,更新成功提示,当然这些都是前端根据后端的代码逻辑来写的,咱们所说的这些功能都是根据业务需求来写的,不是固定的。
加入购物车成功之后,去结算
4.支付功能:
5.后端数据分析
智能题库,像我们说的这些功能,需要的数据,都是我们应该现在后端数据库里面设计好表结构之后,再保存提取出来的数据,所以以后我们写功能的时候,UI做好功能图之后,其实第一步应该是按照功能设计数据库表结构
我们打开浏览器控制台你看看这个页面的ajax请求,看看请求的接口是什么样的,这些接口我们会通过后面要学的djangorestframework来写,我们看看接口api(url)的写法,访问一下这个接口,看看返回给我们json数据是个什么样子的
像这种api接口,按说都应该会看,拿到接口大概就知道这个接口是干什么的。
好,大概就看看这些,简单知道一些功能就行了,我们就开始写。
二 vue切换图片
首先我们先找一些图片:别光看图昂
然后我们写一下轮播图,先看目录结构
看代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test vue</title> </head> <body> <div id="app"> <!-- 1.取图片数据,可以这样取 --> <!--<img :src="imgs[0].imgSrc" alt="">--> <!-- 2.让数据动态起来,放个data里面的属性或者说是变量 --> <!--<img :src="imgs[currentIndex].imgSrc" alt="">--> <!-- 3.给img绑定个click事件--> <img :src="imgs[currentIndex].imgSrc" alt="" @click="imgHandler"> <button @click="prevHandler">上一张</button> <button @click="nextHandler">下一张</button> </div> <script src="vue.js"></script> <script> // 可以有返回值,我们一般给Vue实例起的变量名都叫vm let vm = new Vue({ el:'#app', data(){ return{ //这些数据按说都是后端给的,我们先写死了,只要看效果,至于怎么获取后端的数据,后面学习再说 imgs:[ {id:1,imgSrc:'./img/1.jpg'}, {id:2,imgSrc:'./img/2.jpg'}, {id:3,imgSrc:'./img/3.jpg'}, {id:4,imgSrc:'./img/4.jpg'}, ], currentIndex:0, //默认选中第一张 } }, //通过下面的操作你会发现,完全不需要你自己写dom操作,更改数据就完成了图片的切换 methods:{ //上一张的点击事件 prevHandler(){ this.currentIndex--; //判断一下,如果currentIndex的值小于等于了0,那么让他显示第一张 if (this.currentIndex <= 0){ this.currentIndex = 0; } }, //下一张的点击事件 nextHandler(){ //让currentIndex的值自动加一,然后数据驱动视图,那么html中的img标签里面那个src就变成了下一张图片的数据 this.currentIndex++; //判断一下,如果currentIndex的值等于了所有图片的个数,那么让他显示第一张 if (this.currentIndex === this.imgs.length){ this.currentIndex = 0; } }, //给图片绑定click事件 imgHandler(e){ //还记得这个可写可不写的事件对象e吗,或者写event console.log(e); //事件对象,MouseEvent {isTrusted: true, screenX: 141, screenY: 187, clientX: 141, clientY: 96, …} 鼠标事件对象(点击事件属于鼠标事件对象) console.log(e.target); //当前事件的标签对象,<img src="./img/1.jpg" alt="">点击的当前标签对象 console.log(this);//在vue这个对象里面,这个this表示的当前的vue对象,其实不一定就是这个vue对象,其中涉及到了vue的继承性,关于继承性的简单解释,看一下下面的图解吧 } } }) </script> </body> </html>
vue的继承性:
下面我们来看一个自动播放图片的效果,类似轮播图的效果:注意自己把图片准备好,我下面的这些图片都是200*200的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test vue</title> </head> <body> <div id="app"> <img :src="imgs[currentIndex].imgSrc" alt="" @click="imgHandler"> <button @click="prevHandler">上一张</button> <button @click="nextHandler">下一张</button> </div> <script src="vue.js"></script> <!-- 引入jquery,我们操作一下ajax --> <script src="jquery.js"></script> <script> // 可以有返回值,我们一般给Vue实例起的变量名都叫vm let vm = new Vue({ el:'#app', data(){ return{ imgs:[ {id:1,imgSrc:'./img/1.jpg'}, {id:2,imgSrc:'./img/2.jpg'}, {id:3,imgSrc:'./img/3.jpg'}, {id:4,imgSrc:'./img/4.jpg'}, ], currentIndex:0, //默认选中第一张 } }, methods:{ prevHandler(){ this.currentIndex--; if (this.currentIndex <= 0){ this.currentIndex = 0; } }, nextHandler(){ this.currentIndex++; if (this.currentIndex === this.imgs.length){ this.currentIndex = 0; } }, imgHandler(e){ console.log(e); console.log(e.target); console.log(this); } }, //Vue对象称为一个最大的组件,而这个created方法是组件创建完成后自动执行的内容,通过这个方法我们可以发送ajax请求,其实这个created方法称为vue的钩子函数,后面我们会细说vue里面的这些钩子函数 created(){ //注意this的指向问题,我们下面看看关于this指向的问题及处理方式 // console.log(this); //打印的是当前的vue对象 // setInterval(function () { // console.log(this) //当前setInterval对象的父级对象,此时也就是我们的window对象,Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …},但是我们现在的场景来看,我们更加希望的是这个this是我们当前的vue对象,因为我们要通过这个vue对象操作这个对象里面封装的数据属性,那么计时器里面的function就不能这么写了,下面有两种写法 // },2000); //方法一 setInterval(() => { //使用箭头函数,就能将this指向定义这个setInterval方法的父级对象,还记得吗,箭头函数,更改this的指向,那么此时定义这个方法的父级对象就是我们的Vue对象,这是一种改变this指向的方法,下面还有一种方法 // console.log(this) //vue对象 //执行下一页操作 this.currentIndex++; if (this.currentIndex === this.imgs.length){ this.currentIndex = 0; } },2000); //方法二,就是通过一个变量保存我们当前的vue对象,然后在函数里面用这个变量去操作vue对象里面的内容 // let _this = this; // setInterval(function() { // console.log(_this) //当前vue对象 // },2000) } }) </script> </body> </html>
三 vue中使用ajax
我们通过ajax做一些东西,其实前端往后端去请求数据实现局部刷新的方式有很多(原生js的XMLHttpRequest,简称XHR,还有jQuery的$.ajax(),还有后面要学的axios,还有一个fetch等等都可以发送ajax请求,都可以做请求数据局部刷新的效果。)
上面的这个列表的数据其实是从后端接口请求来的,我们也去请求一下这个接口,首先我们先找到这个接口
这样看这些数据不太好看,我们找个在线的json数据查看工具,看一看这些数据,首先copy一下这些数据,然后找个在线json数据查看器
但是你对比着看一下,这个全部说明是前端做的,不是后端给的数据,大家记者昂,不一定前端页面上所有的数据都是后端给的,看你们的业务
好,数据找到了,那我们就来写写我们的代码
看代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test vue</title> </head> <body> <div id="app"> <div> <!-- 6.循环数据生成标签,打开页面你就看到效果了,你会发现少个全部那个标签功能,所以我们想办法把它加上,怎么加呢,给categoryList添加一个数据不就行了吗 --> <span v-for="(value,index) in categoryList" :key="value.id"> <!-- 为什么用id,因为我们其实网站上还有其他的操作要和后端进行交互,通过id值来查找数据,这个说的远了点 --> {{ value.name }} </span> </div> </div> <script src="vue.js"></script> <!-- 引入jquery,我们操作一下ajax --> <script src="jquery.js"></script> <script> // 可以有返回值,我们一般给Vue实例起的变量名都叫vm let vm = new Vue({ el:'#app', data(){ return{ categoryList:[] //1.提前准备一个空数组放这里,后面我们把通过ajax获取来的数据放进来 } }, methods:{ }, //2.写个钩子函数created created(){ //3. 写ajax去请求数据(其实除了用jQuery的ajax,还有其他的方式,我们后面再说) $.ajax({ //注意昂,人家的接口返回的数据结构可能会发生变化,所以下面的内容要以人家现在接口返回的数据结构基础上来进行操作,我下面这个可能不是人家现在最新的数据结构了。 url:'https://www.luffycity.com/api/v1/course_sub/category/list/', type:'get', //如果请求成功执行下面的函数 // success:function (data) { 不用这个了,我们用箭头函数,因为要改this的指向,让this指向我们的vue对象,才能通过this来操作vue对象里面的数据属性 success: (data) => { //4. 写箭头函数 // console.log(data); //数据就有了,这打印出来是个object对象,这个对象里面有个data属性,data属性对应的值就是我们想要的数据,我们在浏览器控制台是可以看到的,这个object对象还有个error_no属性,这个属性是后端返回的数据获取成功的一个标志,所以我们也判断一下 if (data.error_no === 0){ // 5. 请求接口,获取数据,把数据赋值给vue对象data()方法里面的categoryList let allData = data.data; console.log(allData); //打印一下你会发现它的数据结构就是一个数组套字典,js里称为自定义对象 // 既然如此,我们直接把这个数据赋值给vue对象里面的data()方法里面的return值里面的那个categoryList就行了,还要注意一点,如果你的数据写道这里发现出不来,你要想一下this的执行问题,所以我们先打印一下this,看看指向的是谁 // console.log(this);//你会发现这个this是ajax对象,所以我们要改为箭头函数,然后再打印这个this,就指向我们的vue对象了,那么通过vue对象就能操作下面的数据了 this.categoryList = allData; // 8. 将'全部'那个标签页添加到数据里面,id给个0,这个id给多少其实是要和后端配合好的,后端说你给0,将来你点击这个全部标签页的时候,后端通过id=0这个参数数据,就把所有的数据都返回给你 this.categoryList.unshift({"id":0,"name":'全部',"category":0}); } }, //如果请求出现错误,执行这个error对应的函数 error:function () { } }) } }) </script> </body> </html>
我们通过上面接口获取的数据结构是这样的,但是你发现少个全部页,所以我们按照下面人家的这个数据结构来添加一组数据,上面的代码中已经写了,大家应该看到了。
下面我们来一个给标签添加css样式,并且添加点击事件的一段代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test vue</title> <style> .active{ background-color: dodgerblue; } </style> </head> <body> <div id="app"> <div> <!-- 绑定点击事件,将index作为参数传给事件函数 --> <span @click="handlerClick(index)" v-for="(value,index) in categoryList" :key="value.id" :class="{active:index==currentIndex}"><!-- 通过class值来给标签加样式,注意写法{active:true或者false,或者得到true或者false的运算式} --> {{ value.name }} </span> </div> </div> <script src="vue.js"></script> <script src="jquery.js"></script> <script> let vm = new Vue({ el:'#app', data(){ return{ categoryList:[], currentIndex:0, } }, methods:{ handlerClick(index){ //把渲染span标签时for循环的index传过来,通过index值来动态更改currentIndex的值,达到一个点击哪个标签哪个标签就有.active类值css样式的效果 this.currentIndex = index; } }, created(){ $.ajax({ url:'https://www.luffycity.com/api/v1/course_sub/category/list/', type:'get', success: (data) => { if (data.error_no === 0){ let allData = data.data; this.categoryList = allData; this.categoryList.unshift({"id":0,"name":'全部',"category":0}); } }, error:function () { } }) } }) </script> </body> </html>
图解一下上面这个代码
接下来我们升级下我们的代码,再加一些功能,下面这个我更新了,网址接口不再是上面的那个路径规则了,后端返回的数据也不再是上面的数据结构了
通过这些数据,我们来渲染成下面的效果
你想,我们拿到了数据,通过我们的前端知识是不是就能搞定这样的页面了啊,哈哈,所以我只写一下获取数据的操作,看代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test vue</title> <style> .active{ background-color: dodgerblue; } </style> </head> <body> <div id="app"> <div> <!-- 绑定点击事件,将index和数据的id作为参数传给事件函数 --> <span @click="handlerClick(index,value.id)" v-for="(value,index) in categoryList" :key="value.id" :class="{active:index==currentIndex}"><!-- 通过class值来给标签加样式,注意写法{active:true或者false,或者得到true或者false的运算式} --> {{ value.name }} </span> </div> </div> <script src="vue.js"></script> <script src="jquery.js"></script> <script> let vm = new Vue({ el:'#app', data(){ return{ categoryList:[], currentIndex:0, } }, methods:{ handlerClick(index,id){ //把渲染span标签时for循环的index传过来,通过index值来动态更改currentIndex的值,达到一个点击哪个标签哪个标签就有.active类值css样式的效果 this.currentIndex = index;
//这里大家知道一下可以通过ajax来获取数据,之后我们学一个新的东西叫做axios,来发送ajax请求,现在写的是jQuery的ajax请求 $.ajax({ url:`https://www.luffycity.com/api/v1/courses/?sub_category=${id}&ordering=`, type:'get', success:(data) =>{ var all_data = data.data; console.log(all_data); //打印出来的就是我们想要的数据 } }) } }, created(){ $.ajax({ url:'https://www.luffycity.com/api/v1/course_sub/category/list/', type:'get', success: (data) => { if (data.error_no === 0){ let allData = data.data; this.categoryList = allData; this.categoryList.unshift({"id":0,"name":'全部',"category":0}); } }, error:function () { } }) } }) </script> </body> </html>
四 vue实现音乐播放器
大家先去现在一个mp3音乐文件,然后放到我们的目录里面,一会使用,先告诉大家在页面上播放音乐的标签的使用
看我的目录结构,audio标签播放音乐
我们搞几个音乐,和音乐的描述信息,然后通过这些内容来搞音乐盒,看代码,其中有个audio标签和audio的一些属性,和ended事件
音乐盒音乐文件下载地址:
下载链接:https://pan.baidu.com/s/1EXjTh-oj4b3-skN5WFQKeA
提取码:eoj5
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .active{ background-color: red; } </style> </head> <body> <div id="music"> <!-- 显示mq3音乐的标签,其中controls属性是显示播放控件的(暂停、开始什么的),autoplay属性是让它自动播放的,loop是播放完之后再自动播放,相当于循环播放一首歌,单曲循环,ended的事件是音乐播放完之后触发的事件 --> <!--<audio :src="musicData[currentIndex].songSrc" controls autoplay loop @ended="nextHandler"></audio>--> <!-- 写了ended事件,就别写loop属性了,不然不执行ended的事件 --> <audio :src="musicData[currentIndex].songSrc" controls autoplay @ended="nextHandler"></audio> <!-- ul标签用来显示音乐的一些描述信息 --> <ul> <!-- --> <li @click="songHandler(index)" v-for="(item,index) in musicData" :key="item.id" :class="{active:index===currentIndex}"> <h2>歌手:{{ item.author }}</h2> <p>歌名:{{ item.name }}</p> </li> </ul> </div> <script src="vue.js"></script> <script> //先准备一些音乐的数据 var allMusicData = [ { id: 1, name: '于荣光 - 少林英雄', author: '于荣光', songSrc: './static/于荣光 - 少林英雄.mp3' }, { id: 2, name: 'Joel Adams - Please Dont Go', author: 'Joel Adams', songSrc: './static/Joel Adams - Please Dont Go.mp3' }, { id: 3, name: 'MKJ - Time', author: 'MKJ', songSrc: './static/MKJ - Time.mp3' }, { id: 4, name: 'Russ - Psycho (Pt. 2)', author: 'Russ', songSrc: './static/Russ - Psycho (Pt. 2).mp3' } ]; new Vue({ el:'#music', data(){ return{ musicData:[], currentIndex:0, //这个不是后端给的,这个是前端来控制的,默认播放第一首歌 } }, //点击li标签,播放对应的歌曲 methods:{ songHandler(index){ this.currentIndex = index; }, nextHandler(){ this.currentIndex++; if (this.currentIndex >= this.musicData.length){ this.currentIndex = 0; } } }, created(){ //让this的musicData等于我们上面的数据,按说这应该是后端给的动态数据 this.musicData = allMusicData } //然后什么点击上一首下一首的操作会不会啦,是不是点击按钮控制currentIndex的值就可以了,自己搞定吧,另外还有什么单曲循环(找个变量一直保存着这个currentIndex的值),还有什么随机播放,搞一个random随机值,让currentIndex的随机改变,还有顺序播放等,自动播放下一首的操作需要我们看一下audio标签的事件控制方法了,看看下面的图,找到audio标签的事件属性 }) </script> </body> </html>
找audio标签的事件属性:
audio的事件属性里面有个onended事件,可以做音乐播放完了之后触发的事件
五 计算属性和侦听器
官网是这么说的:
模板内的表达式,就是那个{{ }},非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
<div id="example"> {{ message.split('').reverse().join('') }} </div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message
的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。
再比如说,你发布一些文章,前端显示的时候显示个刚刚或者两天前发布或者30天前发布等内容,而后端给你的就是个日期数据,那你就需要做一些复杂的运算,如果都写在模板语法里面,显得过于复杂,也就是过重。
而我们模板语法里面其实就是要个返回值,所以,对于任何复杂逻辑,你都应当使用计算属性,来帮你计算这些复杂的操作。
<div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { /就是这个computed // 计算属性的 getter reversedMessage: function () { // `this` 指向 vm 实例 return this.message.split('').reverse().join('') } } })
补充个问题昂,如果你在浏览器调试台console的地方看到下面的内容:
再说这个computed之前,我们先学一下watch(就是官网说的v-watch)侦听器,看代码:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <p>{{ msg }}</p> <p>{{ age }}</p> <!--下面这种写法是一个简单的写法,点击一下就将msg的值变为Jaden,支持这种写法,我们还是用我们熟悉的写法吧 --> <!--<button @click="msg='Jaden'">修改</button>--> <button @click="clickHandler">修改</button> </div> <script src="vue.js"></script> <script> let vm = new Vue({ el:'#app', data(){ return{ msg:'chao', age:18 } }, methods:{ clickHandler(){ this.msg = 'Jaden'; //这个数据一旦发生变化,下面的watch立马监听到,然后执行msg对应的那个函数 this.age = 28; } }, //监听器 watch:{ //这个msg就是上面的data里面的msg属性,监听着msg 'msg':function (value) { console.log(value); //Jaden 这就是msg变化后的那个值 if (value === 'Jaden'){ this.msg = '牛x的Jaden'; } }, //可以监听多个属性就这样一个一个写,声明多个属性的监听,vue的计算属性比这个watch要友好,既可以监听单个,又可以监听多个,然后我们接着学计算属性 'age':function (v) { if (v === 28){ this.age = 88; } } } }) </script> </body> </html>
下面我们学一下计算属性,看代码:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <!--使用computed监听就不需要写下面这两个了--> <!--<p>{{ msg }}</p>--> <!--<p>{{ age }}</p>--> <!--只需要写上你computed里面的自己写的那个声明的方法--> <p>{{ myMsg }}</p> <!--下面这种写法是一个简单的写法,点击一下就将msg的值变为Jaden,支持这种写法,我们还是用我们熟悉的写法吧 --> <!--<button @click="msg='Jaden'">修改</button>--> <button @click="clickHandler">修改</button> </div> <script src="vue.js"></script> <script> let vm = new Vue({ el:'#app', data(){ return{ msg:'chao', age:18 } }, methods:{ //有些朋友对this的指向不是很清晰,我在这里再说一下,单体模式方式1和方式2,this都是指的当前vue对象,而方式3箭头函数,这种方式this指向的是定义这个箭头函数的vue对象的父级对象,也就是window对象,所以methods一般不用箭头函数,看下面的created()方法 //方式1 clickHandler(){ this.msg = 'Jaden'; //这个数据一旦发生变化,下面的watch立马监听到,然后执行msg对应的那个函数 this.age = 28; }, // 方式2 // clickHandler:function(){ // this.msg = 'Jaden'; //这个数据一旦发生变化,下面的watch立马监听到,然后执行msg对应的那个函数 // this.age = 28; // }, // //方式3 // clickHandler:()=>{ // this.msg = 'Jaden'; //这个数据一旦发生变化,下面的watch立马监听到,然后执行msg对应的那个函数 // this.age = 28; // } }, // created(){ //而这种定时器方法本身就是一个方法,是window对象调用的方法,这时的this指的是window对象,所以我们使用定时器方式2箭头函数的写法来改变this的指向,让其是使用上下文的this,其实内部是通过es6的bind方法改变的,了解一下就行了,这时就指向了我们的当前vue对象 //定时器方式1 // setInterval(function () { // // },2000); // //定时器方式2 // setInterval( () => { // // },2000) // }, //this指向总结:像这种create(){}属于vue对象里面的方法,里面使用其他方法的时候,比如说定时器,ajax等里面还嵌套了其他函数,那么需要使用箭头函数,像methods和computed这种属性(键值对)对应的大括号里面的方法中使用this都指向的是当前vue对象,如果使用箭头函数,那么this的指向发生变化会指向window对象,所以不要在这里面写箭头函数 //计算属性 computed:{ //属性名随便起,我写了个myMsg,这叫声明一个方法,里面有个返回值 myMsg:function () { //这里面写业务逻辑 //计算属性默认只有getter方法,getter方法的意思就是我们在下面只是用属性,不给属性赋值(this.msg='xxx'这种操作),并且有返回值,后面我们再说一个setter方法,给属性赋值的操作,这里我想做什么呢,想同时监听上面data方法里面的msg和age属性 return `我的名字叫做${this.msg},年龄是${this.age}`;//监听了两个属性 } } }) </script> </body> </html>
关于this的指向问题,也vm实例没有任何关系,而是与箭头函数和普通函数的区别。总结下面两点:
1.es5的普通函数,this指向是指向了调用者,比如vue实例的方法(methods中声明的一个方法)是由vue实例vm调用的,所以this指向vm,vm实例中定义的单体模式的函数,和es5的普通函数一样,this指向调用者vm。
2.箭头函数的this指向它的调用者所在的上下文(资料上箭头函数没有this,其实意思箭头函数中不使用指向调用者的this,而是使用上下文中的this,可以理解为这个函数外层中的this),也就是vm实例所在的上下文(定义vm实例的父类对象),即window对象。
3.后面加上第三方库的时候,还需要看一下this的指向问题,this指向问题比较坑,很多种情况,所以遇到了我们再看
我们把计算属性应用到我们上面写的那个音乐盒实例里面:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .active{ background-color: red; } </style> </head> <body> <div id="music"> <!-- 之前的写法 --> <!--<audio :src="musicData[currentIndex].songSrc" controls autoplay @ended="nextHandler"></audio>--> <!-- 直接使用计算属性来监听musicData和currentIndex的值 --> <audio :src="currentSong" controls autoplay @ended="nextHandler"></audio> <ul> <!-- --> <li @click="songHandler(index)" v-for="(item,index) in musicData" :key="item.id" :class="{active:index===currentIndex}"> <h2>歌手:{{ item.author }}</h2> <p>歌名:{{ item.name }}</p> </li> </ul> </div> <script src="vue.js"></script> <script> //先准备一些音乐的数据 var allMusicData = [ { id: 1, name: '于荣光 - 少林英雄', author: '于荣光', songSrc: './static/于荣光 - 少林英雄.mp3' }, { id: 2, name: 'Joel Adams - Please Dont Go', author: 'Joel Adams', songSrc: './static/Joel Adams - Please Dont Go.mp3' }, { id: 3, name: 'MKJ - Time', author: 'MKJ', songSrc: './static/MKJ - Time.mp3' }, { id: 4, name: 'Russ - Psycho (Pt. 2)', author: 'Russ', songSrc: './static/Russ - Psycho (Pt. 2).mp3' } ]; new Vue({ el:'#music', data(){ return{ musicData:[], currentIndex:0, //这个不是后端给的,这个是前端来控制的,默认播放第一首歌 } }, computed:{ currentSong(){ return this.musicData[this.currentIndex].songSrc } }, //点击li标签,播放对应的歌曲 methods:{ songHandler(index){ this.currentIndex = index; }, nextHandler(){ this.currentIndex++; if (this.currentIndex >= this.musicData.length){ this.currentIndex = 0; } } }, created(){ this.musicData = allMusicData } }) </script> </body> </html>
图解上面的代码
简单总结一下
watch:监听单个属性
computed:可同时监听多个属性,主要产生缓存的数据属性,改变这个数据属性的时候,直接拿缓存中数据进行更改,主要作用是为了减少dom操作造成的性能消耗。
对于初学者来说,以后你用vue开发,直接就把这些方法都写上,即便是暂时用不到,里面不写任何内容,也没关系,不会报错,但是对你自己来说可以给你一个提示的作用。
六 chorme浏览器添加vue扩展程序
后面的学习我们会用到vue的这个扩展程序,所以大家下载一下。
先搞个vpn,FQ,然后在浏览器上添加下面这个扩展程序,检测调试vue开发的网页,或者你用火狐浏览器,火狐应该不用FQ。
vpn工具下载地址:链接:https://pan.baidu.com/s/1szO56suw3e3YnFFnXXcEgA 提取码:1x72
添加成功之后,在浏览器上就会看到这个图标,如果这个网站的页面使用vue开发的,那么这个图标就是亮的,如果不是就是暗色的。
vue官网和饿了么官网等都是vue开发的,大家可以打开看看
打开我们之前用vue写的网页,你打开浏览器调试台,就会看到vue调试工具,里面可以检测我们写的vue的基本上所以内容
你里面的数据发生变化,这里立马就能监测到,上面这个root是根标签,然后你在vue里面声明的所有属性,这里都有,都可以在这里调试。
七 xxx
八 xxx