<div id="app">
<p v-on:click="clickHandle">{{ message }}</p>
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
message: 'hi Vue'
},
methods: {
clickHandle () {
alert('hello, Vue!')
}
}
})
</script>
<div id="app">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">反转字符串</button>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'hello, Vue!'
},
methods: {
reverseMessage () {
// console.log(this.message.split(''))
this.message = this.message.split('').reverse().join('')
}
}
})
</script>
<div id="app">
<!-- <p>{{ if(flag) { 'yes' } else { 'no' } }}</p>-->
<p>{{ flag ? 'yes' : 'no' }}</p>
<!-- {{ 只能使用JS表达式,不能使用JS语句 }} -->
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
flag: false
}
})
// if(flag) {
//
// } else {
//
// }
// let a = 1;
// let b = 2
// console.log(a + b) //
</script>
<div id="app">
<p v-html="message"></p>
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
message: '\n'
+
' hello 1902B\n' +
''
}
})
</script>
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
<div id="app">
<template v-if="seen">
<p>AAA</p>
<p>AAA</p>
<p>AAA</p>
</template>
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
seen: true
}
})
</script>
<div id="app">
<ol>
<li v-for="item in todos">{{ item.text }}</li>
</ol>
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
todos: [
{
text: 'JavaScript'
},
{
text: 'React'
},
{
text: 'Vue2.0'
}
]
}
})
</script>
遍历对象
<div id="app">
<ol>
<li v-for="value in obj">{{ value }}</li>
</ol>
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
obj: {
firstName: '二师兄',
lastName: '猪八戒',
age: '咱也不知道'
}
}
})
</script>
v-if VS v-for
v-for的优先级高于v-if 和 v-show
<div id="app">
<ol>
<li v-for="item in arr" v-if="item.flag">{{ item.title }}</li>
</ol>
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
arr: [
{
title: '熊大',
flag: true
},
{
title: '熊二',
flag: true
},
{
title: '强哥',
flag: false
}
]
}
})
</script>
v-class
v-bind:class 指令也可以与普通的 class 属性共存
<div id="app">
<span class="fontSize" v-bind:class="{ red: addClass }">hello, Vue</span>
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
addClass: true
}
})
</script>
v-bind:style
<div id="app">
<span v-bind:style="styleObj">hello, Vue</span>
</div>
<script>
const vm = new Vue({
el: '#app', // 挂载点
data: { // 咱们的数据 这里是和模板发生关系的地方
styleObj: {
color: 'red',
fontSize: '100px'
}
}
})
</script>
本地(局部)过滤器
<div id="app">
<p>{{ msg | firstUpper }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
msg: 'abc'
},
// 定义局部过滤器
filters: {
firstUpper(val) {
return val.charAt(0).toUpperCase() + val.slice(1)
}
}
})
</script>
全局过滤器
<div id="app">
<p>{{ msg | firstUpper }}</p>
</div>
<script>
// 全局过滤器
Vue.filter('firstUpper', val => {
return val.charAt(0).toUpperCase() + val.slice(1)
})
new Vue({
el: '#app',
data: {
msg: 'abc'
}
})
</script>
过滤器传参
<div id="app">
<p>{{ msg | firstUpper('1') }}</p>
</div>
<script>
// 全局过滤器
Vue.filter('firstUpper', (val, index) => {
return val.slice(0, index) + val.charAt(index).toUpperCase() + val.slice(Number(index) + 1)
})
new Vue({
el: '#app',
data: {
msg: 'abc'
}
})
</script>
过滤器的串联
<div id="app">
<p>{{ msg | firstUpper('1') | connect }}</p>
</div>
<script>
// 全局过滤器
Vue.filter('firstUpper', (val, index) => {
return val.slice(0, index) + val.charAt(index).toUpperCase() + val.slice(Number(index) + 1)
})
Vue.filter('connect', val => {
return val.split('').join('-')
})
new Vue({
el: '#app',
data: {
msg: 'abc'
}
})
</script>
除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令
<div id="app">
<input type="text" v-focus>
</div>
<script>
Vue.directive('focus', {
inserted(el) {
console.log(el)
el.focus()
}
})
new Vue({
el: '#app'
})
</script>
钩子
<div id="app">
<div v-smallfour>{{ num }}</div>
<div>
<button @click="add">Add</button>
</div>
<button onclick="unbind()">unbind</button>
</div>
<script>
// 自定义指令
Vue.directive("smallfour",{
bind:function(el,binding){ //被绑定
console.log('1 - bind');
},
inserted: function () { //绑定到节点
console.log('2 - inserted');
},
update: function () { //组件更新
console.log('3 - update');
},
componentUpdated: function () { //组件更新完成
console.log('4 - componentUpdated');
},
unbind: function () { //解绑
console.log('5 - unbind');
}
});
// 解绑
function unbind() {
vm.$destroy(); //解除绑定
}
// 实例化
const vm = new Vue({
el : '#app',
data : {
num: 0
},
methods: {
add: function () {
this.num++;
}
}
})
</script>
扩展知识
官网
大前端
<div id="app">
<input type="checkbox" value="熊大" v-model="checkedNames">
<label for="">熊大</label>
<input type="checkbox" value="熊二" v-model="checkedNames">
<label for="">熊二</label>
<input type="checkbox" value="强哥" v-model="checkedNames">
<label for="">强哥</label>
<br />
<span>checked names: {{ checkedNames }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
checkedNames: []
}
})
</script>
<div id="app">
<input type="radio" value="熊大" v-model="picked">
<label for="">熊大</label>
<input type="radio" value="熊二" v-model="picked">
<label for="">熊二</label>
<input type="radio" value="强哥" v-model="picked">
<label for="">强哥</label>
<br />
<span>picked: {{ picked }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
picked: ''
}
})
</script>
<div id="app">
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
selected: 'B',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
})
</script>
Vue中数组的方法是变异的方法,因为和原生JS相比增加了响应式的特性;
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护
<div id="app">
<p>{{ message }}</p>
<p>{{ reverseMessage }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'React'
},
computed: {
reverseMessage() {
return this.message.split('').reverse().join('')
}
}
})
</script>
<div id="app">
<p>{{ message }}</p>
<p>{{ reverseMessage() }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'angularJS'
},
computed: { // 只要计算属性依赖的data里面的某个值没有发生任何变化,处理数据的逻辑代码就不再执行了,而是直接返回上次计算的结果
reverseMessage() {
return this.message.split('').reverse().join('')
}
}
// methods: { // methods每次都会执行一遍,没有缓存
// reverseMessage() {
// return this.message.split('').reverse().join('')
// }
// }
})
</script>
<div id="app">
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
<input type="text" v-model="fullName">
</div>
<script>
new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
// 监听firstName这个数据
firstName: function(val) {
console.log(val)
this.fullName = val + '' + this.lastName
},
// 监听firstName这个数据
lastName: function(val) {
console.log(val)
this.fullName = this.firstName + '' + val
}
}
})
</script>
<div id="app">
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
<input type="text" v-model="fullName">
</div>
<script>
new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar'
}
computed: {
// fullName定义的计算属性名
fullName: function() {
return this.firstName + '' + this.lastName
}
}
})
</script>
watch的使用场景/watch的特点
只有监听的值变化的时候才执行,默认不执行
<div id="app">
<p>fullName: {{ fullName }}</p>
<p>firstName: <input type="text" v-model="firstName"></p>
</div>
<script>
new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: ''
},
watch: {
firstName(newName, oldName) {
this.fullName = newName + '' + this.lastName
}
}
})
</script>
初始化执行一次,需要配置一个属性immerdiate
<div id="app">
<p>fullName: {{ fullName }}</p>
<p>firstName: <input type="text" v-model="firstName"></p>
</div>
<script>
new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: ''
},
watch: {
firstName: {
// 类似于钩子
handler(newName, oldName) {
this.fullName = newName + '' + this.lastName
},
immediate: true // 初始化执行一次
},
}
})
</script>
deep 深度监听
<div id="app">
<p>obj.title: <input type="text" v-model="obj.title"></p>
</div>
<script>
new Vue({
el: '#app',
data: {
obj: {
title: '熊大'
}
},
watch: {
obj: {
handler(newName, oldName) {
console.log('obj.title改变了')
},
// immediate: true, // 初始化执行一次
deep: true // 深度监听
},
}
})
</script>
TODOlist
便于协同开发
方便复用
提升整个项目的可维护性
可定制
互操作性 - 多组件互相协同
高内聚
低耦合
样式结构
行为逻辑
数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-select></custom-select>
</div>
<script>
// 注册组件
Vue.component('custom-select', {
template: `
- JavaScript7
- React16
- Vue2.0
- JavaScript5
- JavaScript6
`
})
// 实例化
new Vue({
el: '#app'
})
</script>
</body>
</html>
父传子 - 上到下
基础示例 - 一级传递 - 嵌套一层而已
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-select :btn-val="btn1"></custom-select>
<custom-select :btn-val="btn2"></custom-select>
</div>
<script>
// 注册组件 - 子组件
Vue.component('custom-select', {
props: ['btnVal'],
template: `
- JavaScript7
- React16
- Vue2.0
- JavaScript5
- JavaScript6
`
})
// 实例化 - 看做父组件
new Vue({
el: '#app',
data: {
btn1: '查询',
btn2: '搜索'
}
})
</script>
</body>
</html>
进阶示例 - 多层嵌套 - 多层传递
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-select :btn-val="btn1" :list="list1"></custom-select>
<custom-select :btn-val="btn2" :list="list2"></custom-select>
</div>
<script>
// 注册组件 - 父组件
Vue.component('custom-select', {
props: ['btnVal', 'list'],
template: `
`
})
// 注册组件 - 孙子组件
Vue.component('list', {
props: ['childList'],
template: `
- {{ item }}
`
})
// 实例化 - 看做爷爷组件
new Vue({
el: '#app',
data: {
btn1: '查询',
btn2: '搜索',
list1: ['猪八戒','孙猴子', '沙和尚'],
list2: ['熊大', '熊二', '强子']
}
})
</script>
</body>
</html>
第一步:在组件的标签上面以自定义属性名 + 数据的形式(),进行数据的绑定;
第二步:然后在组件内部通过props进行接收(props:[‘list’]),就可以直接在template中进行数据的使用了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-select :btn-val="btn1" :list="list1"></custom-select>
<custom-select :btn-val="btn2" :list="list2"></custom-select>
</div>
<script>
// 注册组件 - 父组件
Vue.component('custom-select', {
props: ['btnVal', 'list'],
data() {
return {
value: ''
}
},
template: `
`,
methods: {
getVal(val) {
console.log(`${val}我是子组件传递过来的数据`)
this.value = val
}
}
})
// 注册组件 - 孙子组件
Vue.component('list', {
props: ['childList'],
template: `
- {{ item }}
`,
methods: {
selectVal(val) {
// console.log(val)
// 把数据传递给父组件
this.$emit('receive', val) // 第一个参数:自定义事件名;第二个参数:要传递的数据;
}
}
})
// 实例化 - 看做爷爷组件
new Vue({
el: '#app',
data: {
btn1: '查询',
btn2: '搜索',
list1: ['猪八戒','孙猴子', '沙和尚'],
list2: ['熊大', '熊二', '强子']
}
})
</script>
</body>
</html>
第一步:在子组件上通过this下面的$emit(第一个参数是自定义事件,第二个参数要传递的数据)
第二步:在子组件的组件标签上通过@自定义事件名,等于回调函数的形式进行数据的处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-select :btn-val="btn1" :list="list1"></custom-select>
</div>
<script>
// 注册组件 - 父组件
Vue.component('custom-select', {
props: ['btnVal', 'list'],
data() {
return {
value: ''
}
},
template: `
`,
methods: {
getVal(val) {
console.log(`${val}我是子组件传递过来的数据`)
this.value = val
}
}
})
// 注册组件 - 兄弟组件input
Vue.component('child-input', {
props: ['childInput', 'childListItem'],
template: `
`
})
// 注册组件 - 兄弟组件list
Vue.component('list', {
props: ['childList'],
template: `
- {{ item }}
`,
methods: {
selectVal(val) {
// console.log(val)
// 把数据传递给父组件
this.$emit('receive', val) // 第一个参数:自定义事件名;第二个参数:要传递的数据;
}
}
})
// 实例化 - 看做爷爷组件
new Vue({
el: '#app',
data: {
btn1: '查询',
btn2: '搜索',
list1: ['猪八戒','孙猴子', '沙和尚'],
list2: ['熊大', '熊二', '强子']
}
})
</script>
</body>
</html>
第一:兄弟组件通信是利用父组件作为中转;
第二:子 -> 父 -> 子
组件通信重写TODO - 习题素材下载
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
// const myComponent = function() {}
// // 这个data在这里是一个对象
// myComponent.prototype.data = {
// a: 1,
// b: 2
// }
// const component1 = new myComponent()
// const component2 = new myComponent()
//
// component1.data.a = 5
//
// console.log(component2.data.a)
/*
* 如果是对象,不用function,返回每个组件的data都是内存中的同一个地址,一个数据改变了,其他的也会发生变化。
*
* 在JavaScript只有函数可以构成作用域,这就是data为什么是一个函数的原因,每个组件实例,都有自己的作用域,互相独立不会互相影响
*
* */
const myComponent = function() {
this.data = this.data()
}
myComponent.prototype.data = function() {
return {
a: 1,
b: 2
}
}
const component1 = new myComponent()
const component2 = new myComponent()
component1.data.b = 5
console.log(component2.data.b)
</script>
</body>
</html>
是通过Vue空实例,作为连接$emit & $on,又称为中央通信
目前中央通信是解决兄弟间通信,祖父祖孙间通信的最佳方法,不仅限于此,也可以解决父组件子组件间的相互通信
*各组件可自己定义好组件内接收外部组件的消息事件即可,不用理会是哪个组件发过来;而对于发送事件的组件,亦不用理会这个事件到底怎么发送给我需要发送的组件。
*Bus中央通信的方案各种情况下都可用,比较方便
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<Aaa></Aaa>
<Bbb></Bbb>
</div>
<script>
// Vue空实例 中央通信 用于连接$emit & $on
let bus = new Vue()
// 组件A
Vue.component('Aaa', {
template: `我是A组件`,
methods: {
aaa() {
bus.$emit('is-selected') // 广播
}
}
})
// 组件B
Vue.component('Bbb', {
template: `我是B组件`,
created() {
bus.$on('is-selected', function() { // 接收/监听
console.log('我是A组件传递过来的')
})
}
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
数据从父组件传递给子组件,只能单向绑定。
在子组件内部不能直接修改父组件传递过来的数据。
注意:最新的Vue2.6版本,不会警告可以直接修改父组件传递过来的数据,简单查了一下没找到相关资料。按照2.0的理解去记就可以了,知道2.6这个特性即可。
不能直接改变父组件传递过来的数据
<div id="app">
<custom-com :count="count"></custom-com>
</div>
<script>
//子组件
Vue.component('customCom', {
props: ['count'],
template: `
我是自定义的组件
{{ count }}
`,
methods: {
changeCount() {
this.count++
}
}
})
// 看做父组件
new Vue({
el: '#app',
data: {
count: 0
}
})
</script>
第一种修改方式:父组件传递过来的数据作为子组件局部的初始值
<div id="app">
<custom-com :count="count"></custom-com>
</div>
<script>
//子组件
Vue.component('customCom', {
props: ['count'],
data() {
return {
increment: this.count
}
},
template: `
我是自定义的组件
{{ increment }}
`,
methods: {
changeCount() {
this.increment++
}
}
})
// 看做父组件
new Vue({
el: '#app',
data: {
count: 0
}
})
</script>
第二种:通过computed
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-com :count="count"></custom-com>
</div>
<script>
//子组件
Vue.component('customCom', {
props: ['count'],
data() {
return {
increment: this.count
}
},
template: `
我是自定义的组件
{{ incrementCount }}
`,
methods: {
changeCount() {
this.increment++
}
},
computed: {
incrementCount() {
return this.increment
}
}
})
// 看做父组件
new Vue({
el: '#app',
data: {
count: 0
}
})
</script>
</body>
</html>
我们可以为组件的 prop 指定验证要求
内置校验规则
String
Number
Boolean
Array
Object
Date
Function
Symbol
自定义校验规则
props: {
count: {
validator: function(value) {
return value < 10
}
}
},
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-com :count="count"></custom-com>
</div>
<script>
//子组件
Vue.component('customCom', {
// props: {
// count: {
// type: [Number, String],
// default: 100
// }
// },
props: {
count: {
validator: function(value) {
return value < 10
}
}
},
data() {
return {
increment: this.count
}
},
template: `
我是自定义的组件
{{ increment }}
`,
methods: {
changeCount() {
this.increment++
}
}
})
// 看做父组件
new Vue({
el: '#app',
data: {
count: 11
}
})
</script>
</body>
</html>
多个组件可以使用同一个挂载点,动态切换
Component
<div id="app">
<input type="button" value="切换到第1个组件" @click="tabComponent(1)">
<input type="button" value="切换到第2个组件" @click="tabComponent(2)">
<input type="button" value="切换到第3个组件" @click="tabComponent(3)">
<component :is="current"></component>
</div>
<script>
// 第一个组件
const custom1 = Vue.component('custom1', {
template: `我是第1个组件`
})
// 第二个组件
const custom2 = Vue.component('custom2', {
template: `我是第2个组件`
})
// 第三个组件
const custom3 = Vue.component('custom3', {
template: `我是第3个组件`
})
new Vue({
el: '#app',
data: {
current: custom1
},
methods: {
tabComponent(index) {
if (index === 1) {
this.current = custom1
} else if(index ===2) {
this.current = custom2
} else {
this.current = custom3
}
}
}
})
</script>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
它自身不会渲染一个 DOM 元素,也不会出现在父组件链中
<div id="app">
<input type="button" value="切换到第1个组件" @click="tabComponent(1)">
<input type="button" value="切换到第2个组件" @click="tabComponent(2)">
<input type="button" value="切换到第3个组件" @click="tabComponent(3)">
<keep-alive>
<component :is="current"></component>
</keep-alive>
</div>
<script>
// 第一个组件
const custom1 = Vue.component('custom1', {
template: `我是第1个组件`,
methods: {
changeBg(ev) {
ev.target.style.background = 'orange'
}
}
})
// 第二个组件
const custom2 = Vue.component('custom2', {
template: `我是第2个组件`
})
// 第三个组件
const custom3 = Vue.component('custom3', {
template: `我是第3个组件`
})
new Vue({
el: '#app',
data: {
current: custom1
},
methods: {
tabComponent(index) {
if (index === 1) {
this.current = custom1
} else if(index ===2) {
this.current = custom2
} else {
this.current = custom3
}
}
}
})
</script>
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
扩展 - 实战示例
基础示例 - 匿名插槽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom>
<p>我是HTML结构</p>
</custom>
</div>
<script>
Vue.component('custom', {
template: `
hello,1902B
`
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
进阶示例 - 具名插槽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom>
<div slot="third">
<ol>
<li>111</li>
<li>222</li>
<li>333</li>
</ol>
</div>
<div slot="second">替换第二个</div>
<div slot="first">替换第三个</div>
</custom>
</div>
<script>
Vue.component('custom', {
template: `
hello,1902B
`
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
插槽作用域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom>
{{ message }}
</custom>
</div>
<script>
// 看做子组件
Vue.component('custom', {
data() {
return {
message: '我是子组件的数据'
}
},
template: `
{{ message }}
hello,1902B
`
})
// 看做父组件
new Vue({
el: '#app',
data: {
message: '我是父组件的数据'
}
})
/*
* 作用域,互不干扰
* */
</script>
</body>
</html>
方法名 | 状态 | 含义 |
---|---|---|
beforeCreate | creating 状态 | 实例创建之前调用 |
beforeCreate | creating 状态 | 实例创建之前调用 |
created | creating 状态 | 实例创建成功,此时 data 中的数据显示出来了 |
beforeMount | mounting 状态 | 数据中的 data 在模版中先占一个位置 |
mounted | mounting 状态 | 模版中的 data 数据直接显示出来了 |
beforeUpdate | updating 状态 | 当 data 数据发生变化调用,发生在虚拟 DOM 重新渲染和打补丁之前 |
updated | updating 状态 | 数据更改导致的虚拟 DOM 重新渲染和打补丁 |
beforeDestroy | destroying 状态 | 在 vue 实例销毁之前调用,此时实例任然可用 |
destroyed | destroying 状态 | 在 vue 实例销毁之后调用,vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁 |
如果使用了keep-alive会是10个(activated、deactivated)
activated:来缓存组件状态,这个时候created钩子就不会被重复调用了, 如果我们的子组件需要在每次加载的时候进行某些操作,可以使用activated钩子触发
deactivated:组件移除时触发根据服务端还是客户端渲染机制,生命周期依旧会发生变化
updated 不被执行
destroyed 不被执行
哎呀,好无聊啊,看看人家都有对象,一起学习/一起看电影一起做爱做的事,真好。我也好想有个女朋友哦(beforeCreate,概念化阶段,什么都没有)。
你要找的女朋友是什么样的呢?首先她是个女孩子,一个嘴巴、两条腿,等等总之就是女孩子默认的特征(created,有了雏型默认的数据有了)。
我未来的女朋友要像林志玲一样、或者像我的同桌这样的就行,根据自己的喜好已经勾勒出未来女朋友的样子(beforeMount,虚拟的还没有具体的目标)。
哇,隔壁班级新来的那位女孩子不错,她就是我喜欢的类型,我要把她追到手,让她做我女朋友(mounted,有了具体的目标形成了真实的DOM展示给了用户)。
追的我好累啊还没追到手,不行我得调整下战术,不能每天找她玩了,我要好好学习Vue在积云我说第二没人敢说第一那种的,给她补课(beforeUpdate,战术已调整还未投入实战)
去班级看看她有没有什么不会的,教教她(updated,新的战术已投入试用)
这死孩子真麻烦,天天教我Vue,搞的我好像多么笨似的,我自己能搞定四哥说了,要培养自己的学习能力及解决问题的能力,真烦人(beforeDestroy,已经很烦这个小伙子了,准备拒绝他的好意)
你又来干啥玩意儿,我自己能搞定,你给我滚,滚回你们班去,你除了Vue还会啥?四哥没告诉你吗,javascript才是最重要的,你给我滚,别来烦我(destroyed,微信拉黑&隔离灭了你丫的,销毁了!!!)
hash(默认)
history
// 一级路由
{
path: '/about',
name: 'about',
component: About,
children: [ // 二级路由
{
path: '',
name: 'about',
component: Study
}
]
},
tag
class
path: '*',
redirect: '/'
redirect: {
// path: '/'
name: 'home'
}
路由元信息
meta:{}
过渡动效
// template
<transition name="fade">
<router-view />
</transition>
// CSS
.fade-enter {
opacity: 0;
}
.fade-enter-active {
transition: 1s;
}
.fade-enter-to {
opacity: 1;
}
{
path: '/user/:userId?',
component: User
},
<router-link :to="'/user/' + item.id" v-for="item in userList">{{ item.userName }}</router-link>
let { userId } = this.$route.params
// 传递
:to="'/user/' + item.id"
// 接收
this.$route.params.userId
// 传递
<router-link :to="{name:'user',params:{userId:item.id}}" v-for="item in userList">{{ item.userName }}</router-link>
// 接收
this.$route.params.userId
// 传递
<router-link :to="{path:'/user',query:{userId:item.id}}" v-for="item in userList">{{ item.userName }}</router-link>
// 接收
this.$route.query.userId
query VS params
显示上
用法上
{path:'/user',query:{userId:item.id}}
this.$route.query
'/user/:userId?'中的/:userId?可以省略
{name:'user',params:{userId:item.id}}
this.$route.params
'/user/:userId?'中的/:userId?不可以省略
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。
全局的
单个路由的
组件
beforeRouteEnter - 进入某个组件前
beforeRouteUpdate - 组件复用的时候触发
beforeRouteLeave - 离开组件
这里详细 - O(∩_∩)O哈哈~
支持node端和浏览器端
promise
丰富的配置项
transformRequest
transformResponse
baseURL
拦截器
…
社区庞大
npm i axios
// 哪个地方用得到就在哪个组件引入
import Axios from 'axios'
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
axios.get('/user', {
params: {
ID: 12345
}
})
xios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
// 第一个接口
function getCnode() {
return Axios.get('https://cnodejs.org/api/v1/topics111');
}
// 第二个接口
function getMall() {
return Axios.get('https://api.it120.cc/small4/shop/goods/category/all');
}
// 并发请求
Axios.all([getCnode(), getMall()])
.then( (res1, res2) => {
// 两个请求现在都执行完成
console.log(res1)
console.log(res2)
}))
.catch(err => {
console.log(err)
})
// 第一个接口
function getCnode() {
return Axios.get('https://cnodejs.org/api/v1/topics111');
}
// 第二个接口
function getMall() {
return Axios.get('https://api.it120.cc/small4/shop/goods/category/all');
}
// 并发请求
Axios.race([getCnode(), getMall()])
.then(( (res1, res2) => {
// 两个请求现在都执行完成
console.log(res1)
console.log(res2)
}))
.catch(err => {
console.log(err)
})
// 第一个接口
function getCnode() {
return Axios.get('https://cnodejs.org/api/v1/topics111');
}
// 第二个接口
function getMall() {
return Axios.get('https://api.it120.cc/small4/shop/goods/category/all');
}
// 并发请求
Axios.all([getCnode(), getMall()])
.then(Axios.spread(function (res1, res2) {
// 两个请求现在都执行完成
console.log(res1)
console.log(res2)
}))
.catch(err => {
console.log(err)
})
拦截器,顾名思义,用来拦截什么东西的
在Axios中拦截器是用来拦截ajax请求的
分两组共有四个拦截点
实战案例 - loading动画
// App.vue
Loading...
export default {
data() {
return {
isLoading: true // 默认显示
}
},
created () {
// 添加响应拦截器
Axios.interceptors.response.use( (response) => {
// 对响应数据做点什么
this.isLoading = false // 数据请求成功isloading改为false,loading隐藏掉
return response;
});
}
}
扩展知识
Axios - 实战案例讲解
见官网
官网:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
用来管理全局组件状态或管理多个组件共享状态
专门为Vue应用程序开发的状态管理模式
状态可以理解为数据,其实就是用来管理我们的数据的
采用集中式存储管理应用的所有组件的状态
在做一个webApp的时候的时候里面会牵扯到很多数据,这个时候我们可以集中式的管理这些数据
npm i vuex
/**
* index.js Created by SmallFour on 2019/9/28/9:07
*/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
// 状态管理对象
state: {
count: 100
}
})
export default store
import store from './store'
new Vue({
el: '#app', // 挂载点
router, // 路由对象挂载
store,
components: { App }, // 注册组件
template: ' ' // 使用组件
})
<template>
<span>{{ num }}</span>
</template>
<script>
/**
*increment.vue Created by SmallFour on 2019/9/28/8:57
*/
export default {
computed: {
num() {
return this.$store.state.count
}
}
}
</script>
类似容器,包含应用的大部分状态
一个页面只能有一个store
状态存储只能是响应式的
new Vuex.Store({})
state - 定义状态
包含整个应用的大部分状态的对象
// Vuex
state: {
count: 100
}
// 组件中
computed: {
num() {
return this.$store.state.count
}
}
mutations - 改变状态
不能直接改变store中的状态,唯一途径就是通过commit提交mutations
// VUex
mutations: {
addIncrement(state,payLoad) {
state.count+=payLoad.n
}
}
// 组件
increment() {
this.$store.commit('addIncrement', 5)
},
Getters
有时候我们需要从 store 中的 state 中派生出一些状态
可以理解为计算属性
应用实例:购物车总价及总数计算
// Vuex
getters: {
filterCount (state) {
return state.count >= 120 ? 120 : state.count
}
}
// 组件中
computed: {
num1() {
return this.$store.getters.filterCount
}
}
在mutations里面直接异步操作会发生数据混乱的情况
// Vuex
actions: {
addAction(content) {
setTimeout(() => {
content.commit('addIncrement')
}, 1000)
}
}
// 组件中
increment() {
this.$store.dispatch('addAction')
},
项目太大的情况下,在Vuex中会导致有很多个state、mutations、actions、getters等,导致整个项目难以维护,所以就有了modules模块分割
// Vuex中
// 分割模块 - select
const selectModule = {
state: {
val: '我是默认的value'
},
mutations: {
// 改变value值
changeMut(state, payLoad) {
state.val = payLoad
},
}
}
const store = new Vuex.Store({
modules: {
selectModule // 注入到Store的根模块中
}
})
// 组件中
computed: {
getVal() {
return this.$store.state.selectModule.val // 模块分割后取值的时候要加上子模块的名字。注意:在改变状态的时候不必添加子模块名字
}
}