第一天准备文件:
链接:https://pan.baidu.com/s/14Cd_aMQMsgMTZi72AefZ1g?pwd=6666
提取码:6666
Vue是一个用于构建用户界面的渐进式框架
1.构建用户界面:基于数据动态渲染页面
2.渐进式:循序渐进的学习
3.框架:一套完整的项目解决方案,提升开发效率
创建Vue实例,初始化渲染
比如:
<div id="app">
<div>
在安装时选择开发版本,因为开发版本包含完整的警告和调试模式
如果不想安装,可以用用一下语句直接导入
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
//一旦引入VueJS核心包,在全局环境,就有了Vue构造函数
const app = new Vue()
script>
el指定挂载点,选择器指定控制的是哪个盒子
data提供数据
比如在第三步的基础上:
<script>
const app = new Vue({
el:'#app',
data:{
msg:'Hello 黑马'
}
})
script>
上述代码指控制id为app的盒子,数据为‘Hello 黑马’
再将第一步的div盒子更改为:
<div id="app">
{{msg}}
div>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
{{msg}}
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el:'#app',
data:{
msg:'Hello 黑马'
}
})
script>
body>
html>
插值表达式{{ }}
插值表达式是一种Vue的模板语法
利用表达式进行插值,渲染到页面中
表达式:是可以被求值的代码,JS引擎会将其计算出一个结果
{{ 表达式 }}
比如:
<div id="app">
{{msg}}
div>
(1)使用的数据必须存在,要事先声明
(2)支持的是表达式,而不是语句,比如:if for…
例如以下是错误的:
<p>
{{ if }}
p>
(3)不能再标签属性中使用{{ }}插值
例如以下是错误的:
<p title="{{ username }}">
p>
实践案例如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<p>{{ nickname }}p>
<p>{{ nickname.toUpperCase() }}p>
<p>{{ nickname + '你好' }}p>
<p>{{ age>=18 ? '成年' : '未成年' }}p>
<p>{{ friend.name }}p>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el:'#app',
data:{
nickname: 'tony',
age: 18,
friend: {
name: 'jepson',
desc: '热爱学习'
}
}
})
script>
body>
html>
数据改变,视图自动更新
访问数据:“实例.属性名”
例如:在上一个案例实践的网页中,按f12进入控制台输入一下代码,成功访问数据
修改数据:“实例.属性名”=“值”
例如:在上一个案例实践的网页中,按f12进入控制台输入一下代码,成功修改数据
1.点击链接打开极简网址
2.搜索Vue
3.安装Vue Devtools
4.点击推荐下载
5.下载完成后解压
6.打开管理扩展程序
7.将刚下载解压好的后缀为.crx的程序拖拽到下图所示页面的空白部分中
8.弹出提示框,点击添加扩展程序
9.安装完成后点击插件详情
10.将允许访问文件网址打开
11.重启浏览器(一定要重启,不是刷新),插件生效
1.如图点击扩展
2.在弹出的窗口中选择“打开Microsoft Edge加载项”
3.在新窗口中搜索vue
4.安装Vue.js devtools
5.安装完成后,点击管理扩展
6.点击Vue.js devtools的“详细信息”,将“允许访问文件URL”打上勾
7.重启浏览器(一定要重启,不是刷新),插件生效
Vue会根据不同的指令,针对标签实现不同的功能
指令:带有v-前缀的特殊标签属性
<div v-html="表达式">div>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<div v-html="msg">div>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el:'#app',
data:{
msg:`
黑马程序员
`//注意``是模版字符串,不要省略
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
.box{
height: 50px;
width: 100px;
border-radius: 5px;
text-align: center;
border: solid 3px;
padding: 10px;
margin: 10px;
}
style>
head>
<body>
<div id="app">
<div v-show="flag" class="box">我是v-show控制的盒子div>
<div v-if="flag" class="box">我是v-if控制的盒子div>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el:'#app',
data:{
flag:true
}
})
script>
body>
html>
flag:true//当flag元素为true时,id为app的控件显示
效果如图:
flag:false//当flag元素为false时,id为app的控件不显示
<p v-if="表达式">我是一个p标签p>
<p v-else-if="表达式">我是一个p标签p>
<p v-else>我是一个p标签p>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<p v-if="gender === 1">性别:♂ 男p>
<p v-else>性别:♀ 女p>
<hr>
<p v-if="score >= 90">成绩评定A:奖励电脑一台p>
<p v-else-if="score >= 70">成绩评定B:奖励周末郊游p>
<p v-else-if="score >= 60">成绩评定C:奖励零食礼包p>
<p v-else>成绩评定D:惩罚一周不能玩手机p>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el:'#app',
data:{
gender: 2,
score: 80
}
})
script>
body>
html>
<button v-on:click="count--">我是一个按钮button>
②v-on:事件名=“methods中的函数名”
例如:
<button v-on:click="fn">我是一个按钮button>
<button @click="fn">我是一个按钮button>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<button v-on:click="count--">-button>
<span>{{ count }}span>
<button @click="count++">+button>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el:'#app',
data:{
count: 100
}
})
script>
body>
html>
②v-on:事件名="methods中的函数名"的案例
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<button @click="fn">切换显示隐藏button>
<h1 v-show="isshow">黑马程序员h1>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app2 = new Vue({
el:'#app',
data:{
isshow: true
},
methods:{
fn(){
//此处的语句可以替换为app2.isshow = !app2.isshow,但鼓励下面的做法,更利于代码的维护
this.isshow = !this.isshow
}
}
})
script>
body>
html>
<button @click="fn(参数一,参数二)">
按钮
button>
const app= new Vue({
el:#app,
methods:{
fn (a, b) {
console.log('这是一个fn函数')
}
}
})
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
.box {
border: 3px solid #000000;
border-radius: 10px;
padding: 20px;
margin: 20px;
width: 200px;
}
h3 {
margin: 10px 0 20px 0;
}
p {
margin: 20px;
}
style>
head>
<body>
<div id="app">
<div class="box">
<h3>小黑自动售货机h3>
<button @click="buy(5)">可乐5元button>
<button @click="buy(10)">咖啡10元button>
<button @click="buy(8)">牛奶8元button>
div>
<p>银行卡余额:{{ money }}元p>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
money: 100
},
methods: {
buy (price) {
this.money -= price
}
}
})
script>
body>
html>
<img v-bind:属性名="表达式">
<img :属性名="表达式">
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<img v-bind:src="imgUrl" v-bind:title="msg" alt="">
<img :src="imgUrl" :title="msg" alt="">
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el:'#app',
data:{
imgUrl:'./imgs/10-01.png',
msg:'hello 波仔'
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<button v-show="index > 0" @click="index--">上一页button>
<div>
<img :src="list[index]" alt="">
div>
<button v-show="index < list.length - 1" @click="index++">下一页button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
index:0,
list: [
'./imgs/11-00.gif',
'./imgs/11-01.gif',
'./imgs/11-02.gif',
'./imgs/11-03.gif',
'./imgs/11-04.png',
'./imgs/11-05.png',
]
}
})
script>
body>
html>
<li v-for="(item,index) in list">我是一个li标签li>
<li v-for="item in list">我是一个li标签li>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<h3>小黑水果店h3>
<ul>
<li v-for="(item,index) in list">{{ item }} - {{ index }}li>
ul>
<ul>
<li v-for="item in list">{{ item }}li>
ul>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el:'#app',
data:{
list:['西瓜','苹果','鸭梨']
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<h3>小黑的书架h3>
<ul>
<li v-for="(item,index) in booksList" :key="item.id">
<span>{{ item.name }}span>
<span>{{ item.author }}span>
<button @click="del(item.id)">删除button>
li>
ul>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
booksList: [
{ id: 1, name: '《红楼梦》', author: '曹雪芹' },
{ id: 2, name: '《西游记》', author: '吴承恩' },
{ id: 3, name: '《水浒传》', author: '施耐庵' },
{ id: 4, name: '《三国演义》', author: '罗贯中' }
]
},
methods:{
del ( id ) {
//通过id进行删除数组中的对应项
//filter(不会改变原数组):根据条件,保留满足条件的对应项,得到一个新数组
this.booksList=this.booksList.filter(item => item.id != id)
}
}
})
script>
body>
html>
<li v-for="(item,index) in 数组" :key="唯一值">
<input type="text" v-model="变量">
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
账户:<input type="text" v-model="username"> <br><br>
密码:<input type="password" v-model="password"> <br><br>
<button @click="login">登录button>
<button @click="reset">重置button>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
username:'',
password:''
},
methods:{
login(){
console.log(this.username,this.password)
},
reset(){
this.username='',
this.password=''
}
}
})
script>
body>
html>
1.列表渲染
v-for key的设置,{{}}插值表达式
2.删除功能
①v-on调用传参
②filter过滤,覆盖原数组
3.添加功能
①通过v-model绑定输入框 -> 实时获取表单元素的内容
②点击按钮,进行新增,往数组最前面加unshift
4.底部统计和清空
①数组.length累计长度
②覆盖数组清空列表
③v-show控制隐藏
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./css/index.css" />
<title>记事本title>
head>
<body>
<section id="app">
<header class="header">
<h1>小黑记事本h1>
<input v-model="todoName" placeholder="请输入任务" class="new-todo" />
<button @click="add" class="add">添加任务button>
header>
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(item,index) in list" :key="item.id">
<div class="view">
<span class="index">{{ index + 1 }}span> <label>{{ item.name }}label>
<button @click="del(item.id)" class="destroy">button>
div>
li>
ul>
section>
<footer class="footer" v-show="list.length > 0">
<span class="todo-count">合 计:<strong> {{list.length}}strong>span>
<button @click="clear" class="clear-completed">
清空任务
button>
footer>
section>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
todoName:'',
list:[
{id: 1, name: '跑步一公里'},
{id: 2, name: '跳绳200次'},
{id: 3, name: '游泳100米'}
]
},
methods:{
del(id){
this.list = this.list.filter( item =>item.id !== id)
},
add(){
//trim()去除空格
if(this.todoName.trim() === ''){
alert('请输入任务名称')
return
}
//unshift()增加到数组的最前面
this.list.unshift({
id: +new Date(),//用时间戳临时作为id
name:this.todoName,
})
this.todoName=''
},
clear(){
this.list=[]
}
}
})
script>
body>
html>
第二天准备文件:
链接:https://pan.baidu.com/s/1_3NUO6dKECpi7OmV5VMSzg?pwd=6666
提取码:6666
通过"."指明一些指令后缀,不同后缀封装了不同的处理操作
@keyup.enter 用于键盘回车监听(较为常用)
例如:
<input @keyup.enter="add" v-model="todoName"/>
<input v-model.trim="username" type="text"><br>
<input v-model.number="age" type="text"><br>
<div @click="alert('老父亲被点击了')" class="father">
<div @click.stop="alert('儿子被点击了')" class="son">儿子div>
div>
<a @click.prevent="notLink" href="http://www.baidu.com">阻止默认行为a>
语法:
:class=“对象/数组”
①对象->键就是类名,值是布尔值。如果值为true,有这个类,否则没有这个类
适用场景:一个类名,来回切换
<div class="box" :class="{ 类名1: 布尔值, 类名2: 布尔值 }">div>
②数组->数组中所有的类,都会添加到盒子上,本质就是一个class列表
适用场景:批量添加或删除类
<div class="box" :class="[类名1, 类名2 ,类名3 ]">div>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
}
ul {
display: flex;
border-bottom: 2px solid #e01222;
padding: 0 10px;
}
li {
width: 100px;
height: 50px;
line-height: 50px;
list-style: none;
text-align: center;
}
li a {
display: block;
text-decoration: none;
font-weight: bold;
color: #333333;
}
li a.active {
background-color: #e01222;
color: #fff;
}
style>
head>
<body>
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="item.id" @click="activeIndex = index">
<a :class="{ active: index===activeIndex }" href="#">{{item.name}}a>li>
ul>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
activeIndex: 0, //存储选中的下标
list: [
{ id: 1, name: '京东秒杀' },
{ id: 2, name: '每日特价' },
{ id: 3, name: '品类秒杀' }
]
}
})
script>
body>
html>
<div class="box" :style="{ CSS属性名1: CSS属性, CSS属性名2: CSS属性}">div>
代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
.progress {
height: 25px;
width: 400px;
border-radius: 15px;
background-color: #272425;
border: 3px solid #272425;
box-sizing: border-box;
margin-bottom: 30px;
}
.inner {
width: 50%;
height: 20px;
border-radius: 10px;
text-align: right;
position: relative;
background-color: #409eff;
background-size: 20px 20px;
box-sizing: border-box;
transition: all 1s;
}
.inner span {
position: absolute;
right: -20px;
bottom: -25px;
}
style>
head>
<body>
<div id="app">
<div class="progress">
<div class="inner" :style="{width: percent + '%'}">
<span>{{percent + '%'}}span>
div>
div>
<button @click="percent=25">设置25%button>
<button @click="percent=50">设置50%button>
<button @click="percent=75">设置75%button>
<button @click="percent=100">设置100%button>
div>
<script src="./vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
percent: 30
}
})
script>
body>
html>
常见的表单元素都可以用v-model绑定关联 -> 快速获取或设置表单元素的值
他会根据控件类型自动选取正确的方法来更新元素
案例实践如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
textarea {
display: block;
width: 240px;
height: 100px;
margin: 10px 0;
}
style>
head>
<body>
<div id="app">
<h3>小黑学习网h3>
姓名:
<input type="text" v-model="username">
<br><br>
是否单身:
<input type="checkbox" v-model="isSingle">
<br><br>
性别:
<input v-model="gender" type="radio" name="gender" value="1">男
<input v-model="gender" type="radio" name="gender" value="2">女
<br><br>
所在城市:
<select v-model="cityId">
<option value="101">北京option>
<option value="102">上海option>
<option value="103">成都option>
<option value="104">南京option>
select>
<br><br>
自我描述:
<textarea v-model="desc">textarea>
<button>立即注册button>
div>
<script src="./vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
username:'',
isSingle:false,
gender:"",
cityId:'101',
desc:""
}
})
script>
body>
html>
computed: {
计算属性名(){
基于现有数据,编写求值逻辑
return 结果
}
}
案例实践
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
table {
border: 1px solid #000;
text-align: center;
width: 240px;
}
th,td {
border: 1px solid #000;
}
h3 {
position: relative;
}
style>
head>
<body>
<div id="app">
<h3>小黑的礼物清单h3>
<table>
<tr>
<th>名字th>
<th>数量th>
tr>
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ item.name }}td>
<td>{{ item.num }}个td>
tr>
table>
<p>礼物总数:{{ totalCount }} 个p>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
// 现有的数据
list: [
{ id: 1, name: '篮球', num: 1 },
{ id: 2, name: '玩具', num: 2 },
{ id: 3, name: '铅笔', num: 5 },
]
},
computed:{
//注意是属性不是函数
totalCount(){
//0表示求和起始值,reduce遍历list,将每个item的值加上后返回给sum
let total= this.list.reduce((sum, item) => sum + item.num, 0)
return total
}
}
})
script>
body>
html>
计算属性默认的简写,只能读取访问,不能“修改”
如果要**“修改”,需要写计算属性的完整写法**
简写:
computed: {
计算属性名(){
一段代码逻辑(计算逻辑)
return 结果
}
}
完整写法:
computed: {
计算属性名(){
get(){
一段代码逻辑(计算逻辑)
return 结果
},
set(修改的值){
一段代码逻辑(修改逻辑)
}
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./styles/index.css" />
<title>Documenttitle>
head>
<body>
<div id="app" class="score-case">
<div class="table">
<table>
<thead>
<tr>
<th>编号th>
<th>科目th>
<th>成绩th>
<th>操作th>
tr>
thead>
<tbody v-if="list.length > 0">
<tr v-for="(item,index) in list" :key="item.id">
<td>{{ index+1 }}td>
<td>{{ item.subject }}td>
<td :class="{ red: item.score < 60 }">{{item.score}}td>
<td><a @click.prevent="del(item.id)" href="www.baidu.com">删除a>td>
tr>
tbody>
<tbody v-else>
<tr>
<td colspan="5">
<span class="none">暂无数据span>
td>
tr>
tbody>
<tfoot>
<tr>
<td colspan="5">
<span>总分:{{ totalScore }}span>
<span style="margin-left: 50px">平均分:{{ averageScore }}span>
td>
tr>
tfoot>
table>
div>
<div class="form">
<div class="form-item">
<div class="label">科目:div>
<div class="input">
<input
type="text"
placeholder="请输入科目"
v-model.trim="subject"
/>
div>
div>
<div class="form-item">
<div class="label">分数:div>
<div class="input">
<input
type="text"
placeholder="请输入分数"
v-model.number="score"
/>
div>
div>
<div class="form-item">
<div class="label">div>
<div class="input">
<button @click="add" class="submit" >添加button>
div>
div>
div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
list: [
{ id: 1, subject: '语文', score: 20 },
{ id: 7, subject: '数学', score: 99 },
{ id: 12, subject: '英语', score: 70 },
],
subject: '',
score: ''
},
methods: {
del(id){
//filter():筛选,根据id判断筛选内容是否符合条件,若不等则返回给list
this.list = this.list.filter(item => item.id !== id)
},
add(){
if(!this.subject){
alert("请输入科目")
return
}
if(typeof this.score !== 'number'){
alert("请输出正确的成绩")
return
}
//往前面加unshift,往后面加push
this.list.unshift({
id: +new Date(),
subject: this.subject,
score: this.score
})
this.subject=''
this.score=''
}
},
computed:{
totalScore(){
return this.list.reduce((sum, item) => sum+item.score , 0)
},
averageScore(){
if(this.list.length === 0){
return 0
}
//计算属性可以直接使用,toFixed(2)保留两位小数
return (this.totalScore / this.list.length).toFixed(2)
}
}
})
script>
body>
html>
data:{
words:'苹果',
obj:{
words:'苹果'
}
},
watch: {
数据属性名(newValue, oldValue) {
一些业务逻辑 或 异步操作
},
'对象.属性名'(newValue, oldValue) {
一些业务逻辑 或 异步操作
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 18px;
}
#app {
padding: 10px 20px;
}
.query {
margin: 10px 0;
}
.box {
display: flex;
}
textarea {
width: 300px;
height: 160px;
font-size: 18px;
border: 1px solid #dedede;
outline: none;
resize: none;
padding: 10px;
}
textarea:hover {
border: 1px solid #1589f5;
}
.transbox {
width: 300px;
height: 160px;
background-color: #f0f0f0;
padding: 10px;
border: none;
}
.tip-box {
width: 300px;
height: 25px;
line-height: 25px;
display: flex;
}
.tip-box span {
flex: 1;
text-align: center;
}
.query span {
font-size: 18px;
}
.input-wrap {
position: relative;
}
.input-wrap span {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 12px;
}
.input-wrap i {
font-size: 20px;
font-style: normal;
}
style>
head>
<body>
<div id="app">
<div class="query">
<span>翻译成的语言:span>
<select>
<option value="italy">意大利option>
<option value="english">英语option>
<option value="german">德语option>
select>
div>
<div class="box">
<div class="input-wrap">
<textarea v-model="obj.words">textarea>
<span><i>⌨️i>文档翻译span>
div>
<div class="output-wrap">
<div class="transbox">{{ result }}div>
div>
div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
<script>
// 接口地址:https://applet-base-api-t.itheima.net/api/translate
// 请求方式:get
// 请求参数:
// (1)words:需要被翻译的文本(必传)
// (2)lang: 需要被翻译成的语言(可选)默认值-意大利
// -----------------------------------------------
const app = new Vue({
el: '#app',
data: {
// words: ''
obj: {
words: ''
},
result:'',//翻译结果
timer: null
},
// 具体讲解:(1) watch语法 (2) 具体业务实现
watch: {
// 该方法会在数据变化时调用执行
// newValue新值, oldValue老值(一般不用)
// words (newValue) {
// console.log('变化了', newValue)
// }
'obj.words' (newValue) {
//console.log('变化了', newValue)
//防抖:延迟执行 -> 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
//这里是ajax的内容
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params:{
words:newValue
}
})
this.result = res.data.data
console.log(res.data.data)
}, 300)
}
}
})
script>
body>
html>
data:{
obj:{
words:'苹果',
lang:'italy'
}
},
watch: {
数据属性名(newValue, oldValue) {
deep: true,//深度监视
handler(newValue){
console.log(newValue)
}
}
}
案例演示:
需求:在上个案例的基础上,输入内容,修改语言,实时翻译
代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 18px;
}
#app {
padding: 10px 20px;
}
.query {
margin: 10px 0;
}
.box {
display: flex;
}
textarea {
width: 300px;
height: 160px;
font-size: 18px;
border: 1px solid #dedede;
outline: none;
resize: none;
padding: 10px;
}
textarea:hover {
border: 1px solid #1589f5;
}
.transbox {
width: 300px;
height: 160px;
background-color: #f0f0f0;
padding: 10px;
border: none;
}
.tip-box {
width: 300px;
height: 25px;
line-height: 25px;
display: flex;
}
.tip-box span {
flex: 1;
text-align: center;
}
.query span {
font-size: 18px;
}
.input-wrap {
position: relative;
}
.input-wrap span {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 12px;
}
.input-wrap i {
font-size: 20px;
font-style: normal;
}
style>
head>
<body>
<div id="app">
<div class="query">
<span>翻译成的语言:span>
<select v-model="obj.lang">
<option value="italy">意大利option>
<option value="english">英语option>
<option value="german">德语option>
select>
div>
<div class="box">
<div class="input-wrap">
<textarea v-model="obj.words">textarea>
<span><i>⌨️i>文档翻译span>
div>
<div class="output-wrap">
<div class="transbox">{{ result }}div>
div>
div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
<script>
// 接口地址:https://applet-base-api-t.itheima.net/api/translate
// 请求方式:get
// 请求参数:
// (1)words:需要被翻译的文本(必传)
// (2)lang: 需要被翻译成的语言(可选)默认值-意大利
// -----------------------------------------------
const app = new Vue({
el: '#app',
data: {
// words: ''
obj: {
words: '',
lang:'italy'
},
result:'',//翻译结果
timer: null
},
// 具体讲解:(1) watch语法 (2) 具体业务实现
watch: {
obj: {
deep: true, //深度监视
immediate: true, //立刻执行,一进入页面handler立刻执行
handler( newValue ){
// //防抖:延迟执行 -> 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
//这里是ajax的内容
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params:newValue
})
this.result = res.data.data
console.log(res.data.data)
}, 300)
}
}
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./css/inputnumber.css" />
<link rel="stylesheet" href="./css/index.css" />
<title>购物车title>
head>
<body>
<div class="app-container" id="app">
<div class="banner-box"><img src="./img/fruit.jpg" alt="" />div>
<div class="breadcrumb">
<span>span>
/
<span>购物车span>
div>
<div class="main" v-if="fruitList.length > 0">
<div class="table">
<div class="thead">
<div class="tr">
<div class="th">选中div>
<div class="th th-pic">图片div>
<div class="th">单价div>
<div class="th num-th">个数div>
<div class="th">小计div>
<div class="th">操作div>
div>
div>
<div class="tbody">
<div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }">
<div class="td"><input type="checkbox" v-model="item.isChecked" />div>
<div class="td"><img :src="item.icon" alt="" />div>
<div class="td">{{ item.price }}div>
<div class="td">
<div class="my-input-number">
<button :disabled="item.num <= 1" class="decrease" @click="sub(item.id)"> - button>
<span class="my-input__inner">{{ item.num }}span>
<button class="increase" @click="add(item.id)"> + button>
div>
div>
<div class="td">{{ item.num * item.price }}div>
<div class="td"><button @click="del(item.id)">删除button>div>
div>
div>
div>
<div class="bottom">
<label class="check-all">
<input type="checkbox" v-model="isAll" />
全选
label>
<div class="right-box">
<span class="price-box">总价 : ¥ <span class="price">{{totalPrice}}span>span>
<button class="pay">结算( {{totalCount}} )button>
div>
div>
div>
<div class="empty" v-else>空空如也div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
const defaultArr= [
{
id: 1,
icon: './img/火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: './img/荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: './img/榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: './img/鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: './img/樱桃.png',
isChecked: false,
num: 20,
price: 34,
}
]
const app = new Vue({
el: '#app',
data: {
// 水果列表
fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr,
},
methods:{
del(id){
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
add (id) {
const fruit = this.fruitList.find(item => item.id === id)
fruit.num++;
},
sub (id) {
const fruit = this.fruitList.find(item => item.id === id)
fruit.num--;
}
},
computed:{
isAll:{
get () {
return this.fruitList.every(item => item.isChecked)
},
set (value) {
//基于拿到的布尔值,要让所有的小选框同步状态
this.fruitList.forEach(item => {
item.isChecked = value
});
}
},
//统计选中的总数
totalCount(){
return this.fruitList.reduce((sum,item) => {
if (item.isChecked){
return sum+item.num
}else{
return sum
}
} , 0)
},
//统计选中的总价
totalPrice(){
return this.fruitList.reduce((sum,item) => {
if(item.isChecked){
return sum+item.num*item.price
}else{
return sum
}
}, 0)
}
},
watch: {
fruitList: {
deep:true,
handler(newValue){
//将变化后的newValue存入本地(转JSON)
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" />
<style>
.red {
color: red !important;
}
.search {
width: 300px;
margin: 20px 0;
}
.my-form {
display: flex;
margin: 20px 0;
}
.my-form input {
flex: 1;
margin-right: 20px;
}
.table> :not(:first-child) {
border-top: none;
}
.contain {
display: flex;
padding: 10px;
}
.list-box {
flex: 1;
padding: 0 30px;
}
.list-box a {
text-decoration: none;
}
.echarts-box {
width: 600px;
height: 400px;
padding: 30px;
margin: 0 auto;
border: 1px solid #ccc;
}
tfoot {
font-weight: bold;
}
@media screen and (max-width: 1000px) {
.contain {
flex-wrap: wrap;
}
.list-box {
width: 100%;
}
.echarts-box {
margin-top: 30px;
}
}
style>
head>
<body>
<div id="app">
<div class="contain">
<div class="list-box">
<form class="my-form">
<input v-model.trim="name" type="text" class="form-control" placeholder="消费名称" />
<input v-model.number="price" type="text" class="form-control" placeholder="消费价格" />
<button @click="add" type="button" class="btn btn-primary">添加账单button>
form>
<table class="table table-hover">
<thead>
<tr>
<th>编号th>
<th>消费名称th>
<th>消费价格th>
<th>操作th>
tr>
thead>
<tbody>
<tr v-for="(item,index) in list" :key="item.id">
<td>{{ index }}td>
<td>{{ item.name }}td>
<td :class="{ red:item.price > 500 }">{{ item.price.toFixed(2) }}td>
<td><a @click="del(item.id)" href="javascript:;">删除a>td>
tr>
tbody>
<tfoot>
<tr>
<td colspan="4">消费总计: {{totalPrice}}td>
tr>
tfoot>
table>
div>
<div class="echarts-box" id="main">div>
div>
div>
<script src="https://cdn.bootcss.com/echarts/3.7.1/echarts.min.js">script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.js">script>
<script>
/**
* 接口文档地址:
* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
*
* 功能需求:
* 1. 基本渲染
* 2. 添加功能
* 3. 删除功能
* 4. 饼图渲染
*/
const app = new Vue({
el: '#app',
data: {
list: [],
name: '',
price: ''
},
created() {
// const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {
// params: {
// creator: '嘻嘻'
// }
// })
// this.list=res.data.data
this.getlist()
},
mounted() {
this.myChart = echarts.init(document.querySelector('#main'))
this.myChart.setOption({
//标题
title: {
text: '消费账单列表',
left: 'center'
},
//提示框
tooltip: {
trigger: 'item'
},
//图例
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '消费账单',
type: 'pie',
radius: '50%',//圆的半径
data: [
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
})
},
computed: {
totalPrice() {
return this.list.reduce((sum, item) => sum + item.price, 0)
}
},
methods: {
async getlist() {
const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {
params: {
creator: '嘻嘻'
}
})
this.list = res.data.data
this.myChart.setOption({
series: [
{
data: this.list.map(item => ({value: item.price, name:item.name}))
}
]
})
},
async add() {
if (!this.name) {
alert('请输入消费名称')
return
}
if (typeof this.price !== 'number') {
alert('请输入正确的消费价格')
return
}
const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
creator: '嘻嘻',
name: this.name,
price: this.price
})
this.getlist()
this.name = ''
this.price = ''
},
async del(id) {
const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`)
this.getlist()
}
}
})
script>
body>
html>
Vue CLI 是 Vue 官方提供的一个全局命令工具
可以帮助我们快速创建一个开发Vue项目的标准化基础架子【集成 webpack 配置】
npm i @vue/cli -g
(用yarn一直没装上,在这里选了npm)
vue --verison
1.打开vscode,在你想要创建项目的位置打开中断,并输入以下命令
vue create 你的项目名称
cd 你的项目名称
npm run serve
<template>
<div class="app" @click="fn()">
我是结构
div>
template>
<script>
export default{
methods:{
fn(){
alert("hello")
}
}
}
script>
<style lang="less">
.app {
width: 400px;
height: 400px;
background-color: pink;
}
style>
npm install less-loader less --save-dev
//导入需要全局注册的组件
import HmButton from './components/HmButton'
//调用Vue.component进行全局注册
//Vue.component('组件名',组件对象)
Vue.component('HmButton', HmButton)
<组件名>组件名>
<script>
import HmHeader from './components/HmHeader.vue'
import HmMain from './components/HmMain.vue'
import HmFooter from './components/HmFooter.vue'
export default {
components:{
HmHeader:HmHeader,
HmMain,
HmFooter
}
}
script>