文章目录
Vue简介
- Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架
- Vue 只关注视图层, 采用自底向上增量开发的设计
- Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件
- JavaScript框架
- 简化Dom操作
- 响应式数据驱动
第一个Vue程序
-
导入Vue并测试
<body> <div id="app"> {{message}} </div> <script src="vue.js"></script> <script> var app = new Vue({ el:"#app", data:{ message:"Hello Vue" } }) </script> </body>
el:挂载点
-
el通过选择器设置Vue实例管理的元素
-
{{}}修饰的部分会被Vue中的data属性同名参数替换掉
-
Vue实例的作用范围是什么?
<body> {{message}} <div id="app"> {{message}} <span>{{message}}</span> </div>
- 打开网页发现除了外部的无法渲染内部的都能成功渲染,说明元素内部嵌套也会被Vue管理
-
是否可以使用其他的选择器?
<div id="app" class="app"> {{message}} <span>{{message}}</span> </div> <script src="vue.js"></script> <script> var app = new Vue({ //el: "#app", //el: ".app", el: "div", data: { message: "Hello Vue" } }) </script> </body>
- 发现多种选择器都可以成功选中元素并渲染
-
是否可以设置其他的dom元素?
- 肯定可以,但只能支持双标签,因为单标签没有内部,也不能在
<html>
和<body>
中使用
- 肯定可以,但只能支持双标签,因为单标签没有内部,也不能在
data:数据对象
-
Vue中用到的数据定义在data中
-
data中可以写复杂类型的数据
-
渲染复杂类型数据时,遵守js的语法即可
<body> <div id="app"> {{message}} <span>{{school.name}} {{school.age}}</span> <ul> <li>{{hobby[0]}}</li> <li>{{hobby[1]}}</li> <li>{{hobby[2]}}</li> </ul> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: { message: "Hello Vue", school:{ name:"cbc", age:"3" }, hobby:["上网","玩游戏","看视频"] } }) </script> </body>
本地应用
v-text
-
设置标签的文本值(textContent)
<body> <div id="app"> <h2 v-text="message + '!'"></h2> <!--可以插值--> <h2>你好{{message+"!"}}</h2> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: { message:"hello" } }) </script> </body>
v-html
-
设置标签的innerHTML
<body> <div id="app"> <h2 v-html="content"></h2> <!--与v-text的区别就是v-html会解析html--> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: { content:"<a href='#'>hello</a>" } }) </script> </body>
v-on 缩写@
-
设置响应事件
<body> <div id="app"> <input type="button" value="单击事件" v-on:click="doit"> <!--点击触发--> <input type="button" value="移入事件" v-on:mouseenter="doit"> <!--移入触发--> <input type="button" value="双击事件" v-on:dblclick="doit"> <!--双击触发--> <input type="button" value="双击简写" @dblclick="doit"> <!--另一种写法--> <h2 @click="changeFood">{{ food }}</h2> <!--更改元素--> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data:{ food: "肉蛋葱鸡" }, methods:{ //方法绑定在methods属性中 doit:function () { console.log("逻辑"); }, changeFood:function () { this.food+="很好吃"; //改变food的值 } } }) </script> </body>
-
传递自定义参数,事件修饰符
<body> <div id="app"> <input type="button" value="点击" @click="doit(666,'666')"> <!--传参--> <input type="text" @keyup.enter="sayHi"> <!--定义事件修饰,enter键弹起时触发--> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: {}, methods: { doit: function (p1, p2) { console.log("cbc" + p1 + p2); }, sayHi: function () { console.log("Hi"); } } }) </script> </body>
计数器
<body>
<div id="app">
<button @click="down">-</button>
<span v-text="num"></span>
<button @click="up">+</button>
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
num: 0
},
methods: {
down: function () {
this.num === 0 ? alert("不要再减了") : this.num--;
},
up: function () {
this.num === 10 ? alert("不要再加了") : this.num++;
}
}
})
</script>
</body>
v-show
-
根据表达式的真假,切换元素的显示和隐藏
<body> <div id="app"> <img src="111.png" alt="" v-show="true"> <!--通过修改样式实现显示和隐藏--> <button @click="changeShow">芜湖</button> <img src="111.png" alt="" v-show="isShow"> <!--方便更改--> <button @click="addAge">过了一年</button> <img src="111.png" alt="" v-show="age>=18"> <!--可放入表达式--> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: { isShow: true, age: 16 }, methods: { changeShow: function () { this.isShow = !this.isShow; }, addAge:function () { this.age++; } } }) </script> </body>
v-if
-
根据表达式的真假,切换元素的显示和隐藏(操纵dom元素)
<body> <div id="app"> <p v-if="true">我是一个p标签</p> <button @click="changeShow">芜湖</button> <p v-if="isShow">我是一个p标签</p> <!--与v-show不同之处在于v-if会直接把标签去除而不是修改样式--> <button @click="addAge">过了一年</button> <p v-if="age>=18">我是一个p标签</p> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: { isShow: true, age: 16 }, methods: { changeShow: function () { this.isShow = !this.isShow; }, addAge:function () { this.age++; } } }) </script> </body>
v-bind 缩写:
-
动态绑定属性,设置元素的属性(比如src,title,class),
v-bind:属性名=表达式
- 不写的话表示这个属性不是动态的,它的值就是你一开始所赋予的值,它的值是一个字符串
<head> <meta charset="UTF-8"> <title>Vue基础</title> <style> .active{ border: 1px solid red; } </style> </head> <body> <div id="app"> <img v-bind:src="imgSrc" v-bind:title="imgSrc+'~~~'" alt=""> <button @click="changeActive">芜湖</button> <img :class="isActive?'active':''" alt=""> <!--可简写为 :属性名=表达式--> <img :class="{active:isActive}" alt=""> <!--与使用三目运算符效果一致且更简易--> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: { imgSrc:"111.png", imgTitle:"你好", isActive:false }, methods: { changeActive: function () { this.isActive = !this.isActive; } } }) </script> </body>
图片切换
<body>
<div id="app">
<img :src="imgArr[index]" alt=""> <!--数组保存图片地址-->
<a href="javascript:void(0)" v-show="index>0" @click="prev">上一张</a>
<a href="javascript:void(0)" v-show="index<this.imgArr.length-1" @click="next">下一张</a>
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
imgArr: ["111.png", "111.png", "111.png"],
index: 0 //初始化索引为0
},
methods: {
prev: function () {
this.index--;
},
next: function () {
this.index++;
}
}
})
</script>
</body>
v-for
-
根据数据生成列表结构
<body> <div id="app"> <ul> <!--此处item代表每一项的值,index代表索引--> <li v-for="(item,index) in arr" :title="item">{{item}} {{index}} 你好</li> <button @click="add">添加数据</button> <button @click="remove">删除数据</button> <li v-for="item in objArr">{{item.name}}</li> </ul> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: { arr: ["a", "b", "c", "d", "e"], objArr: [ {name: "cbc"}, {name: "aba"} ] }, methods:{ add:function () { this.objArr.push({name:"bbb"}) }, remove:function () { this.objArr.shift(); //删除第一个 //this.objArr.pop(); //删除最后一个 } } }) </script> </body>
v-model
-
获取和设置表单元素的值(双向数据绑定),能将页面上控件输入的值同步更新到相关绑定的data属性,也会在更新data绑定属性时候,更新页面上输入控件的值
<body> <div id="app"> <input type="text" v-model="message" @keyup.enter="getM"> <!--绑定标签与值--> <h2 v-text="message"></h2> <input type="button" value="芜湖" @click="changeM"> </div> <script src="vue.js"></script> <script> var app = new Vue({ el: "#app", data: { message: "cbc" }, methods: { getM: function () { console.log(this.message); }, changeM:function () { this.message = "cbcsb"; } } }) </script> </body>
记事本
css渐入渐出示例
.destroy {
cursor: pointer; /*指定指针样式*/
opacity: 0; /*默认透明度为0*/
transition: opacity 0.2s; /*渐入渐出效果*/
-webkit-transition: opacity 0.2s;
}
/*view是destroy的父标签。鼠标移入view,destroy就会出现*/
.view:hover .destroy {
opacity: 1;
}
- 新增
- 生成列表结构(v-for数组)
- 获取用户输入(v-model)
- 回车,新增数据(v-on .enter 添加数据)
- 删除
- 点击删除指定内容(v-on splice 索引)
- 统计
- 统计信息个数(v-text length)
- 清空
- 点击清除所有信息(v-on)
- 隐藏
- 没有数据时,隐藏元素(v-show,v-if,数组非空)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue基础</title>
<link type="text/css" rel="stylesheet" href="index.css">
</head>
<body>
<!--主体区域-->
<section id="todoApp">
<!--输入框-->
<header class="header">
<h1>记事本</h1>
<input type="text" v-model="inputValue" @keyup.enter="add" autofocus="autofocus" autocomplete="off"
placeholder="请输入任务" class="new-todo">
</header>
<!--列表区域-->
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(item,index) in list"> <!--参数1为值,参数2为下标-->
<div class="view">
<span class="index">{{index+1}}.</span>
<label>{{item}}</label>
<button class="destroy" @click="remove(index)"></button> <!--下标值传参-->
</div>
</li>
</ul>
</section>
<!--统计和清空-->
<footer class="footer" v-show="list.length!=0">
<span class="todo-count"><span v-text="list.length"></span> items left</span>
<button class="clear-completed" @click="clear">
Clear
</button>
</footer>
</section>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#todoApp",
data: {
list: ["写代码", "吃饭饭", "睡觉觉"],
inputValue: ""
},
methods: {
add: function () {
this.list.push(this.inputValue);
},
remove: function (index) {
this.list.splice(index, 1); //参数1:下标 参数2:删除数量
},
clear: function () {
if (confirm("确认清空?")) {
this.list.splice(0); //清空数组
}
}
}
})
</script>
</body>
</html>
网络应用
axios
-
功能强大的网络请求库
-
导入axios
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
-
GET格式
axios.get(地址?查询字符串k=v&...).then(function(response){},function(err){})
-
POST格式
axios.post(地址,参数对象{k:v,k:v...}).then(function(response){},function(err){})
-
随机笑话接口
https://autumnfish.cn/api/joke/list
,请求方法GET,参数num<body> <input type="button" value="get请求" class="get"> <script src="vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <!--导入axios--> <script> document.querySelector(".get").onclick=function () { axios.get("https://autumnfish.cn/api/joke/list?num=3") .then(function (value) { console.log(value) }); } </script> </body>
axios + vue
<body>
<div id="app">
<input type="button" value="获取笑话" @click="getJoke" class="button"><br>
<p v-text="joke"></p>
</div>
<script src="vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
joke: "很好笑的笑话"
},
methods: {
getJoke: function () {
//var that = this;
axios.get("https://autumnfish.cn/api/joke")
.then(function (value) {
app.joke = value.data;
//that.joke = value.data; //两种方法都可行
})
}
}
})
</script>
</body>
天气预报案例
-
回车查询
- 按下回车(v-on .enter)
- 查询数据(axios 接口 v-model)
- 渲染数据(v-for 数组)
-
点击查询
- 点击城市(v-on 自定义参数)
- 查询数据(this.方法()重用)
- 渲染数据
-
天气接口
- 请求地址
http://wthrcdn.etouch.cn/weather_mini
- 请求方法:GET
- 请求参数:city (城市名)
- 响应内容:天气信息
- 请求地址
-
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue基础</title> <link type="text/css" rel="stylesheet" href="css/index.css"> <link type="text/css" rel="stylesheet" href="css/reset.css"> </head> <body> <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="请输入查询的天气"> <button class="input_sub">搜 索</button> </div> <div class="hotkey"> <a href="javascript:;" @click="changeCity('北京')">北京</a> <a href="javascript:;" @click="changeCity('上海')">上海</a> <a href="javascript:;" @click="changeCity('广州')">广州</a> <a href="javascript:;" @click="changeCity('深圳')">深圳</a> <a href="javascript:;" @click="changeCity('宜春')">宜春</a> </div> </div> <ul class="weather_list"> <li v-for="item in weatherList"> <div class="info_type"><span class="iconfont" v-text="item.type"></span></div> <div class="info_temp"> <b v-text="item.low"></b> ~ <b v-text="item.high"></b> </div> <div class="info_date"><span v-text="item.date"></span></div> </li> </ul> </div> <script src="js/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="js/main.js"></script> </body> </html>
-
main.js
var app = new Vue({ el: "#app", data: { city: '', weatherList: [] }, methods: { searchWeather: function () { // 调用接口 axios.get('http://wthrcdn.etouch.cn/weather_mini?city=' + this.city) .then(function (response) { app.weatherList = response.data.data.forecast; }) .catch(function (err) { alert("城市未找到") }) }, changeCity:function (city) { this.city = city; this.searchWeather(); } } });
综合应用
播放器案例
-
歌曲搜索
- 按下回车(v-on .enter)
- 查询数据(axios 接口 v-model)
- 渲染数据(v-for 数组)
- 接口
https://autumnfish.cn/search
- 请求方法:GET
- 请求参数:keywords (查询的关键字)
- 响应内容:歌曲搜索结果
-
歌曲播放
- 点击播放(v-on 自定义参数)
- 歌曲地址获取(接口 歌曲id)
- 歌曲地址设置(v-bind)
- 接口
https://autumnfish.cn/song/url
- 请求方法:GET
- 请求参数:id (歌曲id)
- 响应内容:歌曲的url地址
-
歌曲封面
- 点击播放(增加逻辑)
- 歌曲封面获取(接口 歌曲id)
- 歌曲封面设置(v-bind)
- 接口
https://autumnfish.cn/song/detail
- 请求方法:GET
- 请求参数:ids (歌曲id)
- 响应内容:歌曲详细,包含封面信息
-
歌曲评论
- 点击播放(增加逻辑)
- 歌曲评论获取(接口 歌曲id)
- 歌曲评论渲染(v-for)
- 接口
https://autumnfish.cn/comment/hot?type=0
- 请求方法:GET
- 请求参数:id (歌曲id,type固定为0)
- 响应内容:歌曲热门评论
-
播放动画
- 监听音乐播放(v-on play)
- 监听音乐暂停(v-on pause)
- 操纵类名(v-bind 对象)
-
mv播放
- mv图标显示(v-if)
- mv地址获取(接口 mvid)
- 遮罩层(v-show v-on)
- mv地址设置(v-bind)
- 接口
https://autumnfish.cn/mv/url
- 请求方法:GET
- 请求参数:id (mvid,为0说明没有mv)
- 响应内容:mv的地址
-
html
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta http-equiv="X-UA-Compatible" content="ie=edge"/> <title>++player</title> <!-- 样式 --> <link rel="stylesheet" href="./css/index.css"> </head> <body> <div class="wrap"> <!-- 播放器主体区域 --> <div class="play_wrap" id="player"> <div class="search_bar"> <img src="images/player_title.png" alt=""> <!-- 搜索歌曲 --> <input type="text" autocomplete="off" v-model="query" @keyup.enter="searchMusic"> </div> <div class="center_con"> <!-- 搜索歌曲列表 --> <div class='song_wrapper'> <ul class="song_list"> <li v-for="item in musicList"> <a href="javascript:;" @click="playMusic(item.id)"></a> <b v-text="item.name"></b> <span v-if="item.mvid!=0"><i @click="playMV(item.mvid)"></i></span> </li> </ul> <img src="images/line.png" class="switch_btn" alt=""> </div> <!-- 歌曲信息容器 --> <div class="player_con" :class="{playing:isPlaying}"> <img src="images/player_bar.png" class="play_bar"/> <!-- 黑胶碟片 --> <img src="images/disc.png" class="disc autoRotate"/> <img :src="musicCover" class="cover autoRotate"/> </div> <!-- 评论容器 --> <div class="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" v-text="item.nickname"></dd> <dd class="detail" v-text="item.content"></dd> </dl> </div> <img src="images/line.png" class="right_line"> </div> </div> <div class="audio_con"> <audio ref='audio' @play="play" @pause="pause" :src="musicUrl" controls autoplay loop class="myaudio"></audio> </div> <div class="video_con" v-show="isShow" style="display: none"> <video ref="video" controls="controls" :src="mvUrl"></video> <div class="mask" @click="hide"></div> </div> </div> </div> <script src="js/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="js/main.js"></script> </body> </html>
-
main.js
var app = new Vue({ el: "#player", data: { // 查询关键字 query: "", // 歌曲数组 musicList: [], // 歌曲地址 musicUrl: "", // 歌曲封面 musicCover: "", // 歌曲评论 hotComments: [], // 动画播放状态 isPlaying: false, // 遮罩层的显示状态 isShow: false, // mv地址 mvUrl: "" }, methods: { // 歌曲搜索 searchMusic: function () { axios.get("https://autumnfish.cn/search?keywords=" + this.query).then( function (response) { app.musicList = response.data.result.songs; }, function (err) { } ); }, // 歌曲播放 playMusic: function (musicId) { // 获取歌曲地址 axios.get("https://autumnfish.cn/song/url?id=" + musicId).then( function (response) { app.musicUrl = response.data.data[0].url; }, function (err) { } ); // 歌曲详情获取 axios.get("https://autumnfish.cn/song/detail?ids=" + musicId).then( function (response) { app.musicCover = response.data.songs[0].al.picUrl; }, function (err) { } ); // 歌曲评论获取 axios.get("https://autumnfish.cn/comment/hot?type=0&id=" + musicId).then( function (response) { console.log(response.data.hotComments); app.hotComments = response.data.hotComments; }, function (err) { } ); }, // 歌曲播放 play: function () { this.isPlaying = true; }, // 歌曲暂停 pause: function () { this.isPlaying = false; }, // 播放mv playMV: function (mvid) { axios.get("https://autumnfish.cn/mv/url?id=" + mvid).then( function (response) { app.isShow = true; app.mvUrl = response.data.data.url; }, function (err) { } ); }, // 隐藏 hide: function () { this.isShow = false; this.$refs.video.pause(); } } });
在vue中获取标签
- 第一步:在标签中添加ref="xx"属性
- 第二步:this.$refs.xx.属性="" 此步骤是以xx为标记选中了要操作的标签,通过点属性的方法,进行赋值来修改该标签的属性
-v-clock解决闪烁问题
<style>
[v-clock] {
display: none;
}
</style>