第一章:了解Vue.js
1.Vue.js是什么?
Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
2.Vue.js安装方法
方式一:直接CDN引入
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"><script>
方式二:下载和引入
开发环境 https://vuejs.org/js/vue.js
生产环境 https://vuejs.org/js/vue.min.js
方式三:NPM安装
3.Vuejs初体验--数据和界面分离--响应式
案例一:
创建Vue对象的时候,传入一些options:{}
{}中包含了el属性:该属性决定了这个Vue对象挂载到那一个元素上
{}中包含了data属性:该属性中通常会存储一些数据,数据可以是直接定义的;也可以是从服务器加载的
<div id="app">
<h1>{{message}}</h1>
<h2>{{name}}</h2>
</div>
<script>
// 申明式编程
let app = new Vue({
el: "#app", //用于挂载要管理的元素
data: { //定义数据
message: '你好啊,李银河',
name: "codewhy"
}
})
</script>
案例二:
展示数据列表:使用v-for指令
<div id="app">
<ul>
<li v-for="item in movies">{{item}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
movies : ['星际穿越', '大话西游', '少年派', '盗梦空间']
}
})
</script>
案例三:计数器
<div id="app">
<h2>当前计数:{{counter}}</h2>
<!-- <button v-on:click="counter++">+</button>-->
<!-- <button v-on:click="counter--">-</button>-->
<button v-on:click="add">+</button>
<button v-on:click="sub">-</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
counter: 0
},
methods: {
add: function () {
console.log('add会执行')
this.counter++
},
sub: function () {
console.log('sub会执行')
this.counter--
}
}
})
</script>
属性:methods,该属性用于在Vue对象中定义方法
指令:@click,是v-on:click的简写(语法糖),用于监听某个元素的点击事件,并且需要指定当发生点击时,执行的方法
4.Vue的MVVM是什么?
View层:
视图层
在前端开发中,通常就是DOM层
主要作用就是给用户展示各种信息
Model层:
数据层
数据可以是固定的,也可以是来自服务器的
VueModel层:
视图模型层
视图模型就是View和Model沟通的桥梁
一方面实现了Data Binding,即数据绑定,将Model的改变实时的反应到View当中去
另一方面实现了DOM Listener,即DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data
<!--view层-->
<div id="app">
<h2>当前计数:{{counter}}</h2>
<!-- <button v-on:click="counter++">+</button>-->
<!-- <button v-on:click="counter--">-</button>-->
<button v-on:click="add">+</button>
<button @click="sub">-</button>
</div>
<script src="../js/vue.js"></script>
<script>
// Model层
//语法糖:简写
const obj = {
counter: 0
}
// VueModel层
const app = new Vue({
el: '#app',
// data: {
// counter: 0
// },
data: obj,
methods: {
add: function () {
console.log('add会执行')
this.counter++
},
sub: function () {
console.log('sub会执行')
this.counter--
}
}
})
</script>
第二章:插值的操作
1. mustache语法 {{}}
2. v-once指令:在控制台不能通过该代码来改变界面内容
<div id="app">
<h2>{{message}}</h2>
<h2 v-once>{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
3. v-html指令: 对html代码作解析
<div id="app">
<h2>{{url}}</h2>
<h2 v-html="url">{{url}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
url: '<a href="http://www.baidu.com">百度一下</a>'
}
})
</script>
4. v-text指令:跟mustache效果类似,但不如mustache
<div id="app">
<h2>{{message}}</h2>
<h2 v-text="message"></h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
}
})
</script>
5. v-pre指令:直接展示mustache的内容,比如一下代码第二个<h2>{{message}}</h2>直接展示{{message}}
<div id="app">
<h2>{{message}}</h2>
<h2 v-pre>{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
6. v-cloak指令:比如延时展示时,在展示之前不让源码直接出现在界面上
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<h2>{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
setTimeout(function () {
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
},1000)
</script>
</body>
第三章:动态绑定属性
1. v-bind:用于绑定一个或多个属性值,或者向另一个组件传递props值
(动态绑定从服务器请求过来的数据内容)
<div id="app">
<h2>{{message}}</h2>
<img v-bind:src="imgURL" alt="">
<a v-bind:href="aHref">百度一下</a>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
imgURL: 'https://cn.vuejs.org/images/logo.png',
aHref: 'http://www.baidu.com',
}
})
</script>
2. v-bind的语法糖
<!-- <img v-bind:src="imgURL" alt="">-->
<!-- <a v-bind:href="aHref">百度一下</a>-->
<!-- v-bind的语法糖-->
<img :src="imgURL" alt="">
<a :href="aHref">百度一下</a>
3.1v-bind 动态绑定class(对象语法)
3.1.1 v-bind 绑定class:boolean为true时则添加上该类,boolean为false时则去掉了该类
<div id="app">
<!-- <h2 v-bind:class="{类名1: boolean, 类名2:boolean}">{{message}}</h2>-->
<h2 v-bind:class="{active: isActive, line: isLine}">{{message}}</h2>
<button v-on:click="btnClick">按钮</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
// active: 'active',
isActive: true,
isLine: true,
},
methods: {
btnClick: function () {
this.isActive = !this.isActive
}
}
})
</script>
3.1.2 v-bind 绑定class,如果过于复杂,可以放在一个methods中
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.active {
color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- <h2 v-bind:class="{类名1: boolean, 类名2:boolean}">{{message}}</h2>-->
<!-- <h2 class="title" v-bind:class="{active: isActive, line: isLine}">{{message}}</h2>-->
<h2 class="title" v-bind:class="getClasses()">{{message}}</h2>
<!-- <button v-on:click="btnClick()">按钮</button>-->
<button v-on:click="btnClick">按钮</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
// active: 'active',
isActive: true,
isLine: true,
},
methods: {
btnClick: function () {
this.isActive = !this.isActive
},
getClasses: function () {
return {active: this.isActive, line: this.isLine}
}
}
})
</script>
3.2 v-bind 绑定class(数组语法)
<div id="app">
<h2 v-bind:class="[active,line]">{{message}}</h2>
<h2 :class="getClasses()">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
active: 'aa',
line: 'bb',
},
methods: {
getClasses: function () {
return [this.active, this.line]
}
}
})
</script>
4. v-bind 绑定style
4.1 v-bind 绑定style(对象语法)
<div id="app">
<!-- <h2 :style="{key(属性名): value(属性值)}">{{message}}</h2>-->
<!-- 50px必须加上单引号-->
<!-- <h2 :style="{fontSize: '50px'}">{{message}}</h2>-->
<h2 :style="{fontSize: finaSize, backgroundColor: finalColor}">{{message}}</h2>
<!-- 封装成函数-->
<h2 :style="getStyles()">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
finaSize: '100px',
finalColor: 'red',
},
methods: {
getStyles: function () {
return {fontSize: this.finaSize, backgroundColor: this.finalColor}
}
}
})
</script>
4.2 v-bind 绑定style(数组语法)
<div id="app">
<h2 :style="[baseStyle,baseStyle1]">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
baseStyle: {backgroundColor: 'red'},
baseStyle1: {fontSize: '100px'},
},
})
</script>
5.计算属性:对一些需要转化的数据进行显示更简单;
计算属性相比methods,会进行缓存,如果多次使用,计算属性只会调用一次
5.1 计算属性的示例一
<div id="app">
<!-- 法一:属性-->
<h2>{{firstName + ' ' + lastName}}</h2>
<h2>{{firstName}} {{lastName}}</h2>
<!-- 法二:方法-->
<h2>{{getFullName()}}</h2>
<!-- 法三:计算属性-->
<h2>{{fullName}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: 'Lisa',
lastName: 'chen',
},
// 法二:方法
methods: {
getFullName: function () {
return this.firstName + ' ' + this.lastName
}
},
// 法三:计算属性
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
</script>
5.2 计算属性的示例二
<div id="app">
<h2>总价格为: {{TotalPrice}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
books: [
{id: 110, name: 'linux', price: 100},
{id: 111, name: 'linux1', price: 100},
{id: 112, name: 'linux2', price: 100},
{id: 113, name: 'linux3', price: 100}
],
},
computed: {
TotalPrice: function () {
let result = 0
for(let i = 0; i < this.books.length; i++) {
result += this.books[i].price
}
return result
}
}
})
</script>
5.2 计算属性的示例三:getter方法
<div id="app">
<h2>{{fullName}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: 'kobe',
lastName: 'Lisa',
},
computed: {
// 计算属性一般没有set方法,只读属性
// fullName: {
// get: function () {
// return this.firstName + ' ' + this.lastName
// }
// }
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
</script>
第四章:事件监听
1. v-on
1.1事件监听时,不需要传参时,()可以省略
<div id="app">
<!-- 需求:按+号,计数器增加,按-号,计数器减少-->
<!-- 法一-->
<h2>{{counter}}</h2>
<button v-on:click="counter++">+</button>
<button v-on:click="counter--">-</button>
<!-- 法二-->
<h2>{{counter}}</h2>
<button v-on:click="increment">+</button>
<button @click="decrement">-</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
counter: 0
},
methods: {
// increment: function () {
increment () {
this.counter++
},
decrement () {
this.counter--
}
}
})
</script>
1.2 v-on传参
<div id="app">
<!-- 事件调用的方法没有参数-->
<button @click="btn1Click()">按钮1</button>
<button v-on:click="btn1Click">按钮1</button>
<button @click="btn2Click(123)">按钮2</button>
<button @click="btn2Click()">按钮2</button>
<!-- 在事件定义时,写方法时省略了小括号,但是方法本身是需要一个参数的,这个时候vue会默认将浏览器产生的event事件对象作为参数传入到方法-->
<button @click="btn2Click">按钮2</button>
<button @click="btn3Click">按钮3</button>
<!-- 在调用方式,如何手动的获取到浏览器参数的event对象: $event-->
<button @click="btn3Click(123, $event)">按钮3</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
methods: {
btn1Click () {
console.log('btnClick')
},
btn2Click (event) {
console.log('---', event)
},
btn3Click (abc, event) {
console.log('---', abc, event)
}
}
})
</script>
1.3 v-on的修饰符
1.31 v-on的stop修饰符:阻止事件冒泡
<!--此时会产生事件冒泡-->
<!--<div id="app" @click="divClick">-->
<!-- aaa-->
<!-- <button @click="btnClick">按钮</button>-->
<!--</div>-->
<!--采用修饰符stop阻止事件冒泡-->
<div id="app" @click="divClick">
aaa
<button @click.stop="btnClick">按钮</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {
btnClick () {
console.log('btn')
},
divClick () {
console.log('div')
},
}
})
</script>
1.32 v-on 的prevent修饰符:阻止默认事件
<div id="app">
<form action="baidu">
<!-- 点击事件就默认提交了-->
<input type="submit" value="提交" @click="submitClick">
<!--2.--采用修饰符prevent阻止默认事件-->
<input type="submit" value="提交" @click.prevent="submitClick">
</form>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// message: '你好啊'
},
methods: {
submitClick () {
console.log('submit')
}
}
})
</script>
1.33 v-on 的keyup修饰符:监听某个按键的键帽
<div id="app">
<!-- 3.监听某个键盘的键帽-->
<!-- 此时为监听按键输入抬起来的动作-->
<input type="text" @keyup="keyUp">
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// message: '你好啊'
},
methods: {
keyUp () {
console.log('keyUp')
}
}
})
</script>
1.34 v-on的once修饰符:事件只触发一次
<div id="app">
<!--4. once修饰符:事件只触发一次-->
<button @click.once="btnClick">按钮</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// message: '你好啊'
},
methods: {
btnClick () {
console.log('btn')
}
}
})
</script>
2. 条件判断
2.1 v-if 的使用:
<div id="app">
<h2 v-if="isShow">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true,
}
})
</script>
2.2 v-if和v-else 的使用
<div id="app">
<h2 v-if="isShow">{{message}}</h2>
<h1 v-else>sorry</h1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true,
}
})
</script>
2.3 v-if和v-else-if和v-else 的使用
<div id="app">
<h2 v-if="score>=90">优秀</h2>
<h2 v-else-if="score>=80">良好</h2>
<h2 v-else="score>=60">及格</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
score: 99,
}
})
</script>
2.3 用计算属性更优
<div id="app">
<h2>{{result}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
score: 99,
},
computed: {
result () {
let showMessage = ' '
if(this.score >= 90) {
showMessage = '优秀'
} else if(this.score >= 80) {
showMessage = '良好'
} else {
showMessage = '及格'
}
return showMessage
}
}
})
</script>
3. 案例一: 用户登录
<div id="app">
<span v-if="isUser">
<label for="username">用户账号</label>
<input type="text" id="username" placeholder="用户账号" key="username">
</span>
<span v-else>
<label for="useremail">用户邮箱</label>
<input type="text" id="useremail" placeholder="用户邮箱" key="useremail">
</span>
<button @click="isUser = !isUser">切换类型登录</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isUser: true,
},
})
</script>
4. v-show和v-if:
4.1 v-show 当条件为false时,仅仅是将元素的display属性设置为none
4.2 v-if 当条件为false时,压根就不会有对应的元素在DOM中
总结:当频繁切换时,应该使用v-show; 只有一次切换时使用v-if
<div id="app">
<!-- v-if: 当条件为false时,压根就不会有对应的元素在DOM中-->
<h2 v-if="isShow">{{message}}</h2>
<!-- v-show: 当条件为false时,仅仅是将元素的display属性设置为none-->
<h2 v-show="isShow">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: false,
}
})
</script>
5. v-for 遍历
5.1 v-for 遍历数组
<div id="app">
<!-- 1.在遍历过程中没有使用索引值-->
<ul>
<li v-for="item in names">{{item}}</li>
</ul>
<!-- 2.在遍历过程中使用索引值-->
<ul>
<li v-for="(item, index) in names">
{{index + 1}}.{{item}}
</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
names: ['kobe', 'cindy', 'kristin','lisa']
}
})
</script>
5.2 v-for 遍历对象
<div id="app">
<!-- 1. 在遍历对象的过程中,如果只是获取一个值,那么获取到的是value-->
<ul>
<li v-for="item in info">{{item}}</li>
</ul>
<!-- 2. 获取key和value: (value, key)-->
<ul>
<li v-for="(value, key) in info">{{key}}: {{value}}</li>
</ul>
<!-- 3. 获取key和value和index: (value, key, index)-->
<ul>
<li v-for="(value, key, index) in info">{{index + 1}}-{{key}}: {{value}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
info: {
name: 'kristin',
age: 16,
height: 1.65,
}
}
})
</script>
5.3 v-for 中响应式方法
<div id="app">
<ul>
<li v-for="item in letters">{{item}}</li>
</ul>
<button @click="btnClick">点击</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
letters: ['A', 'B', 'C', 'D', 'E']
},
methods: {
btnClick () {
// v-for中的响应式方法
// 1. push方法:在数组后面添加一个或多个元素
// this.letters.push('F', 'G')
// 2. pop方法:删除数组最后一个元素
// this.letters.pop()
// 3. shift方法:删除数组第一个元素
// this.letters.shift()
// 4. unshift方法:在数组最前面添加一个或多个元素
// this.letters.unshift('a', 'b')
// 5.splice方法:删除/插入/替换元素
// 删除: splice(起始位置,删除元素个数)
// this.letters.splice(0, 2) // C D E
// 添加: splice(起始位置, 0,
// this.letters.splice(0, 0, 'X', 'Y', 'Z') // X Y Z A B C D E
// 替换: splice(起始位置, 替换个数, 替换后的元素)
// this.letters.splice(0, 3, 'm', 'n', 'p') // m n p D E
// 6.sort方法: 排序
// this.letters.sort()
// 7. reverse方法
// this.letters.reverse() // A B C D E
}
}
})
</script>
5.4 v-for的小案例:点击哪里,那里就变红
<!-- css-->
<style>
.active {
color: red;
}
</style>
<!--html-->
<!--作业需求,点击哪一项就文字变红-->
<div id="app">
<ul>
<!-- 动态class属性-->
<li v-for="(item, index) in letters"
:class="{active: currentIndex === index}"
@click="liClick(index)">{{item}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
letters: ['a', 'b', 'c', 'd', 'e'],
currentIndex: 0,
},
methods: {
liClick(index) {
this.currentIndex = index
}
}
})
</script>
6. 购物车案例
第五章:v-model
1. v-model实现双向绑定
<div id="app">
<input type="text" v-model="message">
{{message}}
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
2. v-model结合radio使用
<div id="app">
<lable for="male">
<input type="radio" id="male" name="sex" value="男" v-model="sex">男
</lable>
<lable for="female">
<input type="radio" id="female" name="sex" value="女" v-model="sex">女
</lable>
<h2>你选择的性别是:{{sex}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
sex: '',
}
})
</script>
3. v-model结合checkbox使用
<div id="app">
<!-- <label for="agree">-->
<!--<!– 1. checkbox单选框–>-->
<!-- <input type="checkbox" id="agree" v-model="isAgree">同意协议-->
<!-- </label>-->
<!-- <h2>你选择的是 {{isAgree}}</h2>-->
<!-- <button v-bind:disabled="!isAgree">下一步</button>-->
<!-- 2. checkBoox多选框-->
<input type="checkbox" value="篮球" v-model="hobbies">篮球
<input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
<input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
<input type="checkbox" value="排球" v-model="hobbies">排球
<h2>您的爱好是:{{hobbies}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isAgree: false,
hobbies: []
}
})
</script>
3. v-model结合select使用
<div id="app">
<!-- 下拉单选-->
<select name="fruits" v-model="fruit">
<option value="苹果" >苹果</option>
<option value="香蕉" >香蕉</option>
<option value="榴莲" >榴莲</option>
<option value="葡萄" >葡萄</option>
</select>
<h2>您爱吃的水果是:{{fruit}}</h2>
<!-- 下拉多选-->
<!-- 按住ctr健选择多个-->
<select name="fruits" v-model="fruits" multiple>
<option value="苹果" >苹果</option>
<option value="香蕉" >香蕉</option>
<option value="榴莲" >榴莲</option>
<option value="葡萄" >葡萄</option>
</select>
<h2>您爱吃的水果是:{{fruits}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
fruit: '',
fruits:[]
}
})
</script>
4. v-model值绑定 v-bind: value=""
<div id="app">
<label v-for="item in originHobbies" v-bind:for="item">
<input type="checkbox" v-bind:value="item" v-model="hobbies" v-bind:id="item">{{item}}
</label>
<h2>您的爱好是:{{hobbies}} </h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
originHobbies: ['足球','篮球','羽毛球','乒乓球'],
hobbies: [],
}
})
</script>
5. v-model修饰符
<div id="app">
<!-- 1. 修饰符: lazy-->
<input type="number" v-model.lazy="message">
<h2>{{message}}</h2>
<!-- 2. 修饰符: number-->
<input type="text" v-model.number="age">
<h2>{{age}}--{{typeof(age)}}</h2>
<!-- 3. 修饰符: trim--把空格去掉-->
<input type="text" v-model.trim="name">
<h2>您输入的姓名是: {{name}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
age: 18,
name: '',
}
})
</script>
第六章:Vue组件化
1. Vue组件化的基本使用
<div id="app">
<!-- 3. 使用组件: <使用组件时的标签名></使用组件时的标签名>-->
<cpn></cpn>
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
// 1. 创建组件构造器
const cpnC = Vue.extend({
template: `
<div>
<h2>标题</h2>
<p>内容1</p>
<p>内容2</p>
</div>
`
})
// 2. 注册组件: Vue.component('使用组件时的标签名', 组件构造器)
Vue.component('cpn', cpnC)
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
2. 父组件和子组件
<div id="app">
<mycpn2></mycpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 子组件
const cpn1 = Vue.extend({
template: `
<div>
<h2>标题1</h2>
<p>111111111111</p>
</div>
`
})
// 父组件
const cpn2 = Vue.extend({
template: `
<div>
<h2>标题2</h2>
<p>22222222222</p>
<mycpn1></mycpn1>
</div>
`,
components: {
mycpn1: cpn1
}
})
Vue.component('mycpn2', cpn2)
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
3. 全局组件的语法糖注册写法
// // 第一种写法
// const cpn1 = Vue.extend({
// template: `
// <div>
// <h2>标题2</h2>
// <p>22222222222</p>
// </div>
// `
// })
// Vue.component('mycpn1', cpn1)
// 第二种写法: 语法糖写法
Vue.component('mycpn1',{
template: `
<div>
<h2>标题2</h2>
<p>22222222222</p>
</div>
`
})
4. 局部组件的语法糖注册写法
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
// 局部组件的语法糖写法
components: {
mycpn1: {
template: `
<div>
<h2>标题2</h2>
<p>22222222222</p>
</div>`
}
}
})
5. 组件模板分离写法
5.1 使用script标签,注意:类型必须是text/x-template
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<!--1.script标签,注意:类型必须是text/x-template-->
<script type="text/x-template" id="cpn">
<div>
<h2>title</h2>
<p>ppppppppppp</p>
</div>
</script>
<script src="../js/vue.js"></script>
<script>
// 1.注册一个全局组件
Vue.component('cpn', {
template: `#cpn`
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
5.2 使用template标签
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<!--2.template标签-->
<template id="cpn">
<div>
<h2>title</h2>
<p>bbbbbbbbbbbbbbb</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1.注册一个全局组件
Vue.component('cpn', {
template: `#cpn`
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
6. 组件自己的数据存放在哪里?
组件对象有一个data属性,这个data属性必须是一个函数,而且这个函数返回一个对象,该对象保存数据
<div id="app">
<h2>{{message}}</h2>
<!-- 4.调用组件-->
<cpn></cpn>
</div>
<!--2.组件模板分离-->
<template id="cpn">
<div>
<!-- 3.调用组件自己的数据-->
<h2>{{title}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1. 注册一个全局组件
Vue.component('cpn', {
template: `#cpn`,
data () {
return {
title: '组件自己的数据'
}
}
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
7. 父组件向子组件传递数据--props
<div id="app">
<!-- <cpn v-bind:cmovies="movies" :cmessage="message"></cpn>-->
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<template id="cpn">
<div>
<!-- <p>{{cmovies}}</p>-->
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父传子: props
const cpn = {
template: `#cpn`,
// 1. props: []--数组形式
// props: ['cmovies', 'cmessage'],
// 2. props: {}--对象形式
props: {
// 1.类型限制
// cmovies: Array,
// cmessage: string,
// 2.提供一些默认值,以及必传值
cmessage: {
type: String,
default: '默认值',
required: true, // 必须传值
},
cmovies: {
type: Array,
default() {
return []
},
},
},
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟'],
},
// 局部组件
components: {
cpn
}
})
</script>
8. 子组件向父组件传递(自定义事件)
<!--父组件模板-->
<div id="app">
<!-- 父组件监听事件-->
<cpn @itemclick="cpnClick"></cpn>
</div>
<!--子组件模板-->
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 子组件
const cpn = {
template: `#cpn`,
data() {
return {
categories: [
{id: 'a', name: '热门推荐'},
{id: 'b', name: '手机数码'},
{id: 'c', name: '家用家电'},
{id: 'd', name: '电脑办公'},
]
}
},
methods: {
btnClick() {
// 子组件发射事件
this.$emit('itemclick')
}
}
}
// 父组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
components: {
cpn,
},
methods: {
cpnClick() {
console.log('cpnClick')
}
}
})
</script>
9.父组件直接访问子组件: $children和$refs
<div id="app">
<cpn ref="a"></cpn>
<cpn></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>
我是子组件
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {
btnClick() {
// 1. $children-- 比较少用
// console.log(this.$children);
// this.$children[0].showMessage();
// console.log(this.$children[0].name);
// 2. $refs-- 比较常用
// $refs访问子组件的方法
this.$refs.a.showMessage();
// $refs访问子组件的属性
console.log(this.$refs.a.name);
},
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
name: '我是子组件的name',
}
},
methods: {
showMessage() {
console.log('showMessage');
}
}
}
}
})
</script>
10. 子组件直接访问父组件:
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件cpn</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是子组件ccpn</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
name: '我是cpn组件的name'
}
},
components: {
ccpn: {
template: `#ccpn`,
methods: {
btnClick() {
// // 1. 访问父组件--$parent
// console.log(this.$parent);
// console.log(this.$parent.name);
// 2. 访问根组件--$root
console.log(this.$root);
console.log(this.$root.message);
}
},
}
}
}
}
})
</script>
第七章:插槽slot: 组件的插槽是为了让组件更有扩展性
将共性抽取到组件,将不同暴露为插槽
1. 插槽的基本使用
<div id="app">
<!-- 替换默认值-->
<cpn><span>span</span></cpn>
<!-- 使用默认值-->
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>标题</h2>
<p>hhhhhhhhhhhhh</p>
<!-- 带有默认值的插槽-->
<slot><button>按钮</button></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: `#cpn`,
},
}
})
</script>
2. slot-具名插槽的使用
<div id="app">
<cpn>
<!-- 替换默认的插槽值-->
<!-- <button slot="left">点击</button>-->
<!-- <span slot="center">中间</span>-->
<!-- <span slot="right">右边</span>-->
</cpn>
</div>
<template id="cpn">
<div>
<!-- 多个具名插槽-->
<slot name="left"><span>left</span></slot>
<slot name="center"><span>middle</span></slot>
<slot name="right"><span>right</span></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: `#cpn`,
}
},
})
</script>
3. 编译的作用域:
父组件模板的所有东西都会再父级作用域内编译;
子组件模板的所有东西都会再子级作用域内编译;
<div id="app">
<!-- 作用域是vue实例,此时的isShow是true,所以会展示-->
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<!-- 作用域是子组件cpn,此时的isShow是false,所以不会展示-->
<h2 v-show="isShow">我是子组件</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
isShow: false,
}
}
}
}
})
</script>
4. 作用域插槽:
父组件替换插槽的标签,但是内容由子组件来提供
<div id="app">
<cpn></cpn>
<cpn>
<!-- 目的: 获取子组件的数据-->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{{item}} -- </span>-->
<span>{{slot.data.join(' - ')}}</span>
</template>
</cpn>
<cpn>
<!-- 目的: 获取子组件的数据-->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{{item}} * </span>-->
<span>{{slot.data.join(' * ')}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot :data="pLanguage">
<ul>
<li v-for="item in pLanguage">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
pLanguage: ['Js', 'Ts', 'C++', 'C', 'Python', 'swift'],
}
}
}
}
})
</script>
第八章:模块化开发--导出和导入
1. 常见的模块化规范:CommonJS、AMD、CMD,也有ES6的Modules
1.1 CommonJS
1.1 CommonJS--导出模块
// 导出模块--CommonJS
module.exports = {
flag: flag,
sum: sum,
}
1.1 CommonJS--导入模块
// 导入模块--CommonJS
var {flag, sum} = require('./a.js')
1.2 ES6
type="module"
<body>
<script src="a.js" type="module"></script>
<script src="b.js" type="module"></script>
</body>
1.2 ES6--导出模块
// a.js
let name = 'Lisa'
let flag = true
function sum(num1, num2) {
return num1 + num2
}
if(flag) {
console.log(sum(1, 2));
}
// 导出模块
// 导出方式一
export {
flag, name, sum
}
// 导出方式二
export var num1 = 1000;
export var height = 1.88;
// 导出函数/类
export function add(num1, num2) {
return num1 + num2
}
export class Person{
run(){
console.log('i am running');
}
}
// export default
const adress = 'PeiKing'
export default adress
1.2 ES6--导入模块
// 导入模块
// 导入方式1--导入的{}中定义的变量
import {flag, sum} from "./a.js";
if(flag) {
console.log('求和:');
console.log(sum(10, 20));
}
// 导入方式2--直接导入export中定义的变量
import {num1, height} from "./a.js";
console.log(num1);
console.log(height);
// 导入export的function
import {add, Person} from "./a.js";
console.log(add(30, 50));
const p = new Person();
p.run()
// 导入export的default中的内容
import adr from "./a.js";
console.log(adr);
// 统一全部导入
//import * as 名字 from "./a.js";
import * as a from "./a.js";
console.log(a.name);
第九章:webpack
1.安装:
1.1 先安装Node.js ; 再使用命令全局安装的webpack:npm install webpack -g
1.2 创建项目文件夹
1.3 碰到的问题:
1.31 用webpack打包时用命令执行代码时报错:
webpack ./src/main.js ./dist/bundle.js
改成:webpack ./src/main.js -o ./dist/bundle.js
1.32 执行成功但是一堆warnings,可以配置一个webpack.config.js文件就解决了
module.exports={
mode: 'development',
}
1.33 执行项目代码写的命令太长,可以配置一个webpack.config.js文件,然后终端执行命令简化成webpack就可以执行了
const path = require('path')
module.exports={
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
}
1.34 将执行命令webpack映射npm run build ;在package.json文件中配置
"build": "webpack"
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "",
"license": "ISC"
}
1.35 局部安装webpack
npm install webpack --save-dev
1.36 package.json 的scripts脚本在执行时会按照一定的顺序寻找命令对应的位置:
首先,会寻找本地的node_modules/.bin路径中对应的命令
如果没有找到,会去全局的环境变量中寻找
1.37 如何执行build指令?
npm run build
1.4 webpack扩充loader
1.41 css-loader--负责加载css
先在main.js文件里依赖css文件
// 1. 使用commonjs的模块规范化
const {add, mul} = require('./js/mathUtils')
console.log(add(20, 30));
console.log(mul(20, 30));
// 2. 使用ES6的模块规范化
import {name, age, height} from "./js/info";
console.log(name);
console.log(age);
console.log(height);
// 3.依赖css文件
require('./css/normal.css')
在终端命令:
npm install --save-dev css-loader
然后在webpack.config.js里添加:
module: {
rules: [
{
test: /\.css$/,
use: [ 'css-loader' ]
}
]
}
1.42 style-loader--将模块中的导出作为样式添加到DOM中
在终端命令:
npm install style-loader --save-dev
然后在webpack.config.js里添加:
1.43 webpack-less文件的处理
先在css文件夹下创建一个less文件命名为special.less
再在main.js中进行依赖
在终端安装
npm install --save-dev less-loader less
在webpack.config.js中配置
1.44 webpack--img
先在src下创建img文件夹,添加图片test1
在normal.css里设置背景图片
终端安装命令:
npm install --save-dev url-loader
在webpack.config.js中配置
limit那里的数据小于图片大小时,会报错
则需要安装file-loader
npm install --save-dev file-loader
limit那里的数据大于图片大小时,会将图片编译成base64字符串形式
问题:打包运行,但是页面并没有展示出背景图片,为什么?
解决方案:在webpack.config.js里配置 publicPath: "dist/"就可以展示出页面背景
问题:打包的图片在dist文件下显示的名字是32位的,很复杂,解决方法:
采用在webpack.config.js文件里配置,这样打包得到的dist文件下的图片会放在文件夹img里
2. webpack-ES6转ES5
安装babel-loader
npm install babel-loader babel-core babel-preset-env
在webpack.config.js文件里配置
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
执行:npm run build 此时报错
暂时未解决
3. webpack配置vue
npm install vue --save
然后在main.js中 导入
// 1. 使用commonjs的模块规范化
const {add, mul} = require('./js/mathUtils')
console.log(add(20, 30));
console.log(mul(20, 30));
// 2. 使用ES6的模块规范化
import {name, age, height} from "./js/info";
console.log(name);
console.log(age);
console.log(height);
// 3.依赖css文件
require('./css/normal.css')
// 4. 依赖less文件
require('./css/special.less')
document.writeln('<h2>你好啊</h2>')
// 5.使用vue开发
import Vue from 'vue'
new Vue({
el: '#app',
data: {
message: 'hello webpack',
}
})
在index.html中
<div id="app">
<h2>{{message}}</h2>
</div>
打包运行时出错,需要在webpack.config.js中配置resolve
const path = require('path')
module.exports={
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: "dist/"
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
// 当加载的图片,小于limit时,会将图片编译成base64字符串形式
// 当加载的图片,大于limit时,需要使用file-loader模块进行加载
limit: 8957,
name: 'img/[name].[hash:8].[ext]',
},
}
]
},
// {
// test: /\.js$/,
// exclude: /(node_modules|bower_components)/,
// use: {
// loader: 'babel-loader',
// options: {
// presets: ['@babel/preset-env']
// }
// }
// }
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
}
4. 创建Vue时el和template关系
html模板在之后的开发中,不希望频繁的手动来修改,怎么办?
在main.js中定义template属性
// 5.使用vue开发
import Vue from 'vue'
new Vue({
el: '#app',
template: `
<div>
<h2>{{message}}</h2>
<button @click="btnClick">按钮</button>
<h2>{{name}}</h2>
</div>
`,
data: {
message: 'hello webpack',
name: 'kristin',
},
methods: {
btnClick() {
console.log('click');
}
}
})
index.html中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
</div>
<script src="./dist/bundle.js"></script>
</body>
</html>
同时由template,又有el挂载的东西,,就会把template的东西替换到vue内部,即之前<div id="app">内部东西</div>
优化代码:代码抽离
// 6.使用Vue开发--优化代码
import Vue from 'vue'
const App = {
template: `
<div>
<h2>{{message}}</h2>
<button @click="btnClick">按钮</button>
<h2>{{name}}</h2>
</div>
`,
data() {
return {
message: 'hello webpack',
name: 'kristin',
}
},
methods: {
btnClick() {
}
}
}
new Vue({
el: '#app',
template: `<App></App>`,
components: {
App
}
})
继续优化:在src文件夹下的vue文件夹下创建app.js
export default {
template: `
<div>
<h2>{{message}}</h2>
<button @click="btnClick">按钮</button>
<h2>{{name}}</h2>
</div>
`,
data() {
return {
message: 'hello webpack',
name: 'kristin',
}
},
methods: {
btnClick() {
}
}
}
在main.js中则可以简化,便车给导入模块
// 6.使用Vue开发--优化代码
import Vue from 'vue'
import App from './vue/app.js'
new Vue({
el: '#app',
template: `<App></App>`,
components: {
App
}
})
再简化:在src文件夹下的vue文件夹下创建App.vue
<template>
<div>
<h2 class="title">{{message}}</h2>
<button @click="btnClick">按钮</button>
<h2>{{name}}</h2>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
message: 'hello webpack',
name: 'kristin',
}
},
methods: {
btnClick() {
}
}
}
</script>
<style scoped>
.title {
color: aqua;
}
</style>
然后在main.js中导入
// 6.使用Vue开发--优化代码
import Vue from 'vue'
// import App from './vue/app.js'
import App from './vue/App.vue'
new Vue({
el: '#app',
template: `<App></App>`,
components: {
App
}
})
在终端命令中:
npm install --save-dev vue-loader vue-template-compiler
在webpack.config.js中配置
{
test:/\.vue$/,
use: [
'vue-loader'
]
}
问题:npm run build报错,解决方案:
在package.json中修改vue-loader的版本:
"vue-loader": "^13.0.0",
然后再终端重新安装:npm install
再执行: npm run build
成功,但是style样式没有体现,原因?
未解决
5. webpack-横幅Plugin的使用
5.1 Plugin与loader的区别?
Plugin是插件,它是对webpack本身的扩展,是一个扩展器
loader主要用于转换某些基本类型的模块,它是一个转换器
5.2 Plugin的使用过程?
步骤一:通过npm安装需要使用的plugins
步骤二:在webpack.config.js中的plugins中配置插件
5.3 添加版权的Plugin
效果图如下:
5.4 打包html的plugin--HtmlWebpackPlugin插件
5.4.1作用:
自动生成一个index.html文件
将打包的js文件,自动通过script标签插入到body中
5.4.2 安装
npm install html-webpack-plugin --save-dev
index.html的script语句就可以删除,然后重新打包
5.5 js压缩的plugin插件
5.5.1 安装
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
效果图
6. 搭建本地服务器
webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果
不过它是一个单独的模块,在webpack中使用之前先安装它
npm install --save-dev webpack-dev-server
在webpack.config.js中进行配置
在package.json中配置
在终端执行:
npm run dev
默认在端口8080上执行
改善:自动打开页面
执行报错
8. Vue CLI:
CLI--Command-Line Interface,俗称脚手架,使用vue-cli可以快速dajianVue开发环境以及对应的webpack配置
安装Vue脚手架3: npm install -g @vue/cli
拉取2.x模板: npm install -g @vue/cli-init
Vue CLI2初始化项目: vue init webpack my0project
Vue CLI3初始化项目: vue create my-project