Vue (读音 /vju?/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
如果你想在深入学习 Vue 之前对它有更多了解,我们制作了一个视频,带您了解其核心概念和一个示例工程。
如果你已经是有经验的前端开发者,想知道 Vue 与其它库/框架有哪些区别,请查看对比其它框架。
Vue安装方式
Vue使用步骤
Vue({})
对象,并在html中指定Vue要渲染的容器<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>初识Vue</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">{{message}}</div>
<script>
let app = new Vue({
el: ‘#app‘,
data: {
message: ‘小红‘,
},
})
</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>初识Vue</title>
<script src="js/vue.js"></script>
<style>
span {
margin: 50px 50px;
background-color: bisque;
}
</style>
</head>
<body>
<div id="app">
{{message}}
<br />
<span v-bind:title="title"
>鼠标悬停几秒钟查看此处动态绑定的提示信息!</span
>
</div>
<script>
let app = new Vue({
el: ‘#app‘,
data: {
message: ‘小红‘,
title: ‘页面加载与‘ + new Date().toLocaleDateString(),
},
})
</script>
</body>
</html>
总结
v-bind:title
被称为指令,指令带有前缀v-
,表示他们由Vue
提供的指令title attribute
和Vue
实例的title
保持一致”如果你再次打开浏览器的 JavaScript 控制台,输入 app2.message = ‘新消息‘
,就会再一次看到这个绑定了 title
attribute 的 HTML 已经进行了更新。
绑定DOM结构,动态判断来确定一个html标签执行否
<!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="js/vue.js"></script>
</head>
<body>
<div id="app">
要显示当前时间吗?<br />
<span v-if="flag">{{dateNow}}</span>
<button type="button" v-on:click="funAdd">显示</button>
<button type="button" v-on:click="funNo">不显示</button>
</div>
<script>
let app = new Vue({
el: ‘#app‘,
data: {
dateNow: ‘当前时间为:‘ + new Date().toLocaleDateString(),
flag: false,
},
methods: {
funAdd: function () {
this.flag = true
},
funNo: function () {
this.flag = false
},
},
})
</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>列表展示</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
{{message}}
<br />
<ul>
<li v-for="i in list">{{i}}</li>
</ul>
</div>
<script>
let app = new Vue({
el: ‘#app‘,
data: {
message: ‘列表展示‘,
list: [‘Java‘, ‘C‘, ‘C++‘, ‘Go‘],
},
})
</script>
</body>
</html>
就是从Vue的属性中获取值,然后插入对应HTML中
又叫做胡须语法,两边像胡子
{{message}}
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mustache语法</title>
<script src="../js/vue.js"></script>
</head>
<body>
<h1>Mustache语法,又叫做胡须语法</h1>
<div id="app">
<h3>{{message}}</h3>
<h3>{{message}}, 小新</h3>
<h3>{{message + " " + temp}}</h3>
<h3>{{message}} {{temp}}</h3>
</div>
<script>
let app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么?‘,
temp: ‘Vue.js‘,
},
})
</script>
</body>
</html>
渲染属性之后,不会根据响应式来改变值
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-once指令,不想响应式改变值</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h3>{{message}}</h3>
<h3 v-once>{{message}}</h3>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
},
methods: {},
})
</script>
</body>
</html>
有时候,后端返回的是一个标签,并不是一个连接,这种情况下想把服务器返回的标签插入的Html页面中,就需要用到v-html
指令了
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h3>{{url}}</h3>
<h3 v-html="url"></h3>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
url: ‘<a href="http://www.baidu.com">百度一下</a>‘,
},
methods: {},
})
</script>
</body>
</html>
显示结果
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-text指令使用,与Mustache类似,但不够灵活</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 追加覆盖-->
<h3>{{message}},新酱</h3>
<!-- 直接覆盖-->
<h3 v-text="message">新酱</h3>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
},
methods: {},
})
</script>
</body>
</html>
图片示例
图片
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-pre指令,不替换值</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h3>{{message}}</h3>
<!-- 原样展示 -->
<h3 v-pre>{{message}}</h3>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
},
methods: {},
})
</script>
</body>
</html>
有种情况JS代码执行不了
这就导致HTML页面原样显示数据的话,太别丑
所以需要v-cloak
指令
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-cloak指令,js代码加载完成后显示内容</title>
<script src="../js/vue.js"></script>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<!--
Vue的执行流程,比如下面的代码,h3中,它是原样的展示,直到执行对应的Js代码之后,才会将内容替换成要显示的数据。
这个时候,有一个种情况,就是js代码加载不出来,或卡主了,为了防止原样的展示,所以需要v-cloak指令,让js代码执行完毕后在显示Html代码
-->
<div id="app" v-cloak>
<h3>{{message}}</h3>
</div>
<script>
// 模拟Js代码卡主,页面是还没有渲染的
setInterval(function () {
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
},
methods: {},
})
}, 5000)
</script>
</body>
</html>
之前,学习的都是标签体内容替换,这次来替换标签的属性,那么该如何使用呢?
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-bind属性绑定</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 之前的数据绑定,对标签属性而言是错误的
<img src="{{imgURL}}" alt="" />
<a href="{{url}}"></a>
-->
<img v-bind:src="imgURL" alt="" />
<a v-bind:href="url">百度一下</a>
<!-- 语法糖书写方式,简略方式 -->
<img :src="imgURL" alt="" />
<a :href="url">百度一下</a>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
imgURL:
‘https://dss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1950846641,3729028697&fm=111&gp=0.jpg‘,
url: ‘http://www.baidu.com‘,
},
methods: {},
})
</script>
</body>
</html>
动态修改标签体class
属性的值
语法:<div v-bind:class="{类名1: boolean 类名2: boolean}"></div>
动态添加,一个标签体的class属性
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>动态绑定v-bind(class类名)对象语法</title>
<script src="../js/vue.js"></script>
<style>
.acction {
color: red;
}
.flage {
color: blue;
font-size: 18px;
}
</style>
</head>
<body>
<div id="app">
<div :class="temp">{{message}}</div>
<br /><br /><br />
<!-- 实际应用,复杂的语法 -->
<!--
如果为true,才会显示类名
<div v-bind:class="{类名1: boolean 类名2: boolean}"></div>
-->
<div :class="{acction: isAcction, flage: isFlage}">{{message}}</div>
<button type="button" v-on:click="fun1">显示添加样式</button>
<!-- 所以实际开发中 -->
<div class="写固定的类名" :class="动态显示的类名"></div>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
temp: ‘acction‘,
isAcction: true,
isFlage: true,
},
methods: {
fun1: function () {
this.isFlage = !this.isFlage
},
},
})
</script>
</body>
</html>
补充,还可以是函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-bind对象语法,补充-方法获取class类名</title>
<script src="../js/vue.js"></script>
<style>
.accone {
color: red;
}
</style>
</head>
<body>
<div id="app">
<div :class="getClass()">{{message}}</div>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
},
methods: {
getClass: function () {
return { accone: true }
},
},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-bind数组</title>
<script src="../js/vue.js"></script>
<style>
.accone {
color: red;
}
.line {
font-size: 20px;
}
</style>
</head>
<body>
<div id="app">
<!-- 不带引号是变量,带引号就是字符串 -->
<div :class="[active, line]">{{message}}</div>
<div :class="getClass()">{{message}}</div>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
active: ‘accone‘,
line: ‘line‘,
message: ‘你好么‘,
},
methods: {
getClass: function () {
return [this.active, this.line]
},
},
})
</script>
</body>
</html>
更改标签体的Style
属性
直接插入对象,对象是CSS
格式,key
是驼峰命名
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>动态绑定Style</title>
<script src="../js/vue.js"></script>
<style>
.cals {
font-size: 10px;
color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- <div :style="{key(Style语法): ‘值‘| 变量}">你好吗</div> -->
<div :style="{finalSize: findSize, color: finalColor}">你好吗</div>
<div :style="{finalSize: findSize, color: finalColor}">你好吗</div>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
finalColor: ‘red‘,
finalSize: "100px"
},
methods: {},
})
</script>
</body>
</html>
数组的元素是,已经定义好的样式,在data
中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>动态绑定v-bind(数组)</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<div :style="[baseStyle, baseFonse]">{{message}}</div>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么?‘,
baseStyle: {
backgroundColor: ‘red‘,
},
baseFonse: {
fontSize: ‘30px‘,
},
},
methods: {},
})
</script>
</body>
</html>
代码示例
<title>作业</title>
<script src="../js/vue.js"></script>
<style>
.acc {
color: red;
}
li {
padding-top: 10px;
}
</style>
</head>
<body>
<div id="app">
<ul>
<li
v-for="(m,index) in list"
v-on:click="fun1(index)"
:class="{acc: currentIndex === index}"
>
{{index}}-{{m}}
</li>
</ul>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
list: [‘小新‘, ‘小白‘, ‘夏红‘, ‘小明‘],
currentIndex: -1,
},
methods: {
fun1: function (index) {
this.currentIndex = index
},
},
})
</script>
</body>
</html>
获取data
对象里,两个变量的内容
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>计算属性</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<div>{{message + ‘ ‘ + lastName}}</div>
<div>{{message}} {{lastName}}</div>
<div>{{getName()}}</div>
<!-- 计算属性 -->
<div>{{NameAll}}</div>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么?‘,
lastName: ‘小新‘,
},
// 计算属性
computed: {
NameAll: function () {
return this.message + ‘ ‘ + this.lastName
},
},
// 方法
methods: {
getName() {
return this.message + ‘ ‘ + this.lastName
},
},
})
</script>
</body>
</html>
总结:
计算属性,放在computed
中,他不是一个方法或函数,只是属性,写方上省略了set
方法
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>计算属性,复杂操作</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<div>书总价格:{{priceAll}}</div>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
books: [
{ id: 10001, name: ‘Unix编程艺术‘, price: 110 },
{ id: 10002, name: ‘代码大全‘, price: 119 },
{ id: 10003, name: ‘深入理解计算机原理‘, price: 89 },
],
},
computed: {
priceAll: function () {
let sum = 0
for (let i = 0; i < this.books.length; i++) {
sum += this.books[i].price
}
return sum
},
},
methods: {},
})
</script>
</body>
</html>
在浏览器中,默认情况下,直接访问计算属性的话是调用它的get
方法
如果要在修改属性的值的话,浏览器默认调用set
方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>计算属性的get和set方法</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h3>{{funALl}}</h3>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
lastName: ‘张‘,
firstName: ‘红‘,
},
methods: {},
computed: {
// 属性的全写,有get和set方法,在输出的时候默认自动调用get方法;在修改的时候调用set方法
funALl: {
get: function () {
return ‘abc‘
},
set: function (temp) {
console.log(temp)
},
},
// 以下为简写,省略了set方法
funALl: function () {
return this.lastName + ‘ ‘ + this.firstName
},
},
})
</script>
</body>
</html>
证明上面说的话
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Mustache(函数)优势对比</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!--
函数:每次遇到了就会调用
计算属性:只执行一次,然后不会再调用,只有被修改才会调用
-->
<h3>{{funAll()}}</h3>
<h3>{{funAll()}}</h3>
<h3>{{funAll()}}</h3>
<h3>{{funAll()}}</h3>
<h3>{{funName}}</h3>
<h3>{{funName}}</h3>
<h3>{{funName}}</h3>
<h3>{{funName}}</h3>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
lastName: ‘张‘,
firstName: ‘红‘,
},
methods: {
funAll: function () {
console.log(‘方法执行‘)
return this.lastName + ‘ ‘ + this.firstName
},
},
computed: {
funName: function () {
console.log(‘计算属性执行‘)
return this.lastName + ‘ ‘ + this.firstName
},
},
})
</script>
</body>
</html>
使用方式
v-on:事件名
语法糖:@事件名
代码示例
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-on基本使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
{{count}} <br />
<!-- 第一种写法 -->
<button type="button" v-on:click="count++">+</button>
<button type="button" v-on:click="count--">-</button>
<br /><br /><br />
<!-- 第二中写法 -->
<button type="button" v-on:click="add">+</button>
<button type="button" v-on:click="sub">-</button>
<br /><br /><br />
<!-- 语法糖写法 -->
<button type="button" @click="add">+</button>
<button type="button" @click="sub">-</button>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
count: 0,
},
methods: {
add() {
this.count++
},
sub() {
this.count--
},
},
})
</script>
</body>
</html>
触发事件,函数回调传参问题
自动封装event参数(事件对象)
()
号调用函数,event
对象,需要这么玩$event
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-on参数使用问题</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 1. 无参,不写括号:没有区别都可以执行函数 -->
<button type="button" @click="fun1">按钮1</button>
<button type="button" @click="fun1()">按钮1</button>
<br /><br /><br />
<!-- 2. 有参数,写上参数或不写参数
带括号无参数:正常执行函数,但是参数是个undefined
不带括号,无参数:Vue自动封装事件对象event传输到参数中
-->
<button type="button" @click="fun2()">按钮2带括号</button>
<button type="button" @click="fun2">按钮2不带</button>
<br /><br /><br />
<!-- 3. 有参数,要事件对象也要参数
不自动封装事件对象
加上`$`符号会封装事件对象
-->
<button type="button" @click="fun3(123)">按钮5有参数,</button>
<button type="button" @click="fun3(abc, $event)">
按钮6,有参数,当做变量,并封装事件对象
</button>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
abc: ‘Xiaoxin‘,
},
methods: {
fun1() {
console.log(‘fun1‘)
},
fun2(obj) {
console.log(‘fun2‘, obj)
},
fun3(abc, event) {
console.log(‘abc:‘ + abc + ‘\nevent:‘, event)
},
},
})
</script>
</body>
</html>
事件修饰符
.stop |
解决事件冒泡 |
---|---|
.prevent |
阻止默认事件,可以阻止默认事件,比如表单默认提交 |
.{keyCode|keyAlias} |
只当事件从特定键触发才触发回调 |
.native |
监听组件根元素的原生事件 |
.once |
只触发一次回调 |
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-on事件修饰符的使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<div @click="divClick">
<!-- 这样会有时间冒泡,就是按钮被单击,div也会触发单击事件
解决办法是:
-->
<button @click.stop="buttonClick">按钮</button>
</div>
<form action="/baidu">
<!-- 阻止表单自动提交,阻止默认事件 -->
<input type="submit" value="提交" @click.prevent />
</form>
<input type="text" name="" id="" @keyup="key" /> <br />
<!-- 键盘特定事件来触发函数 -->
<input type="text" name="" id="" @keyup.enter="Mykeyup" />
<br /><br /><br />
<!-- 只触发一次事件 -->
<button type="button" @click.once="Myonce">once触发一次事件</button>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {
divClick() {
console.log(‘divClick‘)
},
buttonClick() {
console.log(‘buttonClick‘)
},
Mykeyup() {
console.log(‘按回车键了 ‘)
},
key() {
console.log(‘键盘按键抬起触发‘)
},
Myonce() {
console.log(‘只触发一次‘)
},
},
})
</script>
</body>
</html>
条件表达式如果为true
那么就会显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-if使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h2 v-if="isShow">
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
{{message}}
</h2>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
isShow: true,
},
methods: {},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-else使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h2 v-if="isShow">
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
{{message}}
</h2>
<h3 v-else>isShow为false显示我</h3>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
isShow: false,
},
methods: {},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-else-if的使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 不建议这么玩,太麻烦,使用计算属性是最佳解决办法 -->
<h3 v-if="score>80">优秀</h3>
<h3 v-else-if="score>60">及格</h3>
<h3 v-else>不及格</h3>
<h1>{{showScore}}</h1>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
score: 100,
},
computed: {
showScore() {
let showStr = ‘‘
if (this.score > 80) {
showStr = ‘优秀‘
} else if (this.score > 60) {
showStr = ‘及格‘
} else {
showStr = ‘不及格‘
}
return showStr
},
},
methods: {},
})
</script>
</body>
</html>
v-if
:不一样的就是v-if结果为false的时候hmlt文件中就不会生成DOMv-show
:只是影藏标签<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-show的使用和与v-if的不同</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h3 v-if="isUser">v-if</h3>
<br />
<h3 v-show="isUser">v-show</h3>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
isUser: true,
},
methods: {},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>用户登录方式切换案例</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<span v-if="isUser">
<label for="username">用户名登录</label><br />
<input type="text" id="username" placeholder="用户名" />
</span>
<span v-else>
<label for="email">邮箱登录</label><br />
<input type="text" id="email" placeholder="用户邮箱" />
</span>
<button @click="isUser = !isUser">切换登录方式</button>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
isUser: true,
},
methods: {},
})
</script>
</body>
</html>
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>案例-01小bug说明以及修复</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
Bug说明: 输入了内容,然后点击切换,发现内容还是存在,正常来说内容应该消失了,
原因:Vue在渲染的时候回对DOM进行优化,像这种差不多的DOM,它都会更换名称(个人现在理解)
解决办法:给input加入key属性标明不一致,Vue就会生成两个,而不是修改属性了
-->
<div id="app">
<span v-if="isUser">
<label for="username">用户名登录</label><br />
<input type="text" id="username" placeholder="用户名" key="username" />
</span>
<span v-else>
<label for="email">邮箱登录</label><br />
<input type="text" id="email" placeholder="用户邮箱" key="email" />
</span>
<button @click="isUser = !isUser">切换登录方式</button>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
isUser: true,
},
methods: {},
})
</script>
</body>
</html>
建议:
每个元素加:key
,如果在运行期间,我们往里面加一个元素,Vue会如何处理?
会,一个一个替代,比如在3号位置插入F,其余的3号变4号,4号变5号,依次类推,这样会繁琐, 建议是加:key
属性,值建议是:元素值,不过如果是相同的值,就会报一个警告,但是如果保证数据的唯一性,这样的问题也不会出现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-for遍历数组</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in names" :key="item">{{item}}</li>
</ul>
<hr />
<ul>
<li v-for="(item, index) in names">{{item}} - {{index+1}}</li>
</ul>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
names: [‘java‘, ‘python‘, ‘C‘, ‘C++‘, ‘C‘],
},
methods: {},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-for遍历对象</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in info">{{item}}</li>
</ul>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
info: {
name: ‘张三‘,
age: 21,
sex: ‘男‘,
},
},
methods: {},
})
</script>
</body>
</html>
样式
代码示例
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>书籍购物车案例</title>
<script src="../js/vue.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="app">
<div v-if="list.length > 0">
<table>
<thead>
<tr>
<th></th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr
v-if="list != null || list.length == 0"
v-for="(item, index) in list"
>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{getPrice(item.price)}}</td>
<td>
<button
type="button"
@click="subPrice(index)"
v-bind:disabled="item.number <= 1"
>
-
</button>
{{item.number}}
<button type="button" @click="addPrice(index)">+</button>
</td>
<td>
<button type="button" @click="deleteBook(index)">移除</button>
</td>
</tr>
</tbody>
</table>
<span>总价格:{{priceSum}}</span>
</div>
<h3 v-else>购物车为空</h3>
</div>
<script src="main.js"></script>
</body>
</html>
style.css
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th,
td {
padding: 8px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
th {
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}
main.js
const app = new Vue({
el: ‘#app‘,
data: {
list: [
{
id: 1,
name: ‘Java编程思想‘,
date: ‘2020-01‘,
price: 89,
number: 1,
Oprice: 89,
},
{
id: 2,
name: ‘Linux从入门到入土‘,
date: ‘2020-02‘,
price: 59.8,
number: 1,
Oprice: 59.8,
},
{
id: 3,
name: ‘现代计算机‘,
date: ‘2020-03‘,
price: 79,
number: 1,
Oprice: 79,
},
{
id: 4,
name: ‘Java核心技术I/II‘,
date: ‘2020-01‘,
price: 150,
number: 1,
Oprice: 150,
},
],
},
methods: {
addPrice(index) {
this.list[index].price =
++this.list[index].number * this.list[index].Oprice
},
subPrice(index) {
// 最少一本书
if (this.list[index].number < 0) {
this.list[index].number = 1
}
this.list[index].price =
--this.list[index].number * this.list[index].Oprice
},
deleteBook(index) {
this.list.splice(index, 1)
},
getPrice(price) {
return ‘¥‘ + price.toFixed(2)
},
},
computed: {
priceSum() {
// let sum = 0
// 第一种遍历方式
// i是下标
// for (let i = 0; i < this.list.length; i++) {
// sum += this.list[i].price
// }
// 第二种遍历方式
// i还是下标
// for (let i in this.list) {
// console.log(i)
// }
// 第三种遍历方式
// item是数组中的值, `of`关键字
// for (let item of this.list) {
// sum += item.price
// }
let sum = this.list.reduce(function (prevValue, book) {
return (prevValue += book.price)
}, 0)
console.log(sum)
return sum
},
},
})
表单绑定
Vue
中使用v-model指令来实现表单元素和数据双向绑定双向绑定
input:value
中数据其实使用v-bind
指令和事件也可以实现v-model
的作用
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-model基本使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message" />
<br /><br /><br />
{{message}}
<br /><br /><br />
<hr />
密码
<input type="password" name="" id="" v-model="password" />
<br />
<h2>密码为:{{password}}</h2>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
password: ‘‘,
},
methods: {},
})
</script>
</body>
</html>
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-model原理,使用其他指令完成</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<input
type="text"
:value="message"
@input="message = $event.target.value"
/>
<br /><br /><br />
{{message}}
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好么‘,
},
methods: {},
})
</script>
</body>
</html>
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-model结合radio单选框使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<label for="gender"
><input
type="radio"
name="sex"
id="gender"
value="男"
v-model="gender"
/>
男
</label>
<label for="nv"
><input type="radio" name="sex" id="nv" value="女" v-model="gender" />
女</label
>
<hr />
<hr />
<h2>您选中的性别是: {{gender}}</h2>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
gender: ‘‘,
},
methods: {},
})
</script>
</body>
</html>
单选
属性是true
或false
多选
多选框value是选项,也可以是数组,具体看情况
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-model结合check多选框使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!--
1. 单选框使用,单选框value是布尔类型
同意协议
-->
<label for="agreement">
<input type="checkbox" name="" id="agreement" v-model="isAgreement" />
同意协议
</label>
<h2>您的选择是: {{isAgreement}}</h2>
<hr />
<hr />
<!--
2. 多选框使用,多选框value是选项
-->
<label for="Basketball">
<input
type="checkbox"
name=""
id="Basketball"
value="篮球"
v-model="hobbys"
/>篮球
</label>
<label for="Football">
<input
type="checkbox"
name=""
id="Football"
value="足球"
v-model="hobbys"
/>足球
</label>
<label for="music">
<input
type="checkbox"
name=""
id="music"
value="音乐"
v-model="hobbys"
/>音乐
</label>
<label for="Playgames">
<input
type="checkbox"
name=""
id="Playgames"
value="打游戏"
v-model="hobbys"
/>打游戏
</label>
<br /><br />
<h2>您的选择是{{hobbys}}</h2>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
isAgreement: false,
hobbys: [],
},
methods: {},
})
</script>
</body>
</html>
单选
value
的值是data
属性中的值
多选
<select>
标签加上multiple
属性
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-model结合select单选和多选使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<select name="abc" id="" v-model="fruits">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="葡萄">葡萄</option>
<option value="橘子">橘子</option>
</select>
<br /><br />
<h2>您选中的水果是:{{fruits}}</h2>
<hr />
<h1>多选</h1>
<br />
<select name="abc" id="" v-model="list" multiple>
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="葡萄">葡萄</option>
<option value="橘子">橘子</option>
</select>
<br /><br />
<h2>您选中的水果是{{list}}</h2>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
fruits: ‘苹果‘,
list: [],
},
methods: {},
})
</script>
</body>
</html>
像前面的04-check,爱好都是写死的,在项目中肯定是需要从后台拿的,那么这样该这么玩,也叫值绑定
我们前面的value中的值,都是写死的,实际开发中,这些input值是从后台过来的,所以我们可以通过v-bind:value动态绑定给value绑定值,这不就是v-bind吗
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>值绑定</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
像前面的04-check,爱好都是写死的,在项目中肯定是需要从后台拿的,那么这样该这么玩,也叫值绑定
我们前面的value中的值,都是写死的,
实际开发中,这些input值是从后台过来的
所以我们可以通过v-bind:value动态绑定给value绑定值
这不就是v-bind吗
-->
<div id="app">
<h2>选择您的爱好:{{temps}}</h2>
<label v-for="item in hobbtys" :for="item">
<input
type="checkbox"
name=""
:id="item"
:value="item"
v-model="temps"
/>
{{item}}
</label>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
hobbtys: [‘篮球‘, ‘足球‘, ‘乒乓球‘, ‘打游戏‘, ‘吃鸡‘],
temps: [],
},
methods: {},
})
</script>
</body>
</html>
lazy
:就是说与input:text控件绑定的话,文本框内容变动,data里就变太浪费,可以让他只有在文本框失去焦点或按下回车才会更新data
中的数据number
:保证绑定data
数据中的数据是一个number
类型trim
:输出字符串两边空格代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-model修饰符的使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!--
1. lazy 懒
就是说与input:text控件绑定的话,文本框内容变动,data里就变太浪费,
需求:想要文本框输入之后按回车或者文本框失去焦点在更新
-->
<input type="text" name="" id="" v-model.lazy="message" />
<br />
<h2>您输入的内容为: {{message}}</h2>
<br /><br />
<hr />
<!--
2. number修饰符 ,
默认情况下:文本框输入的内容是string类型,即使你绑定的数据时number也会转换为string,
需求:输入的转换为number类型,加上修饰符即可完成
-->
<input type="text" v-model="num" /><!--string 类型-->
<br />
<input type="text" v-model.number="num" />
<!-- number类型 -->
<br />
<h2>您输入的是:{{num}},类型为:{{typeof num}}</h2>
<br /><br />
<hr />
<!--
3. trim修饰符,删除多余空格
-->
<input type="text" v-model="name" />
<!--有空额-->
<br />
<input type="text" v-model.trim="name" />
<!-- 无空格 -->
<h2>您输入的内容为:{{name}}</h2>
</div>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘‘,
num: ‘‘,
name: ‘‘,
},
methods: {},
})
</script>
</body>
</html>
组件的使用步骤
创建组件
const pnC = Vue.extend({
template: `<div>
<h2>我是标题</h2>
<p>我是内容哈哈哈哈哈。</p>
<p>嘿嘿嘿,嘻嘻嘻</p>
</div>`,
})
注册组件
Vue.component(‘my-cpn‘, pnC)
使用组件
<div id="app">
<!-- 3. 在这里使用组件 -->
<my-cpn></my-cpn>
</div>
个人概念
说白了,就相当于是一个将HTML代码转化成一个函数一样的东西,Vue里呢就是定义一个新标签,然后编写模块里的内容即可。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>组件的基本使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 3. 在这里使用组件 -->
<my-cpn></my-cpn>
</div>
<script>
// 组件的使用方式
// 1. 创建组件构造器
const pnC = Vue.extend({
template: `<div>
<h2>我是标题</h2>
<p>我是内容哈哈哈哈哈。</p>
<p>嘿嘿嘿,嘻嘻嘻</p>
</div>`,
})
// 2. 注册组件
Vue.component(‘my-cpn‘, pnC)
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
})
</script>
</body>
</html>
Vue.component(‘my-cpn‘, pnC)
注册的默认都是全局组件代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>全局组件和局部组件</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
Vue中使用 Vue.component(‘my-cpn‘, pnC) 注册的组件,默认都是全局组件。
局部组件的注册方式是在Vue实例对象中注册组件才会是局部组件
全局组件:使用函数注册Vue.component(‘my-cpn‘, pnC),注册之后哪里都可以使用
局部组件:在Vue实例里面注册components,只有这一个实例才可以使用
-->
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<div id="app2">
<!-- 不起效果 -->
<cpn></cpn>
</div>
<script>
// 1. 创建组件
let cpnC = Vue.extend({
template: `
<div><h2>您好啊</h2>
<p>哈哈您习</p>
</div>
`,
})
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
components: {
cpn: cpnC, // 注册局部组件
},
})
var app2 = new Vue({
el: ‘#app2‘,
})
</script>
</body>
</html>
Vue.component(‘my-cpn‘, pnC)
注册的全局组件,之外,谁给你注册的谁就是你的父组件子组件注册之后只能在父组件的范围中使用,如果在别的地方使用,那么就会注册全局组件或者在它下面再注册一次
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>父组件和子组件的使用和区别</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
<!-- 不能够使用,如果想使用,那么只能在Vue示例中在注册一次,所以Vue可见也可以当做是一个组件 -->
<cpn1></cpn1>
</div>
<script>
// 是cpnC2的子组件
let cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>哈哈哈</p>
</div>
`,
})
// 父组件
let cpnC2 = Vue.extend({
template: `
<div>
<h2>我是标题2</h2>
<p>呵呵</p>
<cpn1></cpn1>
</div>
`,
components: {
cpn1: cpnC1,
},
})
// 可以当做根组件(root)来看
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
components: {
cpn: cpnC2,
},
})
</script>
</body>
</html>
components
中可以直接定义它的组件代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>语法糖的全局组件和局部组件的注册于使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<my-cpn2></my-cpn2>
<cpn3></cpn3>
</div>
<script>
// 以前的组件注册方式
let cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>哈哈哈</p>
</div>
`,
})
Vue.component(‘my-cpn‘, cpnC1)
// 语法糖写法
Vue.component(‘my-cpn2‘, {
template: `
<div>
<h2>语法糖注册全局组件</h2>
<p>哈哈哈</p>
</div>
`,
})
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
cpn3: {
template: `
<div>
<h2>语法糖注册局部组件</h2>
<p>嘿嘿嘿</p>
</div>
`,
},
},
})
</script>
</body>
</html>
<template id="cpn">
标签,在注册组件的时候指定id
名称即可 推荐使用<script type="text/x-template" id="cpn">
标签,指定上id
值与type
值代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>组件模板分离写法</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn2></cpn2>
</div>
<!-- 1. 分离写法一: 一定要套一个div -->
<script type="text/x-template" id="cpn">
<div>
<h2>组件分离写法1</h2>
<p>哈哈哈哈哈哈哈哈哈哈或或或或或</p>
</div>
</script>
<!-- 2. 第二种写法 template标签使用 一定要套一个div -->
<template id="cpn2">
<div>
<h2>组件分离写法2</h2>
<p>嘻嘻嘻黑恶Hi好IE</p>
</div>
</template>
<script>
// 注册组件
Vue.component(‘cpn‘, {
template: ‘#cpn‘,
})
Vue.component(‘cpn2‘, {
template: ‘#cpn2‘,
})
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {},
})
</script>
</body>
</html>
组件可以访问实例中的数据吗?
答案:不可以,从定义上来说组件是独立的,所以它应该有属于自己的数据模型。
组件如何拥有属于自己的数据模型?
答案:
data()
函数,并返回的是一个对象,这样组件才会用于自己的数据,代码示例
子组件没有数据,访问出错
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>组件可以访问实例中的数据吗</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>{{totial}}</h2>
<p>哈哈哈哈哈</p>
</div>
</template>
<script>
Vue.component(‘cpn‘, {
template: ‘#cpn‘,
})
var app = new Vue({
el: ‘#app‘,
data: {
totial: ‘我是一个标题‘,
},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {},
})
</script>
</body>
</html>
给子组件创建属于组件自己的数据模型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>组件访问实例中的数据</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
1. 组件如何拥有属于自己的数据区:data(){}函数 返回对象实例, 对象实例就是数据,这样。组件才会独立,一个页面有多个相同组件才不会受干扰,还是说组件的独立性
2. 如何访问 就是Mustache语法插值
-->
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>{{totial}}</h2>
<p>哈哈哈哈哈</p>
</div>
</template>
<script>
Vue.component(‘cpn‘, {
template: ‘#cpn‘,
data() {
return {
totial: ‘我是标题哈哈‘,
}
},
})
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {},
})
</script>
</body>
</html>
组件的data为什么是函数
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>组件的data为什么是函数</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h3>当前数字为:{{count}}</h3>
<br />
<button type="button" @click="count++">+</button>
<button type="button" v-on:click="count--">-</button>
</div>
</template>
<script>
Vue.component(‘cpn‘, {
template: ‘#cpn‘,
data() {
return {
count: 0,
}
},
})
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {},
})
</script>
</body>
</html>
父组件给子组件通信:props属性
子组件给父组件通新:子组件中自定义事件,父组件监听
为什么需要组件之间的通信?
在实际开发中,可以能一个网页是由多个组件来组成的,按照规定,一般由root
组件发送网页请求,然后子组件来对返回的数据进行展示,这个时候就需要父子组件的通信
子组件是如何表明哪些数据是从父组件传输过来的?
子组件标明props
属性来标明
如何使用?
在使用子组件的时候传递参数,一定要使用v-bind
来绑定,不然Vue
会当做字符串来处理
props属性可以是什么类型的数据?
requied
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>组件通信,父给子组件通信</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
为什么需要组件之间通信?
在实际开发中,可能一个网页是由多个组件组成的,按照规范,一般root组件来发送网页请求,然后子组件来对返回到的数据进行处理并显示
这个时候就需要父组件来对子组件传输信息
子组件是如何表明哪些数据是从父组件传输过来的?
通过props属性来表明的
那么如何使用?
在使用子组件的时候传递参数 一定要使用v-bind来绑定,不然Vue会当做字符串来处理
props属性可以有什么
- 数组
- 对象
-->
<div id="app">
<cpn :cmessage="message" :clist="list"></cpn>
<hr />
<cpn2 :cmessage="message"></cpn2>
</div>
<template id="cpn">
<div>
<h2>{{cmessage}}</h2>
<ul>
<li v-for="item in clist">{{item}}</li>
</ul>
</div>
</template>
<template id="cpn2">
<div>
<h2>字符串是{{cmessage}}</h2>
<ul>
<li v-for="item in clist">{{item}}</li>
</ul>
</div>
</template>
<script>
// 自定义类型
function Preson() {}
const cpn = {
template: ‘#cpn‘,
props: [‘cmessage‘, ‘clist‘],
}
const cpn2 = {
template: ‘#cpn2‘,
props: {
// 基本数据类型规定,表明传输过来的一定要是字符串类型
cmessage: String,
clist: {
type: Array, // 类型
default() {
return [] // 如果默认值是对象 default必须是函数
},
// 默认值
requied: false, // 必须传输
},
author: Preson, // 自定义类型
},
}
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘电影排行榜‘,
list: [‘阿凡达‘, ‘寄生虫‘, ‘少年与海‘, ‘绅士们‘],
},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
cpn,
cpn2,
},
})
</script>
</body>
</html>
问题:在子组件的props属性的变量命令,如果是驼峰,比如
cMessage
那么在绑定的时候就必须这么写:c-message="xx"
问题原因:由于HTML没有大小写规范,所以只能在大写字母前面加-
来分明
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
props与驼峰命名:
对于子组件中的props属性的命名,如果是驼峰,那么就得在HTML中写c-list这样才行 大写转小写 前面+ -
这是因为HTML是没有大小写区分的
-->
<div id="app">
<npc :c-message="message" :c-list="list"></npc>
</div>
<template id="npc">
<div>
<h2>{{cMessage}}</h2>
<ul>
<li v-for="item in cList">{{item}}</li>
</ul>
</div>
</template>
<script>
const npc = {
template: ‘#npc‘,
props: {
cMessage: String,
cList: {
type: Array,
default() {
return []
},
requied: true,
},
},
}
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘鬼泣5‘,
list: [‘小红‘, ‘小明‘, ‘小新‘, ‘小白‘],
},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
npc,
},
})
</script>
</body>
</html>
案例:手机京东
如何让父组件知道子组件选择的是什么分类,然后由父组件来发送信息
子组件通过事件传输数据到父组件中?
子组件通过子定义事件,然后父组件通过v-on
来监听事件,完成子穿父的通信
什么时候需要自定义事件呢
当子组件需要向父组件传输数据,就需要用到自定义事件了
我们之前学习过的v-on不仅可以用于监听DOM的默认事件,还可以监听组件的自定义事件
自定义事件流程
$emit()
来触发时间v-on
来监听子组件发出的事件代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>父子组件通信-子组件给父组件通信-通过自定义事件来完成</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<npc @item-click="btClick"></npc>
<!-- 这里监听事件,由于是自定义事件,Vue会自动传输事件 -->
</div>
<template id="npc">
<div>
<button type="button" v-for="item in categorys" @click="cpnClick(item)">
{{item.name}}
</button>
</div>
</template>
<script>
const npc = {
template: ‘#npc‘,
data() {
return {
categorys: [
{ id: ‘aaa‘, name: ‘热门推荐‘ },
{ id: ‘bbb‘, name: ‘电脑办公‘ },
{ id: ‘ccc‘, name: ‘家用家电‘ },
{ id: ‘ddd‘, name: ‘手机数码‘ },
],
}
},
methods: {
cpnClick(item) {
// 发射事件给父组件
// this.$emit("自定义事件名", 要传输的参数)
this.$emit(‘item-click‘, item)
},
},
}
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {
btClick(item) {
console.log(item)
},
},
// 计算属性
computed: {},
// 组件注册
components: {
npc,
},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>子组件发出事件修改父组件的值</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<h2>{{count}}的值</h2>
<cpn @sub-click="count--" @add-click="count++"></cpn>
</div>
<template id="cpn">
<div>
<button type="button" @click="subClick">-</button>
<button type="button" @click="addClick">+</button>
</div>
</template>
<script>
const cpn = {
template: ‘#cpn‘,
methods: {
subClick() {
this.$emit(‘sub-click‘)
},
addClick() {
this.$emit(‘add-click‘)
},
},
}
var app = new Vue({
el: ‘#app‘,
data: {
count: 0,
},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
cpn,
},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>13-案例-父子组件中双向绑定案例.html</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
不难,关系搞清楚就行,
如果直接使用v-model绑定的话,会报错误Vue,意思就是说你修该props中的属性没啥意义,
因为即使你修该的,它还是根据父组件中传输过来再修该的,
所以,想要完成父组件的修改,
根据v-model原理来完成 先来:value绑定data中数据,然后根据事件来修改data中数据并发送事件
到父组件,父组件监听然后再修改
-->
<div id="app">
<h1>{{um1}}</h1>
<br />
<h1>{{um2}}</h1>
<npc
:num1="um1"
:num2="um2"
@num1-input="updateUm1"
@num2-input="updateUm2"
></npc>
</div>
<template id="npc">
<div>
<h3>{{num1}}</h3>
<h3>data{{dnum1}}</h3>
<!-- 如果还想修该父组件的值 那么就写事件 v-model根据原理分开来写 写事件-->
<!-- <input type="text" name="" id="" v-model="num1" /> 不推荐这么玩
因为: 如果直接使用v-model绑定的话,会报错误Vue,意思就是说你修该props中的属性没啥意义,
因为即使你修该的,它还是根据父组件中传输过来再修该的,-->
<input type="text" name="" id="" :value="dnum1" @input="num1Input" />
<br />
<h3>{{num2}}</h3>
<h3>data{{dnum2}}</h3>
<input type="text" name="" id="" :value="dnum2" @input="num2Input" />
</div>
</template>
<script>
const npc = {
template: ‘#npc‘,
props: {
num1: {
type: Number,
},
num2: Number,
},
data() {
return {
dnum1: this.num1,
dnum2: this.num2,
}
},
methods: {
num1Input(event) {
this.dnum1 = event.target.value
this.$emit(‘num1-input‘, parseInt(this.dnum1))
},
num2Input(event) {
this.dnum2 = event.target.value
this.$emit(‘num2-input‘, parseInt(this.dnum2))
},
},
}
var app = new Vue({
el: ‘#app‘,
data: {
um1: 0,
um2: 0,
},
methods: {
updateUm1(num1) {
this.um1 = num1
},
updateUm2(num2) {
this.um2 = num2
},
},
// 计算属性
computed: {},
// 组件注册
components: {
npc,
},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>14-案例-父子组件中双向绑定案例(watch实现)</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
不难,关系搞清楚就行,
如果直接使用v-model绑定的话,会报错误Vue,意思就是说你修该props中的属性没啥意义
,因为即使你修该的,它还是根据父组件中传输过来再修该的,
所以,想要完成父组件的修改,
根据v-model原理来完成 先来:value绑定data中数据,然后根据事件来修改data中数据
并发送事件到父组件,父组件监听然后再修改
-->
<div id="app">
<h1>{{um1}}</h1>
<br />
<h1>{{um2}}</h1>
<npc
:num1="um1"
:num2="um2"
@num1-input="updateUm1"
@num2-input="updateUm2"
></npc>
</div>
<template id="npc">
<div>
<h3>{{num1}}</h3>
<h3>data{{dnum1}}</h3>
<input type="text" name="" id="" v-model="dnum1" />
<br />
<h3>{{num2}}</h3>
<h3>data{{dnum2}}</h3>
<input type="text" name="" id="" v-model="dnum2" />
</div>
</template>
<script>
const npc = {
template: ‘#npc‘,
props: {
num1: {
type: Number,
},
num2: Number,
},
data() {
return {
dnum1: this.num1,
dnum2: this.num2,
}
},
// 值发生改变自动触发
watch: {
dnum1(newDnum1) {
this.dnum1 = newDnum1
this.$emit(‘num1-input‘, parseInt(this.dnum1))
},
dnum2(newDnum2) {
this.dnum2 = newDnum2
this.$emit(‘num2-input‘, parseInt(this.dnum2))
},
},
}
var app = new Vue({
el: ‘#app‘,
data: {
um1: 0,
um2: 0,
},
methods: {
updateUm1(num1) {
this.um1 = num1
},
updateUm2(num2) {
this.um2 = num2
},
},
// 计算属性
computed: {},
// 组件注册
components: {
npc,
},
})
</script>
</body>
</html>
父组件直接操作子组件(拿到子组件引用)
this.$children
获取到的是一个数组,包含着该实例下的所有子组件[不推荐使用]this.$refs
通过给子组件设置ref
属性(相当于子组件的key
),然后通过this.$refs.key
拿到对应的子组件子组件直接操作父组件(拿到父组件的引用)
this.$parent
拿到父组件this.$root
直接拿到祖宗组件直接操作子组件,相当于指针来操作子组件
获取子组件两种方式:
children
不推荐 获取到的是组件的数组, 因为在开发中,可能突然往组件之间插入一个,那么他们下标就会改变 所以不贵贱ref
属性 然后通过this.$refs.子组件的ref属性(key)
来访问指定的子组件代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>15-组件访问方式-父组件操作子组件中的数据(方式一:children)</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
<button @click="btnClick">获取子组件</button>
</div>
<template id="cpn">
<div>
<h2>name: {{name}}</h2>
</div>
</template>
<script>
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {
btnClick() {
console.log(this.$children) // 获取的是子组件的数据,因为子组件可能存在多个
// 开始直接操作子组件,
// 调用方法
this.$children[0].showMessage()
console.log(this.$children[0].name)
},
},
// 计算属性
computed: {},
// 组件注册
components: {
cpn: {
template: ‘#cpn‘,
methods: {
showMessage() {
console.log(‘我是子组件‘)
},
},
data() {
return {
name: ‘why ?‘,
}
},
},
},
// 属性修改自动触发
watch: {},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>16-组件访问方式-父组件操作子组件中的数据(方式二:refs)</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn ref="aaa"></cpn>
<button @click="btnClick">获取子组件</button>
</div>
<template id="cpn">
<div>
<h2>name: {{name}}</h2>
</div>
</template>
<script>
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {
btnClick() {
// console.log(this.$children) // 获取的是子组件的数据,因为子组件可能存在多个
// 开始直接操作子组件,
// 调用方法
// this.$children[0].showMessage()
// console.log(this.$children[0].name)
this.$refs.aaa.showMessage()
console.log(this.$refs.aaa.name)
},
},
// 计算属性
computed: {},
// 组件注册
components: {
cpn: {
template: ‘#cpn‘,
methods: {
showMessage() {
console.log(‘我是子组件‘)
},
},
data() {
return {
name: ‘why ?‘,
}
},
},
},
// 属性修改自动触发
watch: {},
})
</script>
</body>
</html>
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>
17-组件访问方式-子访问父组件中的数据(parent,root)操作父组件
</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>root的子组件小红</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>小红的子组件</h2>
<button @click="btnClick">访问父组件</button>
</div>
</template>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
message: ‘我是Vue的示例‘,
},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
cpn: {
template: ‘#cpn‘,
data() {
return {
message: ‘我是小红‘,
}
},
components: {
ccpn: {
template: ‘#ccpn‘,
methods: {
btnClick() {
console.log(‘父组件‘, this.$parent) // 访问父组件,也就是小红
console.log(‘父组件的属性‘, this.$parent.message)
console.log(‘祖宗root组件‘, this.$root) // 访问祖宗 也就是Vue的示例
console.log(‘祖宗root组件的属性‘, this.$root.message) // 访问祖宗 也就是Vue的示例
},
},
},
},
},
},
// 属性修改自动触发
watch: {},
})
</script>
</body>
</html>
slot
插槽:
就相当于是一个接口,用于扩展自定义的东西,就像电脑的USB一样,可以插手机、U盘。
Vue
Vue的插槽定义:就是在组件中留一个<slot></slot>
标签
插槽作用
父组件提供标签,但是内容由子组件来提供
插槽使用步骤-slot
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>slot插槽的基本使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
插槽的基本使用
插槽:就相当于是一个接口,用于扩展自定义的东西,就像电脑的USB一样,可以插手机、U盘。
Vue 的插槽定义:就是在组件中留一个<slot></slot>标签
插槽作用:
父组件提供标签,但是内容由子组件来提供
1. 在使用组件直接插入,就相当于使用了插槽
2. 可以插入很多标签
3. 插槽可以有默认值
-->
<div id="app">
<cpn><button>按钮</button></cpn>
<hr />
<cpn><span>我是span</span></cpn>
<hr />
<cpn><i>哈哈</i></cpn>
<hr />
<cpn>
<h1>h1</h1>
<b>b</b>
</cpn>
<hr />
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是标题</h2>
<p>我是段落</p>
<slot><button>按钮</button></slot>
</div>
</template>
<script>
const cpn = {
template: ‘#cpn‘,
}
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
cpn,
},
// 属性修改自动触发
watch: {},
})
</script>
</body>
</html>
具名插槽的使用:就是给插槽起个名字,再使用的时候告诉组件我们要使用哪个插槽
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>具名插槽的使用</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
具名插槽的使用:就是给插槽起个名字,再使用的时候告诉组件我们要使用哪个插槽
1. 如果有三个插槽都没有名字,那么在使用的时候就会全部替换
2. 如果插槽都有名字,那么你替换没有指定名字,那么就会替换没有名字的插槽
3. 指定名称替换插槽
-->
<div id="app">
<cpn>
<!-- 指定名称 告诉VUe我要替换中间的那个插槽-->
<h2 slot="center">标题2</h2>
<!-- 会自动提换没有名字的插槽 -->
<strong>粗体</strong>
</cpn>
</div>
<template id="cpn">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<script>
const cpn = {
template: ‘#cpn‘,
}
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
cpn,
},
// 属性修改自动触发
watch: {},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>变量作用域</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 看Vue实例中的isShow变量-->
<cpn v-show="isShow"></cpn>
</div>
<!-- 为什么呢?
官网一句话:父组件模板的所有东西都会在父级作用域内编译,子组件模板所有东西都会在子组件作用域编译
-->
<template id="cpn">
<div>
<h2>我是子组件</h2>
<!-- 看组件的isShow变量-->
<button v-show="isShow">按钮</button>
</div>
</template>
<script>
var app = new Vue({
el: ‘#app‘,
data: {
isShow: true,
},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
cpn: {
template: ‘#cpn‘,
data() {
return {
isShow: false,
}
},
},
},
// 属性修改自动触发
watch: {},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>作用域插槽的案例-父组件拿到子组件数据来展示</title>
<script src="../js/vue.js"></script>
</head>
<!--
插槽作用:
父组件提供标签,但是内容由子组件来提供
需求:
不想按照子组件的方式去展示数据,父组件中替换展示方式,、
那么第一点就是拿到子组件的数据,该如何拿到???
-->
<body>
<div id="app">
<cpn></cpn>
<!-- 换一种展示方式 -->
<cpn>
<template slot-scope="slot" slot="aaa">
<span>{{slot.abc.join(" - ")}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot :abc="dataList" name="aaa">
<ul>
<li v-for="item in dataList">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script>
const cpn = {
template: ‘#cpn‘,
data() {
return {
dataList: [‘java‘, ‘C‘, ‘C++‘, ‘Go‘, ‘javaScript‘, ‘Python‘],
}
},
}
var app = new Vue({
el: ‘#app‘,
data: {},
methods: {},
// 计算属性
computed: {},
// 组件注册
components: {
cpn,
},
// 属性修改自动触发
watch: {},
})
</script>
</body>
</html>
导出
导出:export 变量/函数/类/数组
可以多个,中间逗号分隔
还可以exprot default 变量/函数/类/数组
不过一个js
文件里只能这么写一次
导入
import 变量/函数/类/数组 from 路径
不过有限制,只能导出是什么名导入是什么名
还可以全部导入import * as 类名 from 路径
这种方式是把导出的全部都封装成类
有两个人写js
代码小明,小红
h5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 必须带type="module" 这才是ES6的模块开发 -->
<script src="xiaoming.js" type="module"></script>
<script src="xiaohong.js" type="module"></script>
</body>
</html>
小明代码
// 小明在开发
var name = ‘小明‘
var age = 18
let sex = ‘男‘
var flag = true
function sum(num1, num2) {
return num1 + num2
}
// 导出
export { name, age, sex, sum }
// 定义时到处
export let list = [‘Java‘, ‘C#‘]
// 定时时到处类/函数
export function add() {
}
// 上面的几种到处方式,在导入的时候,变量名或方法名都必须和到处的一致,才行
// 带上default 关键字 就可以在导入的时候自定义名 有一个export default这样的导出
export default function (num1, num2) {
return num1 - num2
}
小红代码
// 小红在开发
// 导入
import { age, sex,sum } from ‘./xiaoming.js‘
var name = ‘小红‘
console.log(name)
console.log(age);
console.log(sum(10 ,20))
import {list} from "./xiaoming.js";
console.log(list)
import a from "./xiaoming.js";
console.log(a(10 ,1))
// 导入所有,自动封装成为类 并重命名关键字
import * as aaa from ‘./xiaoming.js‘
console.log(aaa)
安装
npm install webpack -g
-g 表示全局安装
本地安装 npm install webpack@3.6.0 --save-dev 开发环境
验证是否安装成功
webpack --version
webpack打包过程
一定要安装webpack@3.6.0
npm install webpack@版本 -g
安装目录 | 作用 |
---|---|
src | 开发的js/style/img |
dist | 打包好的js文件 |
创建webpack.config.js
const path = require("path")
module.exports = {
// 入口,
entry: "./src/main.js",
// 出口,生成位置
output: {
path: path.resolve(__dirname, "dist"), // 1. 这里一定要动态的获取绝对路径, __driname得到的是当前文件的路径
filename: "bundle.js"
}
}
是因为每次打包都是webpack ./src/main.js ./dist/bundle.js
命令太长,繁琐,所以创建步骤4这个文件,来指定出口入口
但是因为出口:要的是绝对路径,那么就只能通过node来动态获取绝对路径。所以
npm init
初始化node。初始化之后就会有一个package.json
文件。作用相当于Maven差不多,这个时候如果有依赖的话,可以npm install
安装依赖
安装好之后,在script
标签,写上命令build
指定下即可
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.6.0"
}
}
以后执行直接npm run build
来打包
但是这个时候使用的是全局的webpack,要安装局部的npm install webpack@3.6.0 --save-dev
webpack只是起到打包作用,问题是前端有各种文件,那么针对不同文件的打包处理需要不同的方式,这个概念就是loader
loader的安装具体可看
https://www.webpackjs.com/loaders/
css-loader
style-loader
分别配置
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [ ‘style-loader‘, ‘css-loader‘ ]
}
]
}
}
注意事项
css-loader
只是导入css
代码,并不会应用style-loader
应用css
到DOM
loader
时,是从从右向左读取,所以才会是先是使用样式 再导入css
代码了url-loader
file-loader
注意事项
webpack
通过main.js
找到了img
的依赖url-loader
会有一设置limit: 8192,
大小的设置,如果超过8k
就会使用file-loadre
打包图片。file-loader
img/原图片名称+hash值+原来的后缀
, 语法是img[name].[hash].[ext]
配置
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: ‘url-loader‘,
options: {
limit: 8192,
name: "img/[name].[hash].[ext]"
}
}
]
},
]
}
}
一定要指定版本安装不然会出错
npm install --save-dev less-loader@4.1.0 less
想知道的看:https://blog.csdn.net/shujiaw/article/details/105863069
安装:
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: ‘babel-loader‘,
options: {
presets: [‘es2015‘]
}
}
}
]
}
webpack
配置vue
前提
Vue
有两个版本
runtime-only
版本:代码中不可以有任何template
runtime-compiler
版本:代码可有,因为用于编译template
的
webpack
使用Vue
步骤
安装Vue
,因为是不管任何环境都用所以
npm install vue --save
在webpack.config.js
中配置
module.exports = {
// ...
resolve: {
alias: {
‘vue$‘: ‘vue/dist/vue.esm.js‘ // 用 webpack 1 时需用 ‘vue/dist/vue.common.js‘
}
}
}
详细看这里
https://cn.vuejs.org/v2/guide/installation.html#webpack
如果不配置,报错的信息
bundle.js:1451 [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
(found in <Root>)
当完成3.2.5的时候,以后在webpack
开发Vue
的方式是,在html
中只新建<div> id="app"</div>
即可。
在.js
文件里
// 导入Vue
import Vue from ‘vue‘
new Vue({
el: "#app",
template: `
<div>
<h2>{{message}}</h2>
<button @click="btnClick">按钮</button>
</div>
`,
data: {
message: "你好么 webpack"
},
methods: {
btnClick () {
console.log("按钮被单击了");
}
}
})
当Vue
实例里面有el
和template
的时候template
里的东西会把el
的东西替换掉
这么写即可,Vue会把template
中内容替换到html
中<div id="app">
里去
因为要解析
vue
文件所以需要vue
的loader
vue-loader
vue-template-compiler
npm install vue-loader vue-template-compiler --save-dev
修改webpack.config.js
配置
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
publicPath: "dist/" // 图片需要的
},
module: {
rules: [
{
test: /\.vue$/,
use: [‘vue-loader‘]
}
]
},
}
main.js
原版
new Vue({
el: "#app",
template: `<AppAndVue/>`,
components: {
Cpn: {
template: `<div>
<h2>{{message}}</h2>
<button @click="btnClick">按钮</button>
</div>`,
data () {
return {
message: "你好么 webpack"
}
},
methods: {
btnClick () {
console.log("按钮被单击了");
}
}
}
})
抽取后
// 1. 抽取第一步 当前文件抽取
const Cpn = {
template: `<div>
<h2>{{message}}</h2>
<button @click="btnClick">按钮</button>
</div>`,
data () {
return {
message: "你好么 webpack"
}
},
methods: {
btnClick () {
console.log("按钮被单击了");
}
}
}
new Vue({
el: "#app",
template: `<AppAndVue/>`,
components: {
Cpn,// 本文件抽取,没有脱离
}
})
export default {
template: `<div>
<h2>{{message}}</h2>
<button @click="btnClick">按钮</button>
</div>`,
data () {
return {
message: ".js文件外部抽取"
}
},
methods: {
btnClick () {
console.log("按钮被单击了");
}
}
}
main.js中导入
// 抽取方式二:抽取为Cpn.js
import App from ‘./js/Cpn.js‘;
new Vue({
el: "#app",
template: `<AppAndVue/>`,
App, // 已抽取,但是是js文件,只能以ES6默认导出 再导入
}
})
AppAndVue.vue
// 定义模板
<template>
<div>
<h2 class=".tile">{{ message }}</h2>
<button @click="tnbClick">按钮</button>
</div>
</template>
// 定义代码
<script>
export default {
name: ‘AppAndVue‘,
data() {
return {
message: ‘Vue方式抽取‘,
}
},
methods: {
tnbClick() {
console.log(‘Vue方式按钮抽取‘)
},
},
}
</script>
// 编写样式
<style>
.tile {
color: gold;
}
</style>
main.js
// 抽取方式三:抽取为vue文件
import AppAndVue from ‘./vue/AppAndVue.vue‘
new Vue({
el: "#app",
template: `<AppAndVue/>`,
components: {
// Cpn, 本文件抽取,没有脱离
// App, // 已抽取,但是是js文件,只能以ES6默认导出 再导入
AppAndVue,
}
})
由于是webpack
自带插件,不需要安装。直接使用
在webpack.config.js
中
const webpack = require("webpack")
module.exports = {
lugins: [
new webpack.BannerPlugin("最终版权归测试所有")
]
}
安装插件npm install html-webpack-plugin@3.2.0 -save-dev
配置webpack.config.js
内容
const hmtlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
// publicPath: "dist/" 这里不要,因为插件会自动引用生成的js文件的
},
plugins: [
new hmtlWebpackPlugin({
template: "index.html",
}) // 这个意思是根据src下的index.html作为模板生成
]
}
安装npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
webpack.config.js
配置
const UglifyjsWebpackPlugin = require("uglifyjs-webpack-plugin")
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
plugins: [
new UglifyjsWebpackPlugin(),
]
}
webpack
提供了一个可选的本地开发服务器,这个本地服务器基于node.js
搭建,内部使用express
框架,可以实现我们想要的让浏览器自动刷新显示我们修改的结果
安装npm install --save-dev webpack-dev-server@2.9.1
配置webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
devServer: {
contentBase: "./dist",
inline: true
}
}
参数作用
参数 | 作用 |
---|---|
contentBase |
为哪一个文件夹提供本地服务,默认是根文件夹,我们这里写./dist |
port | 端口号 |
inline |
页面实时刷新 |
historyApiFallback |
在SPA页面中,依赖HTML5的history模式 |
另外还可以在package.js
中加上参数,默认自动打开浏览器
--open
参数表示直接打开浏览器"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"bundle": "webpack",
"dev": "webpack-dev-server --open"
},
概念
就是开发一个配置文件,发布一个配置文件。两个配置文件都一样的,分开写的话不乱
步骤
npm install webpack-merge -save-dev
build
base.config.js
dev.config.js
prod.config.js
具体配置文件代码
base.config.js
const path = require("path")
const webpack = require("webpack")
const hmtlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "../dist"), // 上级目录
filename: "bundle.js",
},
module: {
rules: [
{
test: /\.css$/,
use: [‘style-loader‘, ‘css-loader‘]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: ‘url-loader‘,
options: {
limit: 8192,
name: "img/[name].[hash].[ext]"
}
}
]
},
{
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: /\.vue$/,
use: [‘vue-loader‘]
},
]
},
resolve: {
alias: {
"vue$": "vue/dist/vue.esm.js"
}
},
plugins: [
new webpack.BannerPlugin("最终版权归测试所有"),
new hmtlWebpackPlugin({
template: "index.html",
}),
],
}
dev.config.js
const webpackMerge = require("webpack-merge")
const baseConfig = require("./base.config.js")
module.exports = (baseConfig, {
devServer: {
contentBase: "./dist",
inline: true
}
})
prod.config.js
const UglifyjsWebpackPlugin = require("uglifyjs-webpack-plugin")
const webpackMerge = require("webpack-merge")
const baseConfig = require("./base.config")
module.exports = webpackMerge(baseConfig, {
plugins: [
new UglifyjsWebpackPlugin(),
],
})
package.json
配置文件,指定配置文件地址"scripts": {
"bundle": "webpack --config ./build/prod.config.js",
"dev": "webpack-dev-server --open --config ./build/dev.config.js"
},
前提
电脑上有装node.js8.9
或者更高的版本
安装Vue Cli
npm install -g @vue/cli
如果出现问题
npm 装东西出现错误那就去把该路径下的目录删除掉C:\Users\HiWin10\AppData\Roaming
下npm-cache
目录删除,重新安装
自定义创建项目,每个插件的作用
在cmd
窗口输入vue ui
,自动打开本地服务器,根据提示创建即可
1. vue create 项目名
2. 选择自定义创建,还是默认创建
在创建后的项目中,package.json
查看已经添加的插件或依赖
根据提示,添加依赖后添加插件
区别
runtime-compiler
编译过程:temlate
->ast
->render
->vdom
->UI
runtime-only
推荐使用,性能高,代码量更少
编译过程:render
->vdom
->UI
阶段1:后端渲染
典型代表技术:Java的Servlet和JSP
阶段2:前端渲染
代表技术:ajax异步请求
1个页面一组html+css+js
,可以让专门一个服务器提供这些静态数据。
另一个服务器提供API接口
阶段3:前端路由和SPA
SPA页面:就是单页面富应用,整个网站都是使用同一个html页面。
一个页面,通过不同的URL,来显示不同的内容,比如点这个我让这个组件显示,点那个我让那个组件显示,数据的话是通过ajax
服务器动态该来获取
前面已经知道,现在基本都是SPA应用,那么我们需要了解的就是,如何改变URL,但是页面不刷新
在浏览器的交互里输入
location.hash = "xxx"
// 更改路径
history.pushState({}, "", "url")
// 后退
history.back()
// 直接根据pushState入栈的路径可以跳转
histoyr.go() 如果是负数后退,整数前进
概述
router
目录下的index.js
中注册Vue-Router
的插件和路径映射关系App.js
中导入注册Vue-Router
,并使用<router-link to="/home"></router-link>、<router-view></router-view>
,两个标签安装
在vue
的界面里安装,先导入依赖,然后在插件页面,安装插件即可
使用
安装好之后会在src
目录下多一个router
目录,该目录下有一个index.js
文件,该文件记录有Vue-Router
的注册和使用
- 编写自己的Vue组件
<template>
<div>
<h2>我是主页</h2>
<p>哈哈哈哈,我是主页</p>
</div>
</template>
<script>
export default {
name: "Home"
}
</script>
<style>
</style>
- 导入写好的Vue组件
// 1. 配置路由相关信息 导入路由
import VueRouter from "vue-router"
import Vue from ‘vue‘
import Home from ‘../components/Home‘
import About from ‘../components/About‘
// 2. 通过Vue.use(),安装要使用的插件
Vue.use(VueRouter)
// 3. 创建VueRouter对象
// 3.1 路由和组件的映射关系
const routes = [
{
// 用于打开的时候就首页就显示/home的东西
path: "", // 默认,缺省
redirect: "/home",
},
{
// 路径
path: "/home",
// 组件
component: Home,
},
{
path: "/about",
component: About
}
]
const router = new VueRouter({
// 配置路由和组件的映射关系
routes,
// mode默认是hash值切换, 可以换成history
mode: "history"
})
// 4. 将VUeRouter出入到Vue实例中
export default router
- Vue-Router使用
- APP.js修改
<router-link to="/home">
标签,有按钮才行,
to
属性是路径<router-view></router-view>
添加这个标签,作用:自定义组件会显示在这里<template>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-view></router-view>
</div>
</template>
<style>
</style>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({});
</script>
最后一步
应该根路径,用于打开网页的时候,主页显示主页的东西,重定向redirect
import VueRouter from "vue-router"
import Vue from ‘vue‘
import Home from ‘../components/Home‘
import About from ‘../components/About‘
Vue.use(VueRouter)
const routes = [
{
// 用于打开的时候就首页就显示/home的东西
path: "", // 默认,缺省
redirect: "/home",
},
{
path: "/home",
component: Home,
},
{
path: "/about",
component: About
}
]
const router = new VueRouter({
routes,
mode: "history"
})
export default router
提示
在mode
属性是url的修改方式history
或hash
<router-link>
的补充参数
tag
表示指定<router-link>
之后要渲染成什么组件,比如默认是<a>
,可以修改成button
replace
:preplace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中active-class
:当<router-link>
对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称.
修改linkActiveClass
该class
具体的名称也可以通过router实例的属性进行修改
当用随意的标签替代<router-link>
后,其他的标签,要写一个单击事件,然后不跳转的情况下,修改url
代码示例
<template>
<div id="app">
<!-- <router-link to="/home" tag="button" replace>首页</router-link>
<router-link to="/about" tag="button">关于</router-link> -->
<!-- 代码跳转 -->
<button @click="btnClick">首页</button>
<button @click="btnClick2">关于</button>
<router-view></router-view>
</div>
</template>
<style>
</style>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
methods: {
btnClick() {
this.$router.push("/home");
// this.$router.replace("/hemo")
},
btnClick2() {
this.$router.push("/about");
}
}
});
</script>
某些情况下,一个网站的path
是不固定的,比如
/user/aaa
/user/zhangsan
这种方式叫做动态路由,如何使用呢?
:变量名
this.$route.params.变量名
取出即可代码示例
index.js 配置
:变量名
// 1. 配置路由相关信息 导入路由
import VueRouter from "vue-router"
import Vue from ‘vue‘
// 这种方式不是懒加载
// import Home from ‘../components/Home‘
// import About from ‘../components/About‘
// import User from ‘../components/User‘
// 懒加载
const User = () => import("../components/User")
Vue.use(VueRouter)
const routes = [
{
path: "/user/:id",
component: User,
meta: {
title: "用户"
}
},
]
// 4. 将VUeRouter出入到Vue实例中
export default router
User.vue
<template>
<div>
<h2>我是用户标题</h2>
<p>Hahahahha</p>
{{userId}}
<hr>
{{getid}}
</div>
</template>
<script>
export default {
name: "User",
computed: {
userId: function () {
return this.$route.params.id
},
getid () {
return this.$route.params.id
}
}
}
</script>
<style>
</style>
概述
.js
文件:
vue
按照上面这种情况下,如果我们的项目很大,js
代码都写一个文件里,那么这个js文件就会非常大,加载时间如果过长的话,页面就会出现空白,这对用户是不友好的体验
懒加载实现方式
在ES6中, 我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割
// 懒加载
const Home = () => import("../components/Home")
const HomeNews = () => import("../components/HomeNews")
const HoemMessage = () => import("../components/HomeMessage")
什么是嵌套路由
/home/news
和/home/message
访问一些内容实现嵌套路由有两个步骤:
<router-view>
标签代码示例
定义新的组件HemoNews
在home
路径下,添加children
属性来注册路由
在Hemo
中使用<router-link>
和<router-view>
标签
<template>
<div>
<h2>我只嵌套组件-HomeNews</h2>
<ul>
<li>新闻1</li>
<li>新闻2</li>
<li>新闻3</li>
<li>新闻4</li>
</ul>
</div>
</template>
<script>
export default {
name: "HomeNews",
}
</script>
<style>
</style>
const routes = [
{
// 用于打开的时候就首页就显示/home的东西
path: "", // 默认,缺省
redirect: "/home",
},
{
// 路径
path: "/home",
meta: {
title: "首页"
},
// 组件
component: Home,
children: [
// {
// path: "",
// redirect: ‘news‘
// },
{
path: "news",
component: HomeNews
},
{
path: "message",
component: HoemMessage
}
]
},
]
<template>
<div>
<h2>我是主页</h2>
<p>哈哈哈哈,我是主页</p>
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">娱乐</router-link>
<router-view></router-view>
</div>
</template>
:变量名
this.$route.params.变量名
const routes = [ {
path: "/user/:id",
component: User,
meta: {
title: "用户"
}
},
]
<template>
<div>
<h2>我是用户标题</h2>
<p>Hahahahha</p>
{{userId}}
<hr>
{{getid}}
</div>
</template>
<script>
export default {
name: "User",
computed: {
userId: function () {
return this.$route.params.id
},
getid () {
return this.$route.params.id
}
}
}
</script>
<router-link :to="{path: ‘/profile‘, query: {name:‘小红‘, age: 18, heigh: 1.78}}">档案</router-link>
对应的组件上
<template>
<div>
<h2>参数传递</h2>
<h3>{{$route.query.name}}</h3>
<h3>{{$route.query.age}}</h3>
<h3>{{$route.query.heigh}}</h3>
</div>
</template>
<script>
export default {
name: "Profile"
}
</script>
<style>
</style>
<template>
<div id="app">
<!-- <router-link to="/home" tag="button" replace>首页</router-link>
<router-link to="/about" tag="button">关于</router-link>
代码跳转
<button @click="btnClick">首页</button>
<button @click="btnClick2">关于</button> -->
<router-link to="/home" tag="button">首页</router-link>
<router-link to="/about" tag="button">关于</router-link>
<!-- <router-link :to="{path: ‘/profile‘, query: {name:‘小红‘, age: 18, heigh: 1.78}}">档案</router-link>
<router-link :to="‘/user/‘ + userId">用户</router-link> -->
<!-- 换一种方式实现 -->
<button @click="userClick">用户</button>
<button @click="proClick">档案</button>
<!-- keep-alive作用就是防止组件的销毁和创建 这个标签对应着`activated`/`deactivated` 判断当前状态是否处于活跃 -->
<keep-alive>
<router-view />
</keep-alive>
</div>
</template>
<style>
</style>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
methods: {
btnClick() {
this.$router.push("/home");
// this.$router.replace("/hemo")
},
btnClick2() {
this.$router.push("/about");
},
userClick() {
this.$router.push("/user/" + this.userId);
},
proClick() {
this.$router.push({
path: "/profile",
query: {
name: "夏红",
age: 18,
heigh: 18.9
}
});
}
},
data() {
return {
userId: "zhangsan"
};
}
});
</script>
<style scoped>
.router-link-active {
color: red;
}
</style>
$router
为VueRouter
实例,想要导航到不同URL,则使用$router.push
方法$route
为当前router
跳转对象里面可以获取name
、path
、query
、params
等什么是导航守卫?
vue-router
提供的导航守卫主要是用来监听路由的进入和离开的。
pvue-router
提供了beforeEach
和afterEach
的钩子函数, 它们会在路由即将改变前和改变后触发
beforeEach
:改变前
afterEach
:改变后
导航守卫的实际应用
案例:我们来考虑一个需求: 在一个SPA应用中, 如何改变网页的标题呢?
<title>
来显示的, 但是SPA只有一个固定的HTML, 切换不同的页面时, 标题并不会改变JavaScript
来修改<title>
的内容window.document.title = ‘新的标题‘
普通的解决方案:
mounted
生命周期函数, 执行对应的代码进行修改即可导航守卫的解决办法
使用beforeEach
来完成标题的修改
首先给每个路由映射定义标题
const routes = [
{
path: "/about",
component: About,
meta: {
title: "关于"
}
},
]
利用导航守卫完成修改
router.beforeEach((to, from, next) => {
// 从 from 跳到 to
//console.log(to);
document.title = to.matched[0].meta.title;
next() // 必须调用,不调用的话,就不会往下走:不会触发组件
})
beforeEach
参数的说明:
具体学习看:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#路由独享的守卫
什么是
kepp-alive
keep-alive
是Vue
内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
组件的声明周期
在vue-router
中组件都是根据路由的点击,来创建和删除,访问一个path
的时候,这个组件就会创建,再点击其他path
的时候,当前的组件就会删除,这样的话非常浪费资源。而keep-alive
就是为了解决这么个问题。
当然通过create
和destroyed
分别是Vue对象的构建和析构执行的回调,可以验证组件的创建与销毁
keep-alive
带来的事件
名称 | 作用 |
---|---|
activated | 当前组件活跃 |
deactivaed | 当前组件不活跃 |
只有使用keep-alive
才可以使用
使用方式
<!--
keep-alive作用就是防止组件的销毁和创建
这个标签对应着`activated`/`deactivated` 判断当前状态 是否处于活跃
-->
<keep-alive>
<router-view />
</keep-alive>
keep-valive
重要的属性
include
- 字符串或正则表达,只有匹配的组件会被缓存
exclude
- 字符串或正则表达式,任何匹配的组件都不会被缓存
字符串都是组件的name
属性
比如:exclude="Profile,User"
Vuex
是一个专为Vue.js
应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex
也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
状态管理到底是什么
状态管理模式、集中式存储管理这些名词听起来就非常高大上,让人捉摸不透
实际开发中,我们一般使用状态管理技术,都用于什么场景呢?
state
好比Vue的data数据,state
的数据显示在view中,然后view上触发了某些行为(actions)
,而行为修改了state
多页面的缺陷
多页面管理如果还是用上面单页面的流程图那样的话,那肯定是不合适的比如:
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
Vuex的流程图
流程:
state
:共享状态的数据
Vue Components
:有用到共享数据的组件
Actions
:网络异步请求,必须要经过Actions
,才可以被devtools
记录到
Mutations
:网络请求到之后,通过此属性的方法来完成对state
的修改
Devtools
:是记录着之间发生什么事情的工具,前提是你所完成的操作必须按照图中流程一步一步走,如果有跳过的那么Devtools
就记录不到了。
案例说明
两个组件使用Vuex共享的数据,我想通过一个组件的Click
事件来完成,共享值的修改,然后把新的值立刻在两个组件中显示出来
开发规范,Vuex的存放位置
store
文件夹,用来存放index.js
sotre
目录下编写两个组件
组件1
<template>
<div id="app">
<h2>---App---</h2>
<h5>{{ $store.state.count }}</h5>
<button type="button" @click="addCount">+</button>
<button type="button" @click="addTemp">+5</button>
<button type="button" @click="subCount">-</button>
<HelloVuex></HelloVuex>
</div>
</template>
<script>
import HelloVuex from ‘./components/HelloVuex‘
export default {
name: ‘App‘,
components: {
HelloVuex,
},
methods: {
addCount() {
this.$store.commit(‘increase‘)
},
subCount() {
this.$store.commit(‘reduction‘)
},
addTemp() {
const temp = 5
// 第二种mutations提交方式
this.$store.commit({
type: ‘addTemp‘,
temp,
})
},
},
}
</script>
<style></style>
组件2
<template>
<div>
<hr />
<h2>---HelloVuex---</h2>
<h5>{{ $store.state.count }}</h5>
</div>
</template>
<script>
export default {
name: ‘HelloVUex‘,
}
</script>
<style></style>
Vuex-index.js代码
import Vue from ‘vue‘
import Vuex from ‘vuex‘
Vue.use(Vuex)
const store = new Vuex.Store({
// 保存状态
state: {
count: 0,
},
actions: {},
mutations: {
// increase 事件类型 (){}是回调函数
increase () {
this.state.count++
},
reduction (state) {
this.state.count--
},
// 第二种提交方式
addTemp (state, payload) {
console.log(payload);
state.count += payload.temp
},
},
getters: {},
modules: {}
}
挂载Vue实例中
import Vue from ‘vue‘
import App from ‘./App.vue‘
import store from ‘./store‘
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store,
}).$mount(‘#app‘)
获取State
数据
获取年龄大于18的信息
const store = new Vuex.Store({
// 保存状态
state: {
count: 0,
students: [
{ id: 1, name: "小红", age: 18 },
{ id: 2, name: "小明", age: 28 },
{ id: 3, name: "小白", age: 4 },
{ id: 4, name: "小新", age: 5 },
{ id: 5, name: "正男", age: 26 },
],
info: {
name: "codewhy",
age: 21
}
},
getters: {
get18Age (state) {
return state.students.filter(function (value, index, array) {
return value.age > 18
})
},
}
<p>年龄大于18的学生</p>
<p>{{ $store.getters.get18Age }}</p>
Getter作为参数
如果我们已经有了一个获取所有年龄大于20岁学生列表的getters, 那么代码可以这样来写
Getter传输参数
getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数
比如上面的案例中,我们希望获取指定姓名的学生信息
// 查询姓名的学生,但是不允许带参数,解决办法是:返回一个有参数的函数
byName (state) {
return (name) => {
return state.students.filter((s) => s.name == name)
}
}
<p>指定小新的学生</p>
<p>{{ $store.getters.byName(‘小新‘) }}</p>
一个参数
包含两部分:
mutations: {
addCount(){
state.count++
}
}
addCount
:事件类型
(){state.count++}
:回调函数
代码示例
// 组件中代码
update() {
this.$store.dispatch(‘aupdate‘).then(() => {
console.log(‘update指行完成‘)
})
},
// Mutation中的代码
update (state, name) {
state.info.name = name
}
多个参数传递
代码示例
// 带有参数的mutations
addStudent() {
const stu = { id: 14, name: ‘风间‘, age: 21 }
this.$store.commit(‘addStu‘, stu)
},
// Mutations中代码
addStu (state, stu) {
state.students.push(stu)
},
另一种提交风格
// 组件中代码
addTemp() {
const temp = 5
// 第二种mutations提交方式
this.$store.commit({
type: ‘addTemp‘,
temp,
})
},
// Mutations中代码
// 第二种提交方式
addTemp (state, payload) {
console.log(payload);
state.count += payload.temp
},
响应规则
context是什么
上下文对象,这里的上下文对象值的是store
代码示例,使用定时器模拟网络请求
// APP中代码
update() {
this.$store.dispatch(‘aupdate‘).then(() => {
console.log(‘update指行完成‘)
})
},
// Actionve代码
// 做异步操作
actions: {
// aupdate (context) {
// setInterval(() => {
// let name = "颜韵"
// context.commit("update", name)
// }, 1000)
// 修改,APP里要知道调用完成没有
aupdate (context) {
new Promise((resolve, reject) => {
setInterval(() => {
let name = "颜韵"
context.commit("update", name) // 指行到这里代表数据修改完成
resolve(); // 走then
})
})
}
},
dispatch
方法调用提交commit
方法提交Module是模块的意思, 为什么在Vuex中我们要使用模块呢?
我们按照什么样的方式来组织模块呢?
看下面代码
上面的代码中, 我们已经有了整体的组织结构, 下面我们来看看具体的局部模块中的代码如何书写
注意:
局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState
如果getters中也需要使用全局的状态, 可以接受更多的参数
如果传输的是对象的话,那么接受函数的参数是对象的key那么就会自动拆分,这是ES6的语法
// 1. 导入axios
import axios from ‘axios‘
// 2. 发送请求
axios({
url: ‘http://123.207.32.32:8000/home/multidata‘,
// method: ‘‘ 发送格式 post get
}).then((request) => {
console.log(request);
})
axios(config)
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
axios.all([数组])
axios.all([axios.get("http://123.207.32.32:8000/home/multidata"),
axios.get("http://123.207.32.32:8000/home/data")
]).then(axios.spread((resq1, resq2) => {
console.log(resq1);
console.log(resq2);
}))
在实际开发中,很多路径前面都是一致的,这个时候我们就可以给axios设置一个基础的URL
axios.defaults.baseURL = ‘123.207.32.32:8000‘
// 下面的路径就可以这么写了
axios.all([axios.get("/home/multidata"),
axios.get("/home/data")
]).then(axios.spread((resq1, resq2) => {
console.log(resq1);
console.log(resq2);
}))
请求地址
url: ‘/user‘
请求类型
method:‘get‘
请跟路径
baseURL:‘http://www.mt.com/api‘
请求前的数据处理
transformRequest:[function(data){}]
请求后的数据处理
transformResponse: [function(data){}]
自定义的请求头
headers:{‘x-Requested-With‘:‘XMLHttpRequest‘},
URL查询对象
params:{ id: 12 },
查询对象序列化函数
paramsSerializer: function(params){ }
request body
POST请求
data: { key: ‘aa‘},
超时设置
timeout: 1000
跨域是否带Token
withCredentials: false
自定义请求处理
adapter: function(resolve, reject, config){},
身份验证信息
auth: { uname: ‘‘, pwd: ‘12‘},
响应的数据格式 json / blob /document /arraybuffer / text / stream
responseType: ‘json‘,
为什么要创建axios的实例呢
代码示例
const axiosInstance = axios.create()
axiosInstance.get(‘http://123.207.32.32:8000/home/multidata‘).then((req) => {
console.log(req);
})
const axiosInstance1 = axios.create({
baseURL: ‘http://123.207.32.32:8000‘
})
axiosInstance1.get(‘/home/multidata‘).then((req) => {
console.log(req);
})
注意:不论是请求或响应拦截,都是在前拦截的,比如:请求拦截是在发送请求前拦截。响应是接受响应信息前拦截
// 拦截请求
axiosInstance1.interceptors.request.use(config => {
console.log("拦截到了");
console.log(config);
return config
}, err => {
// 出错
})
// 响应拦截
axiosInstance1.interceptors.response.use((req) => {
console.log(req);
console.log("拦截响应");
return req
}, err => {
// 出错
})
拦截器实际中一般的应用
请求
响应
实际开发中,因为用到第三方框架,所以要想到以后,万一框架不维护了,或者后面要换发送网络请求的框架了。这都是要考虑的情况。
如果说,你的每一个网页里都是导入axios
直接用,那么你的程序太过依赖第三方框架,也就是高耦合,这种情况造成的后果上面也说了,而解决这种问题的思路是。
在src目录下新建network文件夹,然后写在里面导入axios框架,然后我们写函数导出
request.js
import axios from ‘axios‘
export function requset (config) {
const instance = axios.create({
baseURL: "http://123.207.32.32:8000",
timeout: 5000
})
return instance(config)
}
main.js应用
import { requset } from ‘./netrwork/request‘
requset({
url: "/home/multidata",
mode: "get"
}).then((req) => {
console.log(req);
})
变量有了块级作用域,关键字分别是let
和const
;分别是局部变量,常量(不能修改指向)
代码示例,以及没有块级作用域的BUG
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>块级作用域</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!--
ES6的增强:
变量由作用域了。用let关键字定义。
var定义变量是没有作用域的,相当于全局变量,所以有一个缺陷,比如点击按钮输出,这是第几个按钮
没有作用域会产生的问题,以及解决和增强之后的解决
-->
<div id="app">
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
</div>
<script>
var buttons = document.getElementsByTagName(‘button‘)
// 输出结果是直接是第5个按钮被单击,原因是在执行js的时候,程序为每个按钮绑定一个click事件,
// 当全部好,i的值就是5,而js没有作用域,所以使用的都是同一个i变量,解决办法使用函数(闭包)
for (var i = 0; i < buttons.length; i++) {
;(function (num) {
buttons[i].addEventListener(‘click‘, function () {
console.log(‘第‘ + num + ‘个按钮被单击‘)
})
})(i)
}
// --------------------增强之后ES6解决办法
var buttons = document.getElementsByTagName(‘button‘)
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener(‘click‘, function () {
console.log(‘di-‘ + i + ‘被单击‘)
})
}
// ------------ 循环生成的程序
{
i = 0
;(function (num) {
buttons[i].addEventListener(‘click‘, function () {
console.log(‘第‘ + num + ‘个按钮被单击‘)
})
})(i) // 这里是直接函数调用
}
{
i = 1
;(function (num) {
buttons[i].addEventListener(‘click‘, function () {
console.log(‘第‘ + num + ‘个按钮被单击‘)
})
})(i)
}
</script>
</body>
</html>
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script>
// 规则1:在使用的时候,一定要初始化
const obj = ‘xiaobai‘
// 规则2:建议使用const关键字,可以很明确告诉别人这个变量作用
// 规则3:可以修改指向内容
const obj1 = {
name: ‘小白‘,
sex: ‘男‘,
}
obj1.name = ‘小红‘
</script>
</body>
</html>
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>ES6对属性和方法的增强</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script>
// ES5定义对象
var obj = {
name: ‘小红‘,
age: 15,
sex: ‘男‘,
}
name = ‘小红‘
sex = ‘女‘
age = 20
var obj = {
name: name,
age: age,
sex: sex,
}
// ES6增强 可以直接写变量名,会把变量名作为key,内容为value
var obj = {
name,
age,
sex,
}
// ES6对方法的增强
var obj = {
eat: function () {
console.log(‘吃东西‘)
},
}
// 增强
var obj = {
eat() {
console.log(‘吃东西‘)
},
}
</script>
</body>
</html>
见名知意,过滤函数。回调函数中返回如果为true
那么就会存储在新的数组中
代码示例
const list = [12, 34, 555, 1223, 343, 55, 66, 98]
// 求小于100的数字
// filter 回调函数
// 参数,是每个元素的值
// 返回值:布尔类型,如果是true那么会装到新数组中
let newList01 = list.filter(function (number) {
return number < 100
})
console.log(newList01)
替换,回调函数中,遍历每个元素,在回调中操作,并返回值,生成新的数组
// 小于100的数字 乘2倍
// map: 回调函数
// 参数:是每个元素的值
// 返回值是:每个元素的处理
// 更像是:替换数组中所有元素
let newList02 = newList01.map(function (number) {
return number * 2
})
console.log(newList02)
计算和,回调函数中两个参数
代码示例
// 求和
// reduce:回调函数
// 参数1:总数(初始值/先前返回的值)
// 参数2:下一个元素的值
// 初始值,不写也可以,
// 返回值:先前返回的值+下一个元素的值
let newList03 = newList02.reduce(function (preValue, n) {
return preValue + n
}, 0)
console.log(newList03)
let sum = list
.filter(function (number) {
return number < 100
})
.map(function (n) {
return n * 2
})
.reduce(function (p, next) {
return p + next
})
console.log(sum)
原文:https://www.cnblogs.com/q2210075017/p/13261604.html