Vue基础
day1
Vue的现状
最新版本:
Vue 3.0
1、核心代码完全重构(TypeScript)
2、速度更快
3、体积更小
vue的基本使用方法
1.引入vue.js
<script src="./vue.js"></script>
2.定义模板
<div id="app"></div>
3.vue初始化
const app = new Vue({
// 告诉我Vue生效位置,给一个dom id值,或者class
//el 挂载点
el:'#app',
// data:数据对象,用于给模板进行渲染
data:{
//数据
}
})
小结:
1、el给vue实例的挂载点,挂载点外的不归vue管
2、el 可以使任何选择器,id class 标签都可以
Vue data属性接收不同的类型和模板读取
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id='app'>
<p>字符串: {{ message }}</p>
<p>数值类型:{{ num }}</p>
<p>布尔类型:{{ isOk }}</p>
<p>对象类型:{{ student }} {{student.name}} {{student['age']}}</p>
<p>数组类型:{{ hobby }} {{ hobby[0] }}</p>
</div>
</body>
<script>
// data定义不同的数据类型:string, number,boolean,对象,数组
const app = new Vue({
el: '#app',
data: {
message:'简单字符串',
num: 20,
isOk: true,
student: { name: 'tom', age: 18 },
hobby: ['篮球', '足球']
}
})
</script>
</html>
小结:
data接收任意的js类型数据,模板读取方法和js读取是一样的。
v-text标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<div>我的信息是:{{message}}</div>
<!-- v-text会直接覆盖原有的内容,v-text等号后面直接接收data下的值 -->
<div v-text="message">我的信息是:</div>
<!-- 如果v-text需要拼接字符,可以用这个方式 -->
<div v-text="'我的信息是:' + message">我的信息是:</div>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
message: '黑马57前端'
}
})
</script>
</html>
小结
1.v-text会直接覆盖原有的内容,v-text等号后面直接接收data下的值
2.如果v-text需要拼接字符,可以用这个方式
<div v-text="'我的信息是:' + message">我的信息是:</div>
v-html标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<!-- v-html标签:用于解析html元素的 -->
<div id="app">
<div>{{message}}</div>
<div v-html="message"></div>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
message: '<h1>少林功夫好耶</h1><h2>我系铁头功</h2>'
}
})
</script>
</html>
小结
1.html可以解析html结构
v-bind语法(操作标准属性属性值)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
<style>
.box {
width:100px;
height: 100px;
background-color: red;
}
.yellowBox {
width:100px;
height: 100px;
background-color: yellow;
}
</style>
</head>
<body>
<div id="app">
<div class="box"></div>
<!-- 如果要给属性设置值,这是不允许的 -->
<div class="{{myClass}}"></div>
<div :class="myYellow"></div>
<div v-bind:class="myClass"></div>
<!-- 显示logo图片 -->
<img :src="logo"/>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
myClass: 'box',
myYellow: 'yellowBox',
logo: 'https://cn.vuejs.org/images/logo.png'
}
})
</script>
</html>
小结
1、用于html属性的赋值
2、v-bind还可以简写为:
<div v-bind:class="myClass"></div>
<!-- 显示logo图片 -->
<img :src="logo"/>
vue表达式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<!-- 表达式:三目运算,加法,减法,&&,|| -->
<body>
<div id="app">
<div>三目运算符:{{ age >= 18 ? '成年人' : '精神小伙'}}</div>
<div>加法运算:{{ age + 1 }}</div>
<div>减法运算:{{ age - 1 }}</div>
<div v-bind:id="'item-' + id"></div>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
age: 18,
id: 1,
}
})
</script>
</html>
小结
1、Vue的模板语法支持常见的表达式,例如三目运算符、加法、减法、和运算、或运算
vue中的循环v-for
语法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<!-- v-for语法:用于循环数组 -->
<!-- 第一种写法 -->
<!-- <div v-for="别名 in 目标数组"></div> -->
<!-- 第二种写法 -->
<!-- <div v-for="(别名, 索引变量) in 目标数组"></div> -->
<!-- key值问题,Vue为了优化列表渲染需要依赖的一个值,你可以不提供给他 -->
<!-- 如果不提供,会提示警告,一般情况下都需要一个key值 -->
<body>
<div id="app">
<!-- 循环数组 -->
<div>我的爱好是</div>
<p v-for="(item, index) in hobby" :key="index">
{{item}}
</p>
<!-- 循环数组,读取对象 -->
<div>学生信息</div>
<p v-for="(stu, idx) in students" :key="stu.id">
第{{idx + 1}}条数据:我的名字叫{{stu.name}},年龄 {{stu.age}}
</p>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
hobby: [ '篮球', '足球', '羽毛球' ],
students: [ { id: 10001 ,name: 'tom', age: 18 }, { id: 1002, name: 'jake', age: 20 } ]
}
})
</script>
</html>
v-for中的key值
v-for对象循环
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<!-- 循环对象:v-for="(属性值,属性key,索引) in 对象" -->
<div id="app">
<p v-for="(item, key, index) in student">
对象的属性为:{{key}} value值为:{{item}} 索引值:{{index}}
</p>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
student: {
name: 'tom',
age: 18
}
}
})
</script>
</html>
小结
:对象循环也是使用v-for
语法,但是他们的值有点不一样
v-for="(属性值,属性key,索引) in 对象"
for循环的问题
v-if的语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>判断语法</title>
<script src="./vue.js"></script>
</head>
<body>
<!-- v-if="布尔值" -->
<div id="app">
<div v-if="isOK">这是isOk为true的时候显示</div>
<!-- 字符串作为v-if条件 -->
<!-- 空串表示false值,非空串表示true值 -->
<div v-if="test">会显示test的内容吗?</div>
<!-- undefined值,也表示false -->
<div v-if="name">会显示undefined吗</div>
<!-- null值 -->
<div v-if="gender">能显示gender吗</div>
<!-- 数值类型, 0表示false, 其他表示true -->
<div v-if="num">是否显示num</div>
<div v-if="age > 18">成年小伙</div>
<div v-else>精神小伙</div>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
isOK: true,
test: 'test',
name: undefined,
gender: null,
num: 1,
age: 18
}
})
</script>
</html>
小结
1、语法: v-if="条件"
<div v-if="name">会显示undefined吗</div>
2、条件可以是任意的js表示真或者假的值
3、还可以增加v-else语句和v-else-if语句
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
v-show的语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-show语法</title>
<script src="./vue.js"></script>
</head>
<body>
<!-- v-show="表示真值或者假值" -->
<!-- v-show如果为false的时候,实际是给元素增加display:none样式 -->
<!-- v-if 如果为false,直接把元素从dom移除 -->
<!-- 使用场景区别 -->
<!-- 当元素频繁的切换可见状态,v-show -->
<!-- 否则,可以用v-if -->
<div id="app">
<div v-show="isOK">v-show语法控制元素</div>
<div v-if="isOK">v-if语法控制的元素</div>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
isOK: false
}
})
</script>
</html>
小结
1.v-show如果为false的时候,实际是给元素增加display:none样式, v-if 如果为false,直接把元素从dom移除
2.使用场景:当元素频繁的切换可见状态,v-show,否则,可以用v-if, 因为v-if为真要重新渲染Dom结构,造成性能浪费
v-model实现radio单选框
v-model
你可以用 v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建双向数据绑定,指令会帮你自动把输入的值更新到数据中。
message的值也会自动显示给绑定表单的元素上,假如value的初始值跟message的初始值不一样,通过v-madel绑定message的值会覆盖掉
value上的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-model语法</title>
<script src="./vue.js"></script>
</head>
<body>
<!-- 如果是radio标签,通过v-model绑定同一个值,他们之间会自动实现互斥的关系 -->
<!-- 如果需要实现数据初始化,给绑定的变量赋予初始值,初始值应该和radio的value值相等 -->
<div id="app">
<input type="radio" name="gender" id="" value="男" v-model="gender">男
<input type="radio" name="gender" id="" value="女" v-model="gender">女
<input type="radio" name="gender" id="" value="不详" v-model="gender">不详
<div>选择的性别是:{{gender}}</div>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
gender: '女'
}
})
</script>
</html>
小结:
1、radio的v-model属性需要绑定同一个值才能成为一组
2、如果需要实现数据初始化,给绑定的变量赋予初始值,初始值应该和radio的value值相等
v-model实现checkbox复选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-model语法</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<!-- value是必须的值 -->
<input type="checkbox" v-model="hobby" value="basketball">篮球
<input type="checkbox" v-model="hobby" value="football">足球
<input type="checkbox" v-model="hobby" value="music">音乐
<div>兴趣:{{hobby}}</div>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
data: {
hobby: ['basketball']
}
})
</script>
</html>
小结
1、checkbox必须有value值,否则会出错
input:textinput事件与change事件
input事件触发
change事件触发
day2
网站优化问题
事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<!-- 数据驱动视图、数据模型驱动 -->
<!-- 关注的只有数据,不需要关注视图相关代码 -->
<div id="app">
<div>当前的数量是 {{ counter }} </div>
<!-- 通过 v-on:事件名 添加事件 -->
<button v-on:click="counter++">加一</button>
<!-- 可以用下面的两个方法绑定事件 -->
<!-- <button v-on:click="reduce()">减一</button> -->
<button v-on:click="reduce">减一</button>
<!-- 给事件传递参数 -->
<button v-on:click="sayHello('tom')">弹出问好的语句</button>
<!-- 事件绑定的简写形式 -->
<button @click="sayHello('tom')">简写的事件绑定</button>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
counter: 0
},
// methods表示页面的方法
methods: {
// 第一种写法
// reduce: function() {
// this.counter--;
// }
// 第二种,基于ES6的函数定义
reduce() {
this.counter--
},
sayHello(name) {
alert(name + '你好呀')
}
}
})
</script>
</html>
小结
1、定义的语法v-on:事件名
2、v-on:click = “方法名/表达式”
3、方法要定义在Vue对象的methods
4、方法的参数传递,可以直接通过绑定事件时传递 v-on:click="sayHello('tom')"
5、事件绑定的简写, @click="sayHello"
事件修饰符
事件修饰符就是拿来阻止默认事件,冒泡之类的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<!-- Vue阻止默认行为 -->
<!-- 第一种方法 -->
<form @submit="login">
<input type="text" name="userName">
<button type="submit">登录</button>
</form>
<!-- 第二种方法 -->
<form @submit.prevent="register">
<input type="text" name="userName">
<button type="submit">注册</button>
</form>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
},
methods: {
// 第一种实现方法
login(e) {
console.log(e)
e.preventDefault();
console.log('login')
},
// 第二种实现方法
register() {
console.log('register')
}
}
})
</script>
</html>
键盘修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<!-- 绑定键盘事件,监听keyup事件,表示按键弹起的时候 -->
<!-- 要监听回车键 -->
<input type="text" @keyup.enter="userInput" v-model="userInfo">
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
userInfo: ''
},
methods: {
userInput() {
// 显示用户输入的内容
console.log('用户按下了回车键' + this.userInfo)
}
}
})
</script>
</html>
小结
键盘修饰符可以拿来监听键盘键
Vue自定义指令
<input type="text" autofocus> 但是这种ios 系统不支持
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" id="myInput" v-focus>
<button @click="userFocus()">聚焦</button>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
},
methods: {
// 不优雅
userFocus() {
document.querySelector('#myInput').focus();
}
},
// 使用自定义指令
directives: {
// 属性名字是变化的,你需要定义成什么指令就起什么名字,v-foucs
focus: {
// inserted是一个钩子函数,当dom被插入到父节点的时候,会被调用
inserted(el) {
// el是原生dom元素,然后调用focus进行聚焦
el.focus();
}
}
}
})
</script>
</html>
小结
1、指令应该定义在directives
2、指令的名字作为对象的key
值
3、对象的value值,定义钩子函数,例如inserted
4、在inserted
函数里面获取原生dom元素,调用foucs方法
5、在dom元素,加入v-focus
过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用过滤器 -->
<!-- 使用管道符 -->
<div>{{ name | upper }}</div>
<div v-bind:id="name | upper"></div>
<!-- 使用多个管道 -->
<div>{{ price | toyuan | multiply}} 元</div>
<!-- 过滤文明用语 -->
<div>{{ message | towenming }}</div>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
name: 'tom',
price: 10000,
message: '你西内'
},
methods: {
},
// 过滤器定义的位置
filters: {
upper(value) {
return value.toUpperCase();
},
toyuan(value) {
return value / 100;
},
// 乘10
multiply(value) {
return value * 10
},
// 把语言过滤成优雅的说法
towenming(value) {
return value.replace('西内', '好棒哦')
}
}
})
</script>
</html>
小结
1、定义过滤器,过滤器都定义在filters
对象中
2、filters对象中可以定义多个过滤器,过滤器实际上就是一个函数,函数会接收到一个值,这个值是管道前面的变量
3、使用过滤器的方法,需要用到一个管道符<div>{{ name | upper }}</div>
4、管道符就是 |
计算属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<!-- 第一种方法:模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。 -->
<div>{{ phone.substr(0, 4) + '****' + phone.substr(7)}}</div>
<!-- 第二种方法 -->
<div>{{getPhone()}}</div>
<!-- 第三种方法 -->
<div>使用计算属性:{{displayPhone}}</div>
<input type="text" v-model="phone">
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
phone: '18661111234'
},
methods: {
getPhone() {
return this.phone.substr(0, 4) + '****' + this.phone.substr(7)
}
},
// 计算属性
computed: {
displayPhone() {
return this.phone.substr(0, 4) + '****' + this.phone.substr(7)
}
}
})
</script>
</html>
小结
1、计算属性要定义在computed
节点
2、计算属性调用的时候和普通方法不太一样,方法是需要方法名()
,计算属性直接写上计算属性方法名就可以
3、计算属性触发重新执行的时机,计算属性内依赖的值发生改变时,会重新计算
算属性与普通方法的差异:
计算属性具有缓存的能力,当计算属性内依赖的属性没发生改变,他就不会被重新执行;但是方法调用会根据调用次数执行不同的次数
computed与methods的差异
computed会产生缓存机制,但如果computed属性计算中所依赖的数据发生改变,computed也会随着改变。而methods每次都会计算一次数值,浪费性能
day3
侦听属性watch
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
<div>全名:{{fullName}}</div>
</div>
</body>
<script>
// 使用侦听属性 watch
const app = new Vue({
el: '#app',
data: {
firstName: '',
lastName: '',
fullName: '',
},
watch: {
// 侦听firstName属性的变化,value就是变化的值
firstName(newVal, oldVal) {
this.fullName = newVal + this.lastName
},
lastName(newVal, oldVal) {
this.fullName = this.firstName + newVal;
}
}
})
</script>
</html>
小结:
1、侦听属性是用于监听data下属性值的变化
2、侦听属性定义在watch
节点
3、侦听属性方法可以得到两个参数,分别为新的值和旧的值
firstName(newVal, oldVal) {
this.fullName = newVal + this.lastName
},
4、如果页面上需要监听数据并且显示某个值,可以考虑计算属性,否则用侦听器
侦听属性deep属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<div>{{product.name}}</div>
<div>价格:{{product.price}}块</div>
<input type="text" v-model="product.amount">
</div>
</body>
<script>
// 使用侦听属性 watch
const app = new Vue({
el: '#app',
data: {
product: {
name: '商品名字',
price: 100,
amount: 0
}
},
// 监听amount变化,发送ajax请求到服务端,检查库存数量
watch: {
// 如果你要监听对象里的某个属性,可以用这种写法
// 'product.amount': function(newVal) {
// console.log(newVal)
// }
// 这个写法不能监听对象的子属性
// product(newVal) {
// console.log(newVal)
// }
product: {
// deep表示深度监听,把对象或者数组的子元素都进行监听
deep: true,
// newVal得到的是监听对象
handler(newVal, oldVal) {
console.log(newVal, oldVal)
}
}
}
})
</script>
</html>
小结:
1、监听对象或者数组,是没法监听子属性的变化。
2、通过deep
属性设置为深度监听,才能监听对象或者数组的子属性
3、侦听处理函数,写在handler
属性里
Vue的生命周期
小结
1.Vue的生命周期也就是这八个钩子函数组成的
网络请求一般放在什么周期?
放在created和mounted都可以,一般情况下mounted
什么生命周期才能拿到 data的数据?
在created周期才能拿到
自定义组件
组件解决代码复用,js复用的函数,vue的页面复用
如何定义组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用组件 -->
<counter></counter>
<!-- 如果组件使用驼峰命名,使用的时候,把驼峰改为横杆 -->
<!-- <heimaCounter></heimaCounter> -->
<heima-counter></heima-counter>
<xboss-counter></xboss-counter>
</div>
</body>
<script>
// 定义自定义全局组件
// couter表示组件的名字
Vue.component('counter', {
// template表示组件模板
template: '<div>hello component</div>'
})
Vue.component('heimaCounter', {
// template表示组件模板
template: '<div>hello heima</div>'
})
Vue.component('xboss-counter', {
// template表示组件模板
// 注意!Vue组件模板只允许有一个根元素
template: `
<div>
<div>hello xboss-counter</div>
<div>test</div>
</div>`
})
const app = new Vue({
el: '#app'
})
</script>
</html>
小结
1、定义全局组件,可以通过Vue.component('组件名', { template })
2、组件名建议都用小写,如果是两个单词,用横杠连接,尽量不要用驼峰命名,如果用了驼峰命名,在使用的时候驼峰的大写用横杠连接。
组件传参
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<blog-post title="这是新闻标题" content="这是新闻内容"></blog-post>
<blog-post title="这是第二条新闻标题" content="这是第二条新闻内容"></blog-post>
<blog-post title="这是第三条新闻标题" content="这是第三新闻内容"></blog-post>
</div>
</body>
<script>
// 定义一个显示文章的组件
// 名字叫:blog-post
// 接收的参数:title content
Vue.component('blog-post', {
// 通过props对象接收传递过来的数据
// 组件接收外部参数,用props
props: [ 'title', 'content' ],
// 组件内部的数据,用data定义
data() {
return {
author: '蟹老板'
}
},
template: `
<div>
<h1>{{title}}</h1>
<p>作者:{{author}}</p>
<h3>{{content}}</h3>
</div>
`
})
const app = new Vue({
el: '#app',
})
</script>
</html>
小结
1、组件通过props
属性接收外部参数
2、给组件传递参数的写法<blog-post title="这是新闻标题" content="这是新闻内容"></blog-post>
组件验证参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<blog-post title="这是新闻标题" content="这是新闻内容"></blog-post>
<blog-post title="这是第二条新闻标题" content="这是第二条新闻内容"></blog-post>
<blog-post title="第三条新闻标题" :content="num"></blog-post>
</div>
</body>
<script>
// 定义一个显示文章的组件
// 名字叫:blog-post
// 接收的参数:title content
Vue.component('blog-post', {
// 通过props对象接收传递过来的数据
// 组件接收外部参数,用props
// props: [ 'title', 'content' ],
// 验证props属性
props: {
// 对象的key值就是参数的名字,value值验证规则
title: {
// 验证数据不能为空,如果传递空值,会提示警告
required: true,
},
// 验证cotnent必须为String类型
content:String
},
// 组件内部的数据,用data定义
data() {
return {
author: '蟹老板'
}
},
template: `
<div>
<h1>{{title}}</h1>
<p>作者:{{author}}</p>
<h3>{{content}}</h3>
</div>
`
})
const app = new Vue({
el: '#app',
data() {
return {
num: 1
}
}
})
</script>
</html>
小结:
1、验证参数可以通过props等于一个对象
required
是否必填
type
数据传入类型,可以设置为任何的JS基础类型
default
数据默认值
props: {
// 对象的key值就是参数的名字,value值验证规则
title: {
// 验证数据不能为空,如果传递空值,会提示警告
required: true,
},
content: {
// 验证cotnent必须为String类型
type: String
}
},
day4
父子组件概念
父更早创建的,子在父里面
blog-post是app实例的子组件,other是app的孙组件
<div id="app">
<blog-post v-for="(item, index) in newsList" :news="item"></blog-post>
<!--父组件-->
<blog-post v-for="(item, index) in newsList" :news="item">
<!--子组件-->
<other></other>
</blog-post>
</div>
父子组件之间通讯
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<!-- 父组件接收子组件事件,然后做相应的逻辑 -->
<blog-post @hide="childHide" v-for="(item, index) in newsList" :index="index" :news="item"></blog-post>
</div>
</body>
<script>
// 定义一个显示文章的组件
// 名字叫:blog-post
// 接收的参数:title content
Vue.component('blog-post', {
// 通过props对象接收传递过来的数据
// 组件接收外部参数,用props
props: [ 'news', 'index' ],
template: `
<div>
<h1>{{news.title}}</h1>
<p>作者:{{news.author}}</p>
<h3>{{news.content}}</h3>
<button @click="hideNews">屏蔽当前信息</button>
</div>
`,
methods: {
hideNews() {
// 如何通知父组件?
// 发送事件及传递数值给父组件
// 通过$emit('自定义事件名')
this.$emit('hide', this.index)
}
}
})
const app = new Vue({
el: '#app',
data() {
return {
newsList: [
{ title: '新闻标题1', content: '新闻内容', author: '蟹老板' },
{ title: '新闻标题2', content: '新闻内容', author: '蟹老板' },
{ title: '新闻标题3', content: '新闻内容', author: '蟹老板' },
]
}
},
methods: {
// 接收到子组件事件后,处理函数
childHide(index) {
// 直接把newsList删除掉相应的元素
this.newsList.splice(index, 1)
}
}
})
</script>
</html>
小结:
1、子组件通过this.$emit(‘事件名’, '参数')
发送事件通知父组件
2、父组件通过v-on:子组件事件名="父组件处理函数"
兄弟组件之间通讯
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<aiqi1 @yy="aiqi"></aiqi1>
<!--利用v-bind向组件模板传入content-->
<aiqi2 :title="content"></aiqi2>
</div>
</body>
<script>
Vue.component('aiqi1', {
template: `<div>
//使用emit向组件aiqi1发送参数zyf
<input type="text" v-model="zyf" @keyup="$emit('yy',zyf)" >
</div>`,
data() {
return {
zyf: '',
}
}
})
Vue.component('aiqi2', {
props: ['title'],
template: `<div>{{title}}</div>`
})
const app = new Vue({
el: "#app",
data() {
return {
content: '',
}
},
methods: {
aiqi(zyf) {
this.content = zyf;
}
},
});
</script>
</html>
小结:
1、子组件通过$emit
传递数据给父组件
2、父组件保存子组件传递过来的数据
3、父组件把数据通过props
传递给其他兄弟组件
局部组件和全局组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
{{msg}}
<blog></blog>
</div>
<div id='app2'>
{{msg}}
<blog></blog>
<comment></comment>
</div>
</body>
<script>
// 全局组件,会在所有vue的实例都生效
Vue.component('blog', {
template: '<div>myblog</div>'
})
// 第一个vue实例
const app = new Vue({
el: '#app',
data() {
return {
msg: 'app'
}
}
})
// 第二个实例
const app2 = new Vue({
el: '#app2',
data() {
return {
msg: 'app2'
}
},
// 局部组件,用于声明当前实例有什么组件
components: {
comment: { template: '<div>comment组件</div>' }
}
})
</script>
</html>
1、全局组件通过Vue.component
方法定义
2、全局组件可以给任意的实例调用
3、局部组件定义在实例的components
节点
4、定义方法
components: {
comment: { template: '<div>comment组件</div>' }
}
Vue路由
单页应用(SPA:single page application):把所有的页面加载到同一个html页面,然后通过切换元素的显示和隐藏状态,实现页面的流畅切换效果。
单页应用的优势:切换流畅,使用体验比较好
单页应用劣势:首次加载较慢,一般单页应用多用于后台管理系统,或者一些追求体验移动应用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 第一步:引入vue和vue-router -->
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
</head>
<body>
<div id="app">
<!-- <a href="#/login">登录</a>
<a href="#/register">注册</a> -->
<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link>
<!-- 用于显示路由页面元素 -->
<router-view></router-view>
</div>
</body>
<script>
// 定义页面组件
const index = {
template: `<div>首页</div>`
}
const register = {
template: `
<div>
<div>注册页面</div>
<label for="username">用户名:</label><br/>
<input type="text" name="username" id="username"/><br/>
<label for="password">密码:</label><br/>
<input type="password" name="password" id="password"/><br/>
<button>注册</button><br/>
</div>
`
}
const login = {
template: `
<div>
<div>登录页面</div>
<label for="username">用户名:</label><br/>
<input type="text" name="username" id="username"/><br/>
<label for="password">密码:</label><br/>
<input type="password" name="password" id="password"/><br/>
<button>登录</button>
</div>
`
}
// 定义路由配置信息,routes
const routes = [
{ path: '/', component: index },
{ path: '/login', component: login },
{ path: '/register', component: register },
]
// 创建VueRouter实例,传递路由配置信息
const router = new VueRouter({
routes
})
// 路由实例传递给Vue
const app = new Vue({
el: '#app',
router
})
</script>
</html>
小结:
1、编写页面组件
2、声明路由配置信息
path: 访问的路径,component 显示的组件
const routes = [
{ path: '/', component: index },
{ path: '/login', component: login },
{ path: '/register', component: register },
]
3、实例化组件
const router = new VueRouter({
routes
})
4、把路由实例传递给Vue实例
const app = new Vue({
el: '#app',
router
})
3、用于显示页面
4、用于链接跳转
哈希(hash)路由
Vue是基于哈希路由实现页面跳转的。
window.location.hash
Vue路由参数传递
1、路由配置文件加入参数名字
参数是以冒号为开始,冒号后面表示参数名字
const routes = [
{ path: '/', component: index },
{ path: '/login', component: login },
// 注册页面接收一个参数,叫source表示来源
// 定义路由参数写法 /register/:参数名字
{ path: '/register/:source', component: register },
]
2、给页面传递参数
<router-link to="/register/微信">注册</router-link>
3、在目标页面获取参数
this.$route
表示当前页面路由对象
this.$route.params
表示页面参数对象
mounted() {
// dom渲染完毕的生命周期钩子函数
console.log(this.$route.params.source)
}
监听路由参数的动态变化
通过watch特性监听$route对象
watch: {
// 通过watch监听路由对象,实现参数变化监听
// to 表示目标页面路由对象
// from 表示从哪个页面过来的路由对象
$route(to, from) {
console.log(to);
console.log(from)
}
}
404找不到页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 第一步:引入vue和vue-router -->
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
</head>
<body>
<div id="app">
<!-- <a href="#/login">登录</a>
<a href="#/register">注册</a> -->
<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link>
<!-- 用于显示路由页面元素 -->
<router-view></router-view>
</div>
</body>
<script>
// 定义页面组件
const index = {
template: `<div>首页</div>`
}
const register = {
template: `
<div>
<div>注册页面</div>
<label for="username">用户名:</label><br/>
<input type="text" name="username" id="username"/><br/>
<label for="password">密码:</label><br/>
<input type="password" name="password" id="password"/><br/>
<button>注册</button><br/>
</div>
`
}
const login = {
template: `
<div>
<div>登录页面</div>
<label for="username">用户名:</label><br/>
<input type="text" name="username" id="username"/><br/>
<label for="password">密码:</label><br/>
<input type="password" name="password" id="password"/><br/>
<button>登录</button>
</div>
`
}
const NotFound = {
template: '<div>页面找不到</div>'
}
// 定义路由配置信息,routes
const routes = [
{ path: '/', component: index },
{ path: '/login', component: login },
{ path: '/register', component: register },
//通过*表示路径找不到
{ path: '*', component: NotFound }
]
// 创建VueRouter实例,传递路由配置信息
const router = new VueRouter({
routes
})
// 路由实例传递给Vue
const app = new Vue({
el: '#app',
router
})
</script>
</html>
day5
编程式路由
以前是通过router-link
进行页面跳转,但是有些时候,是希望通过在执行逻辑的时候调用js进行页面跳转的。以前,是通过window.location.href = "地址"
router.push 在原来路由基础上,跳转到另外一个路由
第一种:(最常用方法)
router.push('跳转路径')
第二种:(相对少用)
router.push({ name: '路由名字', params: { source: '123' } })
router.replace 替换路由,用该方法会替换掉上一个路由访问历史
router.replace('路由路径')
<router-link to="路由路径" replace></router-link>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
</head>
<body>
<div id="app">
<!-- 通过页面元素跳转 -->
<router-link to="/login">去登录页</router-link>
<a href="#/register">跳转到注册-使用a标签</a>
<!-- 编程式路由 -->
<div @click="jumpToRegister">跳转到注册</div>
<div style="margin: 50px;border: 5px solid red">
<router-view></router-view>
</div>
</div>
</body>
<script>
const Login = {
template: '<div>这是一个登录页面</div>'
}
const Register = {
template: '<div>这是一个注册页面</div>'
}
// 初始化路由
// 1、路由配置
const routes = [
{ path: '/login', component: Login },
{ path: '/register/:source', component: Register, name: 'register' }
]
// 2、实例化路由
const router = new VueRouter({
routes
})
// 初始化Vue
const app = new Vue({
el: '#app',
router,
methods: {
jumpToRegister() {
// 使用原生的跳转,也是可以,实际上,只要能操作到url的变化,都可以跳转
// window.location.href = '#/register'
// 第一种使用编程式跳转的方法
// router.push('/register')
// 第一种方法,传递参数
// router.push('/register/123')
// 第二种(比较少用),注意,只能通过name进行跳转,params传递参数
// router.push({ name: 'register', params: { source: '123' } })
//第三种替换式跳转,就是替换跳转前的页面,跳转后想返回上页的结果,跳转的是上上页
//router.replace('/replace/123456')
}
}
})
</script>
</html>
小结
// 使用原生的跳转,也是可以,实际上,只要能操作到url的变化,都可以跳转
// window.location.href = ‘#/register’
// 第一种使用编程式跳转的方法
// router.push(’/register’)
// 第一种方法,传递参数
// router.push(’/register/123’)
// 第二种(比较少用),注意,只能通过name进行跳转,params传递参数
// router.push({ name: ‘register’, params: { source: ‘123’ } })
//第三种替换式跳转,就是替换跳转前的页面,跳转后想返回上页的结果,跳转的是上上页
//router.replace(’/replace/123456’)
replace应用场景
支付成功跳转支付成功页面,从支付成功返回就是返回购物车页面
命名路由
就是通过name
属性作为跳转别名
1、定义路由的时候,增加name
属性
const routes = [
{ name: 'login', path: '/login', component: '组件' }
]
2、使用编程式路由
router.push({ name: 'login' })
3、组件跳转
<router-link :to="{ name: 'login' }"></router-link>
重定向
1、重定向的使用场景?
一般防止用户跳转到一些没有定义的路由,可以让他跳转到指定的页面。
2、使用方法,redirect指定的是一个路由路径
const routes = [
{ path: '/login', component: Login },
{ path: '/register/:source', component: Register, name: 'register' },
// 实现如果访问到没定义的页面,强制跳转到登录页面
{ path: '*', redirect: '/login' }
]
嵌套路由
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
</body>
<script>
const Blog = {
template: `
<div>
<h1>蟹老板的个人博客</h1>
<router-link :to="{path: '/blog/article'}">查看文章</router-link>
<router-link :to="{path: '/blog/userInfo'}">查看个人信息</router-link>
<router-view></router-view>
</div>
`,
};
// 文章
const Article = {
template: `
<div>
<p>第一篇文章</p>
<p>第一篇文章</p>
<p>第一篇文章</p>
<p>第一篇文章</p>
</div>
`
}
// 个人信息
const UserInfo = {
template: `
<div>
<p>姓名:蟹老板</p>
<p>性别:男</p>
</div>
`
}
const routes = [
{ path: '/', redirect: '/blog' },
{
path: '/blog',
component: Blog,
children: [
{
// 注意:子路由路径不需要以/开头
path: 'article',
component: Article,
},
{
path: 'userInfo',
component: UserInfo,
},
],
},
];
const router = new VueRouter({
routes,
});
new Vue({
el: '#app',
data: {},
router,
});
</script>
</html>
小结:
1、定义路由配置,把子路由配置到children
节点,children接收一个数组,数组和其他路由配置是一样的,都可以接收相同的参数。
path
参数开头不要斜杠。
{
path: '/blog',
component: Blog,
children: [
{
// 注意:子路由路径不需要以/开头
path: 'article',
component: Article,
},
{
path: 'userInfo',
component: UserInfo,
},
],
},
2、在父路由加入<router-view></router-view>
命名视图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>命令路由</title>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
</head>
<body>
<div id="app">
<router-view name="header"></router-view>
<router-view name="main"></router-view>
<router-view></router-view>
</div>
</body>
<script>
const Header = {
template: '<div style="width: 100%; height: 100px; border: 1px solid;">头部</div>'
}
const Main = {
template: `<div style="width: 100%; height: 300px; border: 1px solid red;">中间区域</div>`
}
const Default = {
template: `<div style="width: 100%; height: 100px; border: 1px solid blue;">默认路由</div>`
}
const routes = [
// 注意是components,和以前的指定单个组件不一样
{ path: '/', components: { header: Header, main: Main, default: Default } }
];
const router = new VueRouter({
routes,
});
new Vue({
el: '#app',
data: {},
router,
methods: {
}
});
</script>
</html>
小结
命名视图是一种将所有路由展示在页面的视图
导航守卫
当路由发生变化的时候,执行的钩子函数
// beforeEach当用户跳转到下一个页面的时候会被触发
router.beforeEach((to, from, next) => {
// to 目标路由对象(跳转到目标页面)
// from 从哪个路由过来的对象
// next 是一个函数,必须执行该函数才会放行
console.log(to)
console.log(from)
// 出现死循环,判断,如果已经进入登录页面,就不要再检查拉
if (jumpToLogin && to.path !== '/login') {
next('/login')
} else {
next();
}
})
router.beforeEach 当从一个页面跳转到另外一个页面的时候会被触发。
to 目标路由对象(跳转到目标页面)
from 从哪个路由过来的对象
next 是一个函数,必须执行该函数才会放行
其他包管理工具yarn
yarn 由facebook提供的包管理工具
因为facebook觉得npm不好用,下载太慢了,经常出错。
安装
切换为国内的下载源
npm config set registry https://registry.npm.taobao.org
通过npm安装yarn
npm install -g yarn
安装Vue-cli方法 https://cli.vuejs.org/zh/
yarn global add @vue/cli
添加环境变量
参考文章:https://www.jianshu.com/p/9308e6abbe44
初始化Vue项目
vue create 项目名字
启动项目
1、进入项目根目录
cd 项目名字
2、启动项目服务器
yarn serve
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gIBwO7DE-1609341216728)(Vue.assets/image-20201115165529653.png)]
Vue项目目录
模块导入规范
ES Model规范
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iElaHqHW-1609341216729)(Vue.assets/image-20201115170440368.png)]
commonjs规范
const fs = require('fs');
前端工程化
1、工程化解决第三方库管理问题
2、帮助我们自动把第三方包合并到一个js文件中