学习前端Vue——by盐焗西蓝花

经过断断续续近一个月的学习,总算跟着入门了Vue,对前端框架有了一个新的认识

接下来总结一下:

  1. 课程主要分为四个板块,Vue基础,本地应用,网络应用,综合应用
  2. Vue基础:导入Vue,准备html结构,把Vue挂载上去,再在里面准备data和methods
  3. 本地应用:实现计数器,图片切换,记事本的制作
  4. 网络应用:结合axios,和准备好的接口综合开发;制作天知道-天气查询页面,
  5. 综合应用:实现一个音乐播放页面,可以在搜索音乐的基础上,对应播放,并且显示歌曲专辑的封面,以及热门评论;在播放暂停的时候会有不同的动画效果,最后在有mv的歌曲中可以在线观看当前歌曲的mv

Vue基础

学习Vue之前需要有一些铺垫知识:HTML,CSS,JavaScript,AJAX基础知识~~(然而我都不怎么会)~~
在学习中选用vscode作为课程中的开发工具(其实其他的也可以,之前用过hbuilder)。
Vue 呢,JavaScript的框架,出现的目的呢是为了简化dom操作(然鹅我并不知道什么是dom操作)百度如下:

一个与系统平台和编程语言无关的接口,程序和脚本可以通过这个接口动态地访问和修改文档的内容、结构和样式。

回看课程发现,dom操作呢简单来说就是获取元素,再操纵元素来实现不一样的网页效果。
Vue呢还可以做到响应式数据驱动,简单来说因为页面是由数据来生成的,所以当数据改变以后,页面就会同步的更新。

在使用Vue之前呢,需要
1.导入开发版本的Vue.js。可以理解为开发版本的jQuery,有各种有意义的提示和警告,适合初学者使用。

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

或者下载好本地版的Vue.js导入即可

<script src="vue.js"></script>

2.创建Vue实例对象,设置el属性和data属性。

		<script>
		var app = new Vue({
			el: '#app',
			data:{
				message:'Hello Vue!'
			}
		});
		</script>

el就是element的缩写,表示挂载点,#号呢表示id选择器
data是数据对象,Vue中用到的数据定义在data中;data中可以写复杂类型的数据(如数组,对象等等),渲染复杂数据时,遵守js的语法即可(如对象的话就是点语法,“city.name”,对象的话就是索引语法,“campus[0]”)。
3.使用简洁的模板语法把数据渲染到页面上:两个大括号表示插值表达式,也就是后面会讲到的v-on指令

		<div id = 'app'>
			{{message}}
		</div>

el挂载点呢通过css选择器设置Vue实例管理的元素,设置完毕以后呢el元素命中的内部,使用两个大括号修饰的部分会被data中同名的数据给替换,比如上文的{{message}}就会被替换为Hello Vue!

三个疑问?

  1. Vue实例的作用范围是什么?
  2. 是否可以使用其他的选择器?
  3. 是否可以设置其他的dom元素呢?

answer:

  1. el内部就可以(Vue会管理el选项命中的元素及其内部的后代元素),写在外部则不会显示
  2. id选择器,class选择器,div选择皆可,但建议选择id选择器为了避免混淆。若选中class选择器,则el里改为“.app”,同样可以实现效果。建议使用div标签进行挂载,因为div标签一般没有什么样式。
  3. div标签,p标签,h2标签皆可,但建议选择div标签;不能使用html标签和body标签

并且为了使信息快速显示出来,在vscode里的Extensions里添加live server插件,每当保存代码即可立即显示当前效果。
学习前端Vue——by盐焗西蓝花_第1张图片

本地应用

通过下面的学习将达到的目标:
1.通过Vue实现常见的网页效果
2.学习Vue指令,以案例的方式巩固所学知识点
3.Vue指令指的是,以v-开头的一组特殊的语法

v-text

设置标签的文本值(textContent)
定义:
Vue:

		<script>
		var app = new Vue({
			el: "#app",
			data:{
				message:"programmer!",
			}
		});
		</script>

html结构:
两种形式:

		<div id = "app">
			<h2 v-text="message+'!'"></h2>
			// 在h2标签内直接写入
			<h2>{{ message }}武汉</h2>
			// 在h2标签之间写入插值表达式
		</div>

解析完毕之后呢会将message的值替换给h2标签的内部
方法一的缺点是不论h2中有什么值都会被全部替换掉,若只想替换部分的值则需使用方法二,只有大括号里的内容会被替换,其他内容会原封不动保持不变
并且还支持字符串的拼接:

<h2 v-text="message+'!'"></h2>
<h2>{{ message +"!"}}武汉</h2>
// 单引号双引号皆可

总结
1.默认写法会替换全部内容,使用插值表达式{{}}可替换指定内容
2.内部支持写表达式

v-html

设置标签的innerHTML
和v-text的区别:
如果设置的是普通的值的话,其实相同;若设置html结构则会解析为链接
定义:
Vue:

		<script>
		var app = new Vue({
			el: '#app',
			data:{
				//content:"programmer",
                content:"百度一下"
                
			}
		});
		</script>

html结构:

		<div id = 'app'>
            <p v-html="content"></p>
            <p v-text="content"></p>
            // 为了对比说明,同时写入v-html和v-text
		</div>

结果:
学习前端Vue——by盐焗西蓝花_第2张图片
前者呢是v-html的结果,为一个链接;后者呢为v-text的结果,为纯文本。

总结
1.v-html指令的作用是:设置标签的innerHTML
2.内容中有html结构会被解析为标签
3.v-text指令无论内容是什么,只会解析为文本
4.解析文本使用v-text,需要解析html结构使用v-html

v-on基础

为元素绑定事件
定义:
Vue:

<script>
var app = new Vue({
	el:#app,
	methods:{
		doIt:function(){
		// 逻辑
		}
	}
})
</script>

html结构:

<div id="app">
	<input type = "button" value = "事件绑定" v-on:事件名 = "方法">
	<input type = "button" value = "事件绑定" v-on:click = "方法">
	// 点击事件
	<input type = "button" value = "事件绑定" v-on:mouseenter = "方法">
	// 鼠标移入事件
	<input type = "button" value = "事件绑定" v-on:dbclick = "方法">
	// 双击事件
	<input type = "button" value = "事件绑定" @dblclick = "方法">
	// 双击事件(简写)
</div>

书写一个“武汉加油!”的实例
Vue:

		<script>
		var app = new Vue({
			el: '#app',
            data:{
                place:"武汉"
                // 定义一个参数为place
            },
            methods:{
                comeOn:function(){
                    this.place+=" 加油!"
                    //写入一个方法,每当调用该方法,即可在末尾加一个" 加油!"
                }
            }
		});
		</script>

html结构:

		<div id ="app">
            <h2 @click="comeOn">{{ place }}</h2>
            /* 结合v-text设置place的文本值,再运用v-on方法绑定点击事件,
            每当点击一次,就调用一次comeOn方法。
            */
		</div>

效果:
在这里插入图片描述

总结:
1.v-on指令的作用是:为元素绑定事件
2.事件名不需要写on
3.指令可以简写为@
4.绑定的方法定义在methods属性中
5.方法内部通过this关键字可以访问定义在data中的数据。

计数器应用:

需要做到:限制了最大值和最小值分别为10和0,加号和减号都写在button标签内
数字区域呢写在两者中间,当我们点击两边的加和减时操纵的就是中间的数字内容。
定义:
Vue:

<script>
var app = new Vue({
	el:"#app",
	data:{
	  num: 1
		}
	// data中定义数据:比如num,num等于1
	methods:{
	     add:function(){},
	     sub:function(){}
		}
	// methods中添加两个方法:比如add(递增),sub(递减)
});
</script>

html结构:

<div class = "input-num">
	<button @click>-</button>
	// 递减的逻辑:大于0递减,否则提示
	<span>{{num}}</span>
	// 使用v-text将num设置给span标签
	<button @click>+</button>
	// 累加的逻辑:小于10累加,否则提示
	// 使用v-on将add,sub分别绑定给+,-按钮
</div>

初始状态:
学习前端Vue——by盐焗西蓝花_第3张图片
完善代码:
Vue:

  <script>
    var app = new Vue({
      el:"#app",
      data:{
        num:1
      },
      methods:{
        add:function(){
          if(this.num<10){
          this.num++;}
          else{
            alert("max! don't click!")
          }
        },
        // 规定最大值为10,否则弹窗
        sub:function(){
          if(this.num>1){
          this.num--;}
          else{
            alert("min! don't click!")
          }
        }
      },
      // 规定最小值为1,否则弹窗
    })
  </script>

html结构:

  <div id="app">
    <!-- 计数器功能区域 -->
    <div class="input-num">
      <button @click="sub">
        -
      </button>
      <span>{{ num }}</span>
      <button @click="add">
        +
      </button>
    </div>
  </div>

总结:
1.创建vue示例时:el(挂载点),data(数据),methods(方法)
2.v-on指令的作用是绑定时间,简写为@
3.方法中通过this,关键字获取data中的数据
4.v-text指令的作用是:设置元素的文本值,简写为{{}}

v-show:

根据表达值的真假,切换元素的显示和隐藏
作为一个常见的网页效果,比如遮罩层,广告等都会有所应用
定义:
Vue:

var app = new Vue({
    el:"#app",
    data:{
	isShow:true
	// true/false(true为显示,false为隐藏)
	age:16
    }
})

html结构:

<div id = "app">
    <img src = "地址" v-show = "true">
    <img src = "地址" v-show = "isShow">
    <img src = "地址" v-show = "age>=18">
</div>

根据布尔值切换显示状态。
本质:切换display 隐藏时display:none

一个实例:
写一个button按钮切换图片显示状态和写一个年龄限制图片显示的button按钮
Vue:

        <script>
            var app = new Vue({
                el: "#app",
                data:{
                    isShow:true,
                    age:17
                },
                methods:{
                    changeIsShow:function(){
                        this.isShow = !this.isShow;
                    },
                    addAge:function(){
                        this.age++;
                    }
                },
            })

html结构:

     <div id = "app">
         <input type="button" value="切换显示状态" @click ="changeIsShow">
         <input type="button" value="累计年龄" @click ="addAge">
         <img v-show ="isShow" src="curacao1.jpg" alt="">
         <img v-show ="age>=18" src="curacao1.jpg" alt="">
     </div>

总结:
1.v-show指令的作用是:根据真假元素的显示状态
2.原理是修改元素的display,实现显示隐藏
3.指令后面的内容,最终都会解析为布尔值
4.值为true则元素显示,值为false元素隐藏
5.数据改变之后,对应元素的显示状态会同步更新

v-if:

根据表达式的真假,切换元素的显示和隐藏,进而直接操纵dom元素
定义:
Vue:

var app = new Vue({
	el:"#app",
	data:{
	    isShow:false
	}
})

html结构:

<div id = "app">
    <p v-if = "true">我是一个p标签</p>
    <p v-if = "isShow">我是一个p标签</p>
    <p v-if = "表达式">我是一个p标签</p>
</div>

v-show操纵的是样式,v-if操纵的是dom树

一个实例:
通过点击事件,切换显示与否;并且通过表达式测试显示与否
Vue:

        <script>
            var app = new Vue({
                el:"#app",
                data:{
                    isShow:false,
                    // isShow为布尔值,默认为false
                    temperature:40
                },
                methods:{
                    toggleIsShow:function(){
                        this.isShow = !this.isShow;
                    }
                    // 通过toggleIsshow方法切换isShow的true和false
                }
            })
        </script>

html结构:

        <div id="app">
            <input type="button" value="切换显示" @click="toggleIsShow">
            <p v-if="isShow">I am a programmer - v-if修饰</p>
            // 表达式测试
            <h2 v-if = "temperature>=35">resila!</h2>
        </div>

总结:
1.v-if指令的作用是:根据表达式的真假切换元素的显示状态(和v-show是一样的,但本质不同)
2.本质是通过操纵dom元素来切换显示状态(操作dom树对性能的消耗比较大)
3.表达式的值为true,元素存在于dom树中,为false,从dom树中移除
4.频繁的切换v-show,反之使用v-if,前者的切换消耗小

v-if和v-show的区别与联系

  1. 联系:都可以做到根据表达式的真假切换元素的状态。
  2. 区别:v-if是操作dom元素(若为false就直接移除了,决定了存在与否),v-show是修改元素的display;也就是说v-show仅仅控制元素的显示方式,display显示为none,需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能,若在运行条件很少改变时,使用v-if更好。

v-bind

设置元素的属性
常见的属性src:图片的地址,文本:title,类:class
形式:v-bind:属性名=表达式
定义:
Vue:

<script>
	var app = new Vue({
	    el:"#app",
	    data:{
	 	imgSrc:"图片地址",
		imgTitle:"黑马程序员",
		isActive:false
	    }
	})
</script>

html结构:

<div id = "app">
    <img v-bind:src = "imgSrc">
    // 地址的绑定:最终把地址解析到src的值后边
    <img v-bind:title = "imgtitle+'!!!!'">
    // 文本的绑定:在字符串后面拼接叹号
    <img v-bind:class = "isActive?'active':''">
    // 类名的绑定:通过三元表达式来判断true或者false
    <img v-bind:class = "{active:isActive}">
    // 类名的绑定:另一种写法,true则生效,false则移除,结果相同
</div>

这里的都可以替换为<:>
比如:就可以替换为

jQuery操作的是dom节点, vue操作的是虚拟dom节点,一个是事件驱动,一个是数据驱动

一个实例:
当点击图片时会出现一个红色框包裹住图片,综合应用v-bind指令,v-on指令。
Vue:

  <script>
      var app = new Vue({
          el:"#app",
          data:{
              imgSrc:"http://test.mycoser.com/Uploads/20170410/thumb_58eb030ae4d7c.jpg",
              imgTitle:"curacao",
              isActive:false
          },
          methods:{
              ToggleActive:function(){
                  this.isActive= !this.isActive
              }
              // 该方法为每当调用立即取反
          }
      })
  </script>

html结构:

<div id ="app">
    <img v-bind:src="imgSrc" alt="">
    <!-- 完整的形式 -->
    <br>
    <img :src="imgSrc" alt="" :title="imgTitle+'!!!'" :class = "isActive?'active':''" @click ="ToggleActive">
    <!-- 缩写的形式 :title为文本的绑定,:class为类名的绑定-->
    <br>
    <img v-bind:src="imgSrc" alt="" v-bind:title="imgTitle+'!!!'" v-bind:class = {active:isActive} @click ="ToggleActive">
    <!--默认isActive为false,因为给图片绑定了点击事件,每当点击时isActive就会变化,则第一次点击时为true,此时class标签就激活了active出现了红色边框-->
</div>

总结:
1.v-bind的作用是为元素绑定属性
2.完整的写法是:v-bind:属性名
3.简写的话,可以直接省略v-bind,只保留:属性名
4.需要动态的增删class,建议使用对象的方式

图片切换:

切换图片的本质:是更改图片的src属性
定义(模板):
Vue:

var app = new Vue({
    el:"#app",
    data:{
    	imgArr:[]
    	// 定义图片数组保存图片
    	index:0
    	// 添加图片索引,因为我们要知道当前显示的是哪一张,从数组第一个开始所以是从0开始
	 }
	 methods:{
	 	prev:function(){},
	 	next:function(){}
	 	// 图片切换逻辑:点击上一张点击下一张切换图片,本质是修改了索引值;逻辑写在methods中。只需要累加和递减就可以了。
	 }
})

html结构:

<div id ="#app">
    <img src = "imgArr[index]">
    // 把img和src属性进行绑定,获取方式就是数组加索引
    <a href = "#" @click="prev">上一张</a>
    <a href = "#" @click="next">下一张</a>
    // 使用v-on指令进行绑定,左右箭头分别放在两个标签里
    // 因为要频繁切换,为了减小消耗,使用v-show指令
</div>

流程:

  1. 定义图片数组 imgArr:[](因为使用的是数组,因此可以很便捷的确定是第一张还是最后一张)
  2. 添加图片索引:index:0
  3. 使用v-bind指令绑定src属性,方式:数组+索引---->地址:imgArr[index]
  4. 图片切换逻辑:prev和next
  5. 使用v-on指令绑定两个a标签,将“上一张”的这个a标签对应prev;将“下一张”的这个a标签对应next
  6. 通过v-show作为显示与否条件,不使用if可以减少消耗

实例操作:

Vue:

  <script>
      var app = new Vue({
          el:"#mask",
          // 对最大的div进行挂载
          data:{
            imgArr:[
                "./images/curacao1.jpg",
                "./images/curacao2.jpg",
                "./images/curacao3.jpg",
                "./images/curacao4.jpg",
                "./images/curacao5.jpg",
            ],
            // 把所有图片引入图片数组里
            index:0,
          },
          methods:{
            prev:function(){
                this.index--;
            },
            next:function(){
                this.index++; 
            }
            // prev方法和next方法分别让index的值自增或自减
          }
      })
  </script>

html结构:

  <div id="mask">
    <div class="center">
      <h2 class="title">
        <img src="./images/curacao1.jpg" alt="">
        库拉索Curacao
      </h2>
      <!-- 图片 -->
      <img :src="imgArr[index]" alt="" />
      <!-- 左箭头 -->
      <a href="javascript:void(0)" @click="prev" v-show="index!=0" class="left">
          <img src="./images/prev.png" alt="" />
       // 绑定prev方法给左箭头,并且在第一张图片时隐藏(通过v-show)
      </a>
      <!-- 右箭头 -->
      <a href="javascript:void(0)" @click="next" v-show="index class="right">
        <img src="./images/next.png" alt="" />
      </a>
      // 绑定next方法给右箭头,并且在最后一张图片时隐藏(通过v-show)
    </div>
  </div>
  //javascript:void(0)则停留在原地,一动不动,我们称之为“死链接”

总结:
1.列表数据使用数组保存:imgArr和index
2.v-bind指令可以设置元素属性,比如src–>":"
3.看css文档,发现:
position 属性规定元素的定位类型。
这个属性定义建立元素布局所用的定位机制。任何元素都可以定位,不过绝对或固定元素会生成一个块级框,而不论该元素本身是什么类型。相对定位元素会相对于它在正常流中的默认位置偏移。

z-index在使用绝对定位 position:absolute属性条件下使用才能使用。通常我们让不同的对象盒子以不同顺序重叠排列,我们就是要z-index样式属性。

v-for

根据数据生成列表结构(响应式)
可以十分便捷的操纵列表结构
定义:
Vue:

var app = new Vue({
   el:"#app",
   data:{
     arr:[1,2,3,4,5](用数组表示)
     // 列表的形成依赖数据,结合的类型呢,有数组,对象,数字字符串,迭代器等等,最常见的是数组。
     objArr:[
     	{name:"jack"},
     	{name:"rose"}
     ]
     // 数组的对象不是数字,而是其他类型如对象objArr
    }
})

html结构:

<div id ="app">
  <ul>
    <li v-for = "item in arr" :title="item">你好{{ item }}</li>
(其中,“item”可以改名字,in不可改,“arr”也可更改,是在Vue上定义的数组)
	// 如果li中有内容,也会一并生成。此处写入了“你好”,就会生成5个你好的li标签,后代元素呢也会跟随标签生成
	// 这里的item可以使用,结合其他指令(v-text,v-bind指令)
	<li v-for = "(item,index) in arr" :title="item">
		{{ index }}{{ item }}
	</li>
	// 数组的索引页也是比较常用的将item变为(item,index)
	<li v-for="(item,index) in objArr ">
		{{item.name}}
	</li>
	// item代表的就是对象数组的元素,对应其内容则需要使用点语法
  </ul>
</div>

现在数组有五个数,循环起来就会有5组“li标签”。
v-for指令的作用是把作为模板的标签还有其内部的所有内容根据数据的个数拷贝若干份。
v-for的强大之处在于:若对应数组里的对象增加或者减少了,那生成的列表呢会同步改变。

一个实例:
Vue:

  <script>
      var app = new Vue({
          el: "#app",
          data:{
              arr:["beijing","shanghai","wuhan","ezhou"],
              vegetables:[
                  {name:"西蓝花炒蛋"},
                  {name:"蛋炒西蓝花"}
              ]
              // 测试对象数组
          },
          methods:{
              add:function(){
                  this.vegetables.push({name:"花菜炒蛋"});
                  // push为追加内容的用法,写一个固定的内容
              },
              remove:function(){
                  this.vegetables.shift();
                  // shift默认为移除最左边的元素
              }
          },
      })
  </script>

html结构:

 <div id = "app">
     <input type="button" value="添加数据" @click = "add">
     <input type="button" value="移除数据" @click = "remove">
     <ul>
         <li v-for = "(item,index) in arr">
             {{ index+1 }}斌斌想去的地方:{{item}}
         </li>
         // 测试v-for指令结合索引index,以及使用v-text
     </ul>
     <h2 v-for ="item in vegetables" v-bind:title = "item.name">
         {{ item.name }}
     </h2>
     // 用h2标签测试对象数组的功能
 </div>

总结:
1.v-for指令的作用是:根据数据生成列表结构
2.数组经常和v-for结合使用
3.语法是(item,index)in 数据
4.item和index可以结合其他指令一起使用
5.数组长度的更新会同步到页面上,是响应式的

v-on补充:

传递自定义参数,事件修饰符的使用
定义:
Vue:

<script>
	var app = new Vue({
	  el:"#app",
	  methods:{
	  doIt: function(p1,p2){},
	  sayHi:function(){}
	}
	})
</script>

html结构:

<div id ="app">
  <input type ="button" @click ="doIt(p1,p2)"/>
   // 触发的方法名为doIt,若要传入参数则需在括号内写入参数p1即可,通过对应的形参就可以获得参数了
  <input type = "text" @keyup= "sayHi">
   // 事件修饰符:这里的text文本框绑定了一个按钮事件,对应的逻辑呢就是sayHi,无论按下什么按钮都会sayHi。
  <input type = "text" @keyup.enter = "sayHi">
   // 限定回车按钮,语法呢就是事件修饰符加“点”,后加enter,这样呢只会在按回车键的时候才会触发逻辑
</div>

在触发事件的时候呢,传入自定义的值,写法和调用数据传参十分的类似
获取v-on的事件修饰符的说明文档:https://cn.vuejs.org/v2/api/#v-on

一个实例:
测试事件修饰符和事件绑定方法函数传参
Vue:

 <script>
     var app = new Vue({
         el:"#app",
         methods:{
             doIt:function(p1,p2){
                 // console.log("做it");
                 console.log(p2);
                 console.log(p1);
             },
             // 这里的p1对应的就是“666”,而p2对应的就是“老铁”
             // 调用函数时会在监视器里显示p2和p1的值
             sayHi:function(){
                 alert("吃了没");
             }
         }
     })
 </script>

html结构:

 <div id="app">
     <input type="button" value="点击" @click="doIt(666,'老铁')">
     // 点一下就多一个
     <input type="text" @keyup.enter="sayHi">
     // 测试事件修饰符
 </div>

总结:
1.事件绑定的方法写成函数调用的形式,可以传入自定义参数
2.定义方法时需要定义形参来接收传入的实参
3.事件的后面跟上 .修饰符 可以对事件进行限制
4. .enter 可以限制触发的按键为回车
5. 事件修饰符有多种

v-model:

获取和设置表单元素的值(双向数据绑定)
定义:
Vue:

var app = new Vue({
  el:"#app",
  data:{
    message:"I am a programmer"
  }
})

html结构:

<div id = "app">
  <input type = "text" v-model="message"/>
  // 和data中的massage绑定,解析完毕以后两者的值会关联起来
</div>

**双向数据绑定:**一解析以后message的值会解析到表单元素上,当更改表单元素的值后,也会把此次更新同步到message元素上边;也就是更改任意一边,两边会同时更新message的值。

一个实例:
Vue:

 <script>
     var app = new Vue({
         el:"#app",
         data:{
             message:"I am a programmer"
         },
         methods:{
             getM:function(){
                 alert(this.message);
             },
             setM:function(){
                 this.message = "cool"
             }
         }
     })
 </script>

html结构:

 <div id="app">
     <input type="button" value="修改message" @click="setM">
     // 结合v-on指令修改message的值
     <input type="text" v-model = "message" @keyup.enter="getM">
     // 输入一个文本框,会自动显示message的值,结合v-on获取一下message的值
     <h2>{{ message }}</h2>
     // 当手动更改文本框中的值即message的值会自动跟随改变
 </div>

总结:
1.v-model指令的作用是便捷的设置和获取表单元素的值
2.绑定的数据会和表单元素值相关联
3.绑定得数据←→表单元素的值

记事本案例:

学习前端Vue——by盐焗西蓝花_第4张图片
功能:
1.新增 2.删除 3.统计 4.清空 5.隐藏

新增:

功能项:
1.生成列表结构(v-for 数组)
2.获取用户输入 (v-model)
3.通过回车按钮来新增数据(v-on 的.enter 添加数据)

Vue:

  <script>
      var app = new Vue({
          el:"#todoapp",
          // 挂载元素为最大的section标签
          data:{
              list:["写代码","吃饭饭","睡觉觉"],
              // 根据数组生成一个列表结构
              inputValue:""
          },
          methods:{   
              add:function(){
                  this.list.push(this.inputValue);
              }
              // 添加的点击方法
          }
      })
  </script>

html结构:

<!-- 主体区域 -->
 <section id = "todoapp">
     <!-- 输入框 -->
     <header class="header">
         <h1>小黑笔记本</h1>
         <input v-model ="inputValue" @keyup.enter ="add" autofocus="autofocus" autocomplete="off" placeholder="请输入任务" class="new-todo" />
         // 使用v-model添加一个新增的值
         // 通过点击方法然后按回车添加新的值
         // autofocus 属性规定当页面加载时 input 元素应该自动获得焦点。
     </header>
     <!-- 列表区域 -->
     <section class ="main">
         <ul class="todo-list">
             <li class="todo" v-for ="(item, index) in list">
             //在li标签中写入v-for指令,
                 <div class="view">
                     <span class="index">{{ index + 1  }}.</span>
                     // 索引值
                     <label>{{ item }}</label>
                     // 数组每一项值
                     <button class="destroy"></button>
                 </div>
             </li>
         </ul>
     </section>
 </section>

总结:
1.v-for指令的作用是根据一个数组生成一个列表结构
2.v-model指令的作用是双向绑定数据,可以把data 中的数据和表单上的数据关联起来,可以方便的设置或者取值
3.v-on指令可以绑定事件,并且结合事件修饰符进行限制(使用keyup.enter限制触发的按键)
4.通过审查元素快速定位,如确定v-for时确定在“li”中,v-on在input中。通过审查元素快速定位到你要操作的元素,没有必要从头到尾全部看一遍,加快速度。

删除

功能项:
点击删除指定内容 (v-on指令 splice索引)
通过对应的下标删除指定的元素,并且v-for指令的内部呢是可以获取到元素下标的,就可以结合方法的绑定传入自定义的参数,把下标传入进去,结合到一起就可以根据索引点击删掉对应的元素了。

删除功能是点击小叉叉来实现的
通过审查元素发现删除功能是在class="destroy"的button标签中实现的
Vue:

 remove:function(index){
     this.list.splice(index,1);
     // 在methods中添加一个新的方法用于删除元素并传入参数index
     // 通过splice方法删除,括号内写入删除内容和个数
 }

html结构:
在class="view"的div标签中写入:

<button class="destroy" @click="remove(index)"></button>
// 通过v-on指令的点击方法调用remove方法并传入参数index

splice方法的具体应用:

https://www.w3school.com.cn/jsref/jsref_splice.asp

总结:
1.数据改变,则和数据绑定的元素同步改变
2.事件可以接受自定义的参数
3.splice方法

统计

统计信息个数对应列表的个数
(通过v-text指令把数组长度渲染到页面上;统计v-text的length)
html结构:
通过审查元素的方式定位到需要修改的位置:找到footer标签

 <!-- 统计和清空 -->
 <footer class="footer">
     <span class="todo-count"><strong>{{list.length}}</strong>item left</span>
     // v-text的插值表达式表示的数组的长度,并且增加减少的时候同步更新
     <button class="clear-completed">
         Clear
     </button>
 </footer>

1.footer 标签定义文档或节的页脚,应当含有其包含元素的信息,如文档的作者、版权信息、使用条款链接、联系信息。可在一个文档中使用多个footer元素。
2.strong 标签和 em 标签一样,用于强调文本,但它强调的程度更强一些。

总结:
1.基于数据的开发方式:所有和数据相关的内容,我们只需要找到数据就可以了,比如说个数,就是数组的长度
2.v-text指令的使用

清空:

一次性删除所有信息
1.点击清除所有信息(v-on)逻辑的执行是在点击的时候,页面是通过v-for指令结合数据渲染而成
2.清空的本质就是把数组清空
Vue:
在methods方法中:

 clear:function(){
     this.list= [];
 }
 // 该方法使数组清空

html结构:
footer标签中的button标签里修改

 <button class="clear-completed" @click="clear">
     Clear
 </button>
 // 绑定点击事件,调用clear方法

隐藏:

没有数据的时候隐藏底部“剩余”和“清空”的元素 ,让页面更加美观
(v-show或v-if,只要数组非空即可)
通过审查元素发现,“剩余”在span中,class=todo-count;
“清空”在button中,class=clear-completed。
html结构:

 <span class="todo-count" v-if="list.length!=0">
     <strong>{{list.length}}</strong>
     item left
 </span>
 <button class="clear-completed" @click="clear" v-show="list.length!=0">
     Clear
 </button>
 // 如果数组为空时,就不显示即隐藏

总体总结:
1.列表结构可以通过v-for 指令结合数据形成
2.v-on指令结合事件修饰符可以对事件进行限制,比如.enter
3.v-on指令在绑定事件时可以传递自定义参数
4.通过v-model可以快速的设置和获取表单元素的值
5.基于数据的开发方式

网络应用:

目标:
1.学习axios(网络请求库),内部是ajax;但封装之后使用会更加便捷,功能单一容量很小,可以十分方便的和其他框架和库结合
2.学习axios和vue结合一起

axios的基本使用:

axios:功能强大的网络请求库

导包:

使用方法:

1.get请求:axios.get(地址)
格式:
axios.get(地址?查询字符串).then(function(response){},function(err){})
地址就是文档提供的接口地址;然后.then方法后面传递的第一个函数会在请求响应完成的时候触发,第二个函数呢会在请求失败的时候触发,它们的形参可以用来获取信息,一个是服务器响应的内容,一个是错误的信息,若需要传递参数,跟上查询字符串就可以了。
查询字符串的格式:key=value&key2=value2(不限个数)
其中key是文档提供的,value是具体要传输的值

2.post请求:axios.post(地址)
(两者基本相同)
不同在于:
post是:axios.post(地址,参数对象)
get是:axios.get(地址?查询字符串)
格式:
axios.pos(地址,{key:value,key2:value2}).then(function(response){},function(err){})
其中key由接口文档提供,value是具体要传输的数据

提供两个预先准备的接口:

get随机获取笑话的接口
地址:https://autumnfish.cn/api/joke/list
请求参数:num
post进行用户注册接口
地址:https://autumnfish.cn/api/user/reg
请求参数:username

不同的接口有不同的返回值
然后演示:
html结构:

<input type="button" value="get请求" class="get">
<input type="button" value="post请求" class="post">
// 准备两个按钮分别测试get请求和post请求
<!-- 官网提供的 axios 的在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

// 接口1:随机笑话
document.querySelector(".get").onclick = function(){
    axios.get("https://autumnfish.cn/api/joke/list?num=3").then(function(response){
        console.log(response);
    },function(err){
        console.log(err);
    })
}
// 看三条笑话

// 接口2:用户注册
document.querySelector(".post").onclick = function(){
    axios.post("https://autumnfish.cn/api/user/re2g",{username:"robin"}).then(function(response){
        console.log(response);
    },function(err){
        console.log(err);
    })
}

结果1:
在这里插入图片描述
显示的内容是response对象;其中呢data就是要的数据(data: {msg: “获取3条笑话”, jokes: Array(3)})
config和request是这次请求的一些信息,不重要

若错误的话,会在console里显示

Error: Request failed with status code 404

结果2:
显示内容为注册成功,若再次注册会发现注册失败因重复注册。

错误的话会在39行(console.log(err))处显示
Error: Request failed with status code 404
为错误提示代码

总结:
1.axios必须先导入才能使用
2.使用get或post方法即可发送对应的请求
3.then方法中的回调函数会在请求成功或失败时触发
4.通过回调函数的形参可以获取响应内容,或错误信息,
axios官网
https://github.com/axios/axios

axios加vue:

axios如何结合vue开发网络应用

网络应用的核心是“data”中的数据是通过网络获取到的。所以呢在方法中发送网络请求,在响应回来之后,把服务器返回的数据设置给data中对应的值就可以了
将曾经的“this.xxxx”改变。

目标:随机获得笑话然后渲染到用户界面上
定义(模板):
Vue:

var app = new Vue({
    el:"#app",
    data:{
        joke:"很好笑的笑话"
    },
    methods:{
        getJoke:function(){
            axios.get("地址").then(function(response){
                // joke
            },function(err){})
        }
    },
})

html结构:

 <div id="app">
     <input type="button" value="获取笑话" @click="getJoke">
     <p>{{joke}}</p>
 </div>

要测试this是否变化,下面例子使用笑话的接口
在getJoke方法内的内部和axios的内部以及response内部分别使用console.log(this.joke)会发现三个结果分别为:
“很好笑的笑话”;“‘一串笑话’”;“undefined”
发现this.joke的值会发生变化
因此需要定义一个变量保存this的值,在function中加入var that = this;,因this可以拿到joke这个值的,但是后面的axios会改变this的值,把服务器返回的数据直接返回给that的值:that.joke = response.data;

总结:
1.axios回调函数中的this已经改变,无法访问到data中的数据
2.把this保存起来,回调函数中直接使用保存的this即可
3.和本地应用比起来的最大区别就是改变了数据来源
即:需要提前保存,使用保存的值就可以了。

天知道-网络应用:

回车查询,点击查询来查询天气信息

天知道-回车查询:

输入内容后按下回车,调用接口,将输入的内容传递到服务器,再接收到服务器响应到的内容之后呢,渲染成一个列表
1.按下回车(v-on keyup.enter)
2.查询数据(axios接口,v-model)
3.渲染数据(v-for 数组 that)

天气的信息是通过调用接口实现的:

天气接口:
1.请求地址:http://wthrcdn.ethouch.cn/weather_mini
2.请求方法:get
3.请求参数:city(查询的城市名)
4.响应内容:天气信息

main.js:

var app = new Vue({
    el:"#app",
    data:{
        city:'',
        // 查询的城市
        weatherList: [],
        // 存储天气信息
    },
    methods:{
        searchWeather:function(){
            var that = this;
            // 保存this
            // 调用接口
            axios.get('http://wthrcdn.etouch.cn/weather_mini?city='+this.city).then(function(response){
                // console.log(response.data.data.forecast);
                // 来获取5个天气预报消息
                that.weatherList = response.data.data.forecast;
            }).catch(function(err){})
        }
    },
})

html结构:

<div class="wrap" id="app">
    <div class="search_form">
        <div class="logo"><img src="img/logo.png" alt="logo" /></div>
        <div class="form_group">
            <input type="text" v-model = "city" @keyup.enter="searchWeather" class="input_txt" placeholder="请输入查询的天气" />
            // v-on指令绑定searchWeather方法,v-model拿到输入的内容
            <button class="input_sub" @click="searchWeather">
                搜 索
            </button>
        </div>
        <div class="hotkey">
            <a href="javascript:;">北京</a>
            <a href="javascript:;">上海</a>
            <a href="javascript:;">广州</a>
            <a href="javascript:;">武汉</a>
        </div>
    </div>
    <ul class="weather_list">
        <li v-for = "item in weatherList">
        // v-for指令渲染拿的的数据
            <div class="info_type"><span class="iconfont ">{{item.type}}</span></div>
            <div class="info_temp">
                <b>{{item.low}}</b>
                ~
                <b>{{item.high}}</b>
            </div>
            <div class="info_date"><span>{{item.date}}</span></div>
            // 通过v-text渲染具体的数据
        </li>
    </ul>
</div>

总结:
1.应用的逻辑代码建议和页面分离,使用单独的js文件编写
2.axios回调函数中this指向改变了,需要额外保存一份
3.服务器返回的数据比较复杂时,获取的时候需要注意层级结构

天知道-点击查询:

点击输入框下方的热门城市会修改文本框的值,同时调用接口,将输入的内容传给服务器,接收到服务器响应的内容之后,渲染成一个列表的结构
1.点击城市 (v-on 自定义参数)
2.查询数据
3.渲染数据
通过this关键字调用之前使用的方法

main.js中:
加入:

        changeCity:function(city){
        //传入一个具体的城市所以要定义形参	
            this.city =city;
            // 改城市,将city值改为传入的city值。前一个city为定义的city,后一个city为该函数的形参city
            this.searchWeather();
            // 在此函数中调用searchWeather函数,直接通过点击就可以查询对应城市的天气信息
        }

html结构:
更改:

  <div class="hotkey">
      <a href="javascript:;" @click = "changeCity('北京')">北京</a>
      // 把点击事件放入,并且把实参“北京”传入button中
      <a href="javascript:;" @click = "changeCity('上海')">上海</a>
      <a href="javascript:;" @click = "changeCity('广州')">广州</a>
      <a href="javascript:;" @click = "changeCity('武汉')">武汉</a>
  </div>

总结:
1.自定义参数可以让代码的复用性更高
2.methods中定义的方法内部,可以通过this关键字点出其他方法(通过这个语法重复利用了查询天气的逻辑)

综合应用:

悦听player
1.歌曲搜索 2.歌曲播放 3.歌曲封面 4.歌曲评论 5.播放动画 6.mv播放
学习前端Vue——by盐焗西蓝花_第5张图片

音乐查询:

根据关键字查询你想听的歌
1.按下回车进行歌曲搜索(v-on .enter)
2.查询数据(axios 接口 v-model)
3.渲染数据(v-for 数组 that)

歌曲搜索接口:

请求地址:
https://autumnfish.cn/search
请求方法:get
请求参数:keywords(查询的关键字)
响应内容:歌曲搜索结果

在main.js中:

var app = new Vue({
    el:"#player",
    // 通过审查元素发现id为player的标签包裹着整个播放器
    data:{
        query:"",
        // 查询存储的内容
        musicList:[],
        // 查询存储的歌曲列表
    },
    methods:{
        searchMusic:function(){
            var that = this;
            axios.get("https://autumnfish.cn/search?keywords="+this.query).then(function(response){
                // console.log(response);
                // console.log(response.data.result.songs);
                that.musicList=response.data.result.songs;
            },function(err){ })
        }
    }
})

html结构:
通过审查元素的方法找到class="search_bar"的div标签

<!-- 搜索歌曲 -->
<input type="text" autocomplete="off" v-model="query" @keyup.enter="searchMusic">
// 使用v-model指令双向绑定数据,v-on结合事件修饰符.enter方法绑定事件搜索的逻辑

再找到class=“song_list” 的ul标签

 <li v-for="item in musicList"><a href="javascript:;"></a><b>{{ item.name }}</b><span><i></i></span></li>
 // 在下面的li标签中加入v-for指令,使用v-text指令利用点语法渲染出歌曲的名字

总结:
1.服务器返回的数据比较复杂时,获取的时候要注意层级结构
2.通过审查元素快速定位到需要操纵的元素

音乐播放:

查询出来的歌点击播放即可播放
设置歌曲地址的本质就是设置src属性,属性的设置使用v-bind指令;同时呢,在data中增加地址的属性,每次查询完之后把服务器返回的结果设置给data中的属性,绑定的结果呢会同步更新
1.点击播放(v-on 自定义参数)
2.歌曲地址获取(接口 歌曲id)
3.歌曲地址设置,结合自定义参数简化编码

歌曲url获取
1.请求地址:https://autumnfish.cn
2.请求方法:get
3.请求参数:id(歌曲id)
4.响应内容:歌曲的url地址

main.js中:
在methods中加入playMusic方法:

playMusic:function(musicId){
// 需要传输歌曲id所以设置一个新的形参musicId
    var that = this;
    axios.get("https://autumnfish.cn/song/url?id="+musicId).then(function(response){
        that.musicUrl = response.data.data[0].url;
        // 检测完id 可以用之后,就继续完善playMusic方法,使用axios来调接口
        // response.data.data[0].url  来获取具体某首音乐的播放地址;再在data中添加一个musicUrl来存储音乐的地址
    },function(){})
}

html结构中:

<ul class="song_list">
    <!-- 点击放歌 -->
    <li v-for="item in musicList"><a href="javascript:;" @click="playMusic(item.id)"></a><b>{{ item.name }}</b><span><i></i></span>
    // 然后在html页面中找到播放的那个标签,也就是li标签中的a标签,在其中加入v-on指令,写入@click="playMusic(item.id)
    </li>
</ul>

此时点击不同的歌曲的播放键,就会有不同的id显示

总结:
1.歌曲id依赖歌曲搜索的结果,对于不用的数据也需要关注

歌曲封面:

在切换歌曲的同时呢,歌曲的封面也能同步切换,不仅能听歌,还能看到精美的歌曲封面

点击审查元素,发现控制歌曲封面的div是“player_con”
其中默认的封面图片是cover.png,更改封面的本质就是更改了src属性
然后依旧发现封面是从接口中调用实现的

步骤:
1.点击播放 (在播放音乐方法内部增加获取对应歌曲封面的逻辑,同时把歌曲的id 传递给服务器)
2.歌曲封面获取 (在获取到封面的属性之后呢设置给src属性)
3.歌曲封面设置(v-bind进行绑定)

歌曲详情获取:
1.请求地址:
https://autumnfish.cn/song/detail
2.请求方法:get
3.请求参数:ids(歌曲id)
4.响应内容:歌曲详情,包含封面信息

main.js中:
在methods方法中的歌曲播放方法中加入 歌曲详情获取
在data中加入变量musicCover为歌曲封面图片

axios.get("https://autumnfish.cn/song/detail?ids="+musicId).then(function(response){
    that.musicCover = response.data.songs[0].al.picUrl;
    // 保存封面的地址
},function(err){})
// 利用axios的get方法,通过接口地址根据歌曲的id获取歌曲的封面在线图片的网址

html结构:
最后在html中通过审查元素找到src:

 <!-- 歌曲信息容器 -->
 <div class="player_con">
     <img src="images/player_bar.png" class="play_bar">
     <!-- 黑胶碟片-->
     <img src="images/disc.png" class="disc autoRotate">
     <img :src="musicCover" class="cover autoRotate">
     // ./images/cover.png的改为变量musicCover,同时将src 改为v-bind形式,即其缩写形式“:src”
 </div>

总结:
1.在vue中通过v-bind操纵属性(src 属性)
2.对于本地无法获取的数据,基本都会有对应的接口

歌曲评论:

在点击播放的同时,同步的显示这首歌的热门评论
1.点击播放:评论的获取呢和音乐的播放,专辑封面图片的获取是同步进行的,所以继续在音乐播放的这个方法后面呢增加逻辑
2.歌曲评论获取:(接口 歌曲id)
3.歌曲评论渲染:歌曲评论渲染(v-for);拿到了之后通过v-for指令在页面上渲染一个列表结构

热门评论的获取的接口的调用:
1.请求地址:https://autumnfish.cn/comment/hot?type=0
2.请求方法:get
3.请求参数:id(歌曲id,type固定为0)
4.响应内容:歌曲的热门评论

main.js中:
在playMusic函数中加入axios方法获取歌曲热门评论

// 歌曲评论获取
axios.get("https://autumnfish.cn/comment/hot?type=0&id="+musicId).then(function(response){
    // get 方法中不同于之前在后面写入“?=”再+musicId,这里呢在type=0后拼接上一个&id=
    that.hotComments = response.data.hotComments;
},function(err){})

html结构:
通过审查元素发现需要改的标签呢为dl标签

 <!-- 歌曲容器 -->
 <div class="comment_wrapper" ref='comment_wrapper'>
     <h5 class="title">热门留言</h5>
     <div class='comment_list'>
         <dl v-for="item in hotComments">
             <dt><img :src="item.user.avatarUrl" alt=""></dt>
             // 用户头像
             <dd class="name">{{ item.user.nickname }}</dd>
             // 用户名字
             <dd class="detail">
             // 用户评论信息
                 {{ item.content }}
             </dd>
         </dl>
     </div>
     //在后面呢加入v-for指令,写入item in hotComments;
     //并且根据用户头像 :src="item.user.avatarUrl",用户名{{ item.user.nickname }},用户评论{{ item.content }}来渲染在页面上
     <img src="images/line.png" class="right_line">
 </div>

总结:
点击播放的同时。歌曲播放、专辑封面显示和热门评论显示同时显示

播放动画:

在播放时碟片不会动,应该在播放时碟片旋转,暂停时碟片固定不动

核心:增删一个类;播放和暂停有自己各自一个事件,只需在各自的事件中增删类名就好了

在审查元素中发现,播放时在div中类名class会加入playing,暂停时class中就没有playing
步骤:
1.监听音乐播放 (v-on play)
2.监听音乐暂停 (v-on pause)
3.操纵类名(v-bind 对象);两种状态:有/无–>data中加入一个布尔值
不需要调用接口,操纵类名即可,类名切换需要在事件中完成,通过事件知道是播放还是暂停,需要用到v-on指令

main.js中:
在methods加入两个新的方法,第一个为play方法,第二个为pause方法

        play:function(){
            console.log("play");
            this.isPlaying = true;
        },
        pause:function(){
            console.log("pause");
            this.isPlaying = false;
        }
        // 发现点击“播放”和“暂停”的话,在后台都会显示“play”和“pause”
        // 在play和pause两个function中,加入逻辑this.isPlaying = true和this.isPlaying = false

html结构中:
找到audio标签

<div class="audio_con">
    <audio ref='audio' @play="play" @pause="pause" :src="musicUrl" controls autoplay loop class="myaudio"></audio>
    // 添加v-on指令,缩写为@:@play="play" @pause="pause" 
</div>

再找到class=player_con的div标签

<!-- 歌曲信息容器 -->
<div class="player_con" :class="{playing:isPlaying}">
// 写入 :class="{playing:isPlaying}"
// 由css中提前写入的判断条件来确定;playing 是预先写好的转的css动画格式,对象形式t/f来选择是否触发
    <img src="images/player_bar.png" class="play_bar">
    <!-- 黑胶碟片-->
    <img src="images/disc.png" class="disc autoRotate">
    <img :src="musicCover" class="cover autoRotate">
</div>

播放mv:

通过审查元素发现播放mv 的标签为video标签,会发现src标签内的为播放mv的地址(即在线视频地址),更换不同的mv的本质就是设置src的地址为一个新值
显示和隐藏的(点击周围的黑色发现一个div中的style标签变了)本质就是改变该div的样式(通过v-show),通过接口获取mv的地址;mv图标有的有有的没有,因为不同的歌有或没有mvid,显示或者不显示依赖于mvid

步骤:
1.mv图标显示(v-if,因为不用频繁切换显示)
2.mv地址获取(v-on指令 获取接口)
3.遮罩层(v-show v-on)
4.mv地址设置(v-bind)

mv地址获取
请求地址:https://autumnfish.cn/mv/url
请求方法:get
请求参数:id(mvid,为0则说明没有mv)
响应内容:mv的地址

任意搜索一个人的歌,根据显示的列表,查找每一首歌的mvid,若为0则表示为无mv,若不为0则表示有mv可以播放;在审查元素中发现,mv的图标在li标签下的span标签。在span标签后写入v-if=“item.mvid!=0”
html结构中:

<ul class="song_list">
    <!-- 点击放歌 -->
    <li v-for="item in musicList"><a href="javascript:;" @click="playMusic(item.id)"></a><b>{{ item.name }}</b>
    <span v-if="item.mvid!=0" @click="playMV(item.mvid)"><i></i></span></li>
    // 找到span标签,后面写入v-on指令和v-if指令,绑定为点击事件
</ul>

点击mv图标要播放mv,播放mv的本质就是通过接口获取mv的地址,设置给对应地址的标签,同时呢弹出播放的界面。

继续在main.js里面:
写一个新的方法“播放mv”playMv方法

// 播放mv
playMV:function(mvid){
    var that = this;
    axios.get("https://autumnfish.cn/mv/url?id="+mvid).then(function(response){
        // 在axios中的get方法里写入接口+"?id"(但此id为mvid,书写为id)后面写好response,
		// 根据审查元素发现response.data.data.url为mv的在线播放地址
        that.isShow = true;
        that.mvUrl = response.data.data.url;
    },function(err){})
},
// 隐藏遮罩层
hide:function(){
    this.isShow = false;
},

获取完mv的地址后,需要做出弹出遮罩层,然后弹出播放mv的界面
通过审查元素找到mv的div标签为class=“video_con”:

<div class="video_con" v-show ="isShow" style="display:none;">
    <video :src="mvUrl" controls="controls"></video>
    // 具体的播放标签为controls
    // 在vedio标签中加入:src="mvUrl" 
<div class="mask" @click="hide"></div>
</div>

回到main.js中,添加两个变量,分别为
// 遮罩层的显示 isShow:false,
// mv地址 mvUrl:"",

总结:
1.不同的接口需要的数据是不同的,文档的阅读需要仔细
2.页面结构复杂之后,通过审查元素的方法去快速定位相关元素
3.响应的元素需要在data中定义,无论是本地应用还是网络应用

你可能感兴趣的:(javascript,vue.js)