Vue2进阶语法
Vue进阶语法
【一】v-model
修饰符
v-model
:针对 input 标签实现数据双向绑定
# lazy:等待input框的数据绑定失去焦点之后再变化
# number:数字开头,只保留数字,后面的字母不保留;字母开头,都保留
# trim:去除首尾的空格
<body>
<div id="app">
<h1>v-model进阶</h1>
<p>普通 <br>
<input type="text" v-model="name">--------->{{name}}
</p>
<p>lazy:当失去焦点更新数据 <br>
<input type="text" v-model.lazy="name1">--------->{{name1}}
</p>
<p>number:数字开头,只保留数字,后面的字母不保留;字母开头,都保留 <br>
<input type="text" v-model.number="name2">--------->{{name2}}
</p>
<p>trim:去除首尾的空格 <br>
<input type="text" v-model.trim="name3">--------->{{name3}}
</p>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
name1: '',
name2: '',
name3: '',
},
methods: {},
computed: {}
})
</script>
【1】v-model.lazy
和 @change
的区别
v-model.lazy
和@change
都是 Vue 中处理表单输入的方式,但它们有一些区别:- v-model.lazy:
v-model.lazy
是v-model
的一个修饰符,它会在输入框失去焦点时才更新绑定的数据。- 这意味着,当用户在输入框中输入内容时,并不会立即更新数据,而是等到用户离开输入框(例如点击其他地方)时才会更新数据。
- @change:
@change
是一个事件监听器,它会在表单元素的值发生改变并且失去焦点时触发。- 这意味着,当用户在输入框中输入内容后,并且离开输入框时,触发
change
事件,从而执行相应的事件处理函数。
- v-model.lazy:
- 因此,主要的区别在于数据更新的时机:
v-model.lazy
是在失去焦点时才更新数据。@change
是在失去焦点时触发事件,需要手动处理数据更新。
【二】vue发送ajax请求
# vue中使用ajax
-1 jquery的ajax
-2 js原生的fetch
-3 第三方axios(最多)
【1】三种请求方式各自的优劣势及特点
【1.1】jQuery 的 AJAX
-
特点:
-
简单易用,可以快速地发送 AJAX 请求。
-
兼容性好,适用于各种浏览器。
-
提供丰富的方法和选项,便于处理各种情况。
-
-
优势:
-
API 简单,易于上手。
-
兼容性好,能够在各种浏览器中使用。
-
功能丰富,提供了丰富的回调函数和选项。
-
-
劣势:
-
依赖于整个 jQuery 库,如果项目中只使用了少量 jQuery 功能,会显得冗余。
-
jQuery 的体积相对较大,可能会影响页面加载速度。
-
【1.2】原生 JavaScript 的 Fetch
-
特点:
-
是原生的浏览器 API,不依赖于任何库。
-
使用 Promise API 处理异步请求,代码结构清晰。
-
-
优势:
-
原生 API,不需要引入额外的库,减少了项目的依赖。
-
支持 Promise,更好地处理异步操作。
-
-
劣势:
-
兼容性较差,一些老旧的浏览器不支持 Fetch API。
-
功能相对简单,需要自己封装一些功能来满足需求。
-
【1.3】第三方库 Axios
-
特点:
-
基于 Promise,支持浏览器和 Node.js。
-
提供了丰富的功能,如拦截器、取消请求等。
-
在前端社区中广泛应用,有大量的文档和社区支持。
-
-
优势:
-
支持 Promise,便于处理异步操作。
-
提供了丰富的功能和选项,如拦截器、全局配置等。
-
支持取消请求,能够有效地管理并发请求。
-
-
劣势:
-
需要额外引入库,增加了项目的依赖。
-
相对于原生 Fetch,体积略大。
-
【2】使用
<body>
<div id="app">
<p>
数据 <br>
name {{name}}
age {{age}}
</p>
<p>
<button @click="handleJquery">jquery发送ajax</button>
</p>
<p>
<button @click="handleFetch">fetch发送ajax</button>
</p>
<p>
<button @click="handleAxios">axios发送ajax</button>
</p>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: 'lea4ning',
age: 20
},
methods: {
handleJquery() {
$.ajax({
// 请求地址
url: 'http://127.0.0.1:5000/',
// 请求方式
type: 'POST',
// 携带的数据
data: JSON.stringify({name: this.name, age: this.age}),
// 指定 Content-Type 为 JSON
contentType: 'application/json',
// 成功的回调函数
success: (res) => {
this.name = res.result.name
this.age = res.result.age
},
// 失败的回调函数
error: (exc) => {
console.log(exc)
}
})
},
handleFetch() {
fetch('http://127.0.0.1:5000/', {
// 请求方法 默认时get请求
method: 'POST',
// 携带在请求体中的数据
body: JSON.stringify({name: this.name, age: this.age}),
// 请求头
headers: {'Content-Type': 'application/json'},
// 如何处理重定向
redirect: "follow"
}).then(response => response.json()).then(
// 固定格式第一次需要将 响应数据.json()
data => {
console.log(data)
this.name = data.result.name
this.age = data.result.age
}).catch(
// 出现异常的回调函数
exc => console.error(exc))
},
handleAxios() {
axios.post('http://127.0.0.1:5000/',
{name: this.name, age: this.age}).then(response => {
// 处理成功情况
console.log(response);
this.name = response.data.result.name
this.age = response.data.result.age
})
.catch(function (error) {
// 处理错误情况
console.log(error);
})
.finally(function () {
// 总是会执行
});
},
},
})
</script>
# flask 后端
from flask import Flask, jsonify, request
# 第三方模块 # 去除cors跨域请求验证
from flask_cors import CORS # pip install flask-cors
app = Flask(__name__)
CORS(app)
@app.route('/', methods=['POST'])
def index():
# 查看请求携带的数据
print(request.data)
# 将请求携带的json数据转换成字典格式
print(request.json)
res = jsonify({
'code': 100,
'msg': 'success',
'result': {
'name': 'lea4ning_true',
'age': 99
}
})
return res
if __name__ == '__main__':
app.run()
【3】跨源资源共享(CORS)
-
跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。
-
出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。
【3.1】flask为响应添加CORS响应头
【3.1.1】简单请求
import json
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def index():
res = jsonify({
'code': 100,
'msg': 'success',
'result': {
'name': 'lea4ning',
'age': 20
}
})
# 直接为响应头添加信息即可
res.headers['Access-Control-Allow-Origin'] = '*'
return res
【3.1.2】使用flask-cors 解决跨域问题
from flask import Flask, jsonify, request
# 导入类
from flask_cors import CORS
app = Flask(__name__)
# 实例化对象
CORS(app)
@app.route('/')
def index():
res = jsonify({
'code': 100,
'msg': 'success',
'result': {
'name': 'lea4ning_true',
'age': 99
}
})
return res
【3.2】Django为响应添加CORS响应头
【3.2.1】简单请求
- 在返回的结果中加入允许信息(简单请求)
def test(request):
import json
obj=HttpResponse(json.dumps({'name':'lqz'}))
# obj['Access-Control-Allow-Origin']='*'
return obj
- 放到中间件处理复杂和简单请求:
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
def process_response(self,request,response):
if request.method=="OPTIONS":
#可以加*
response["Access-Control-Allow-Headers"]="Content-Type"
response["Access-Control-Allow-Origin"] = "*"
return response
【3.2.2】使用django-cors-headers 解决跨域问题
pip install django-cors-headers
# settings.py
### 注册APP
INSTALLED_APPS = (
...
'corsheaders',
...
)
### 添加中间件
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
...
]
### 添加配置
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
'token'
)
【三】计算属性和侦听器
【1】计算属性
- 计算属性会根据它的依赖进行缓存。只有当相关依赖发生改变时,才会重新计算。这意味着只要依赖没有发生变化,多次访问计算属性会立即返回之前缓存的结果,不会重新计算。
- 普通方法在每次调用时都会重新计算。即使相同的数据和逻辑在多个地方调用,它也会重新执行。
【1.1】使用
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {},
// 将计算属性写在 computed 中
computed: {
函数名(){
// 调用data中的数据 // 当data中的数据发生变化时,计算属性也就会发生变化
// 【注】只有在计算属性中调用了的变量发生变化时,才会跟着变化
return '计算属性的返回值'
};
now: function () {
// 该计算属性将不会发生变化,因为Date.now()并不是响应式依赖
return Date.now()
}
}
})
</script>
【1.2】示例
<body>
<div id="app">
<h1>计算属性</h1>
<p>
firstName:{{firstName}}
</p>
<p>
lastName:{{lastName}}
</p>
<p>
fullName:{{fullName}} <br>
修改firstName: <input type="text" v-model.lazy="firstName">
</p>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
firstName: '赵',
lastName: 'xxx'
},
methods: {},
computed: {
fullName() {
console.log('计算属性fullName执行了')
// 只有当依赖的变量发生变化时,才重新计算
return this.firstName + this.lastName
}
}
})
</script>
【1.3】进阶用法
- 计算属性默认只有 getter,不过在需要时你也可以提供一个 setter
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {},
// 将计算属性写在 computed 中
computed: {
计算属性:{
// 指定set需要,将计算属性写成对象形式 // 而不是函数形式
// 对象中包含两个函数,get和set
get:function(){
return '获取计算属性时执行'
},
set(){
// 修改计算属性时执行
}
}
}
})
</script>
<body>
<div id="app">
<h1>计算属性</h1>
<p>
firstName:{{firstName}}
</p>
<p>
lastName:{{lastName}}
</p>
<p>
fullName:{{fullName}} <br>
修改fullName: <input type="text" v-model="fullName" @focus="fullName=''">
</p>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName: ''
},
methods: {},
computed: {
fullName: {
get: function(){
console.log('计算属性的get被触发了')
// 当获取属性时,调用get
return this.firstName + this.lastName
},
set(value) {
console.log('计算属性的set被触发了')
// 当修改计算属性时,调用set
this.firstName = value.slice(0, 1)
this.lastName = value.slice(1)
}
}
}
})
</script>
【2】侦听器
- 监听一个属性,只要这个属性发生变化,就执行函数
- 当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的
【2.1】使用
<script>
var vm = new Vue({
el: '#app',
data: {},
watch: {
// 需要监听的属性名:函数(){}
属性名:function (newValue,oldValue) {
// 有两个参数 // 第一个是更新过的值,第二个是旧的值
// 一些操作
}
</script>
【2.2】简单示例
<body>
<div id="app">
<p>{{num}}</p>
<p>
<button @click="handleNum">数字加1</button>
</p>
<p>变化了【{{count}}】次</p>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
num: 0,
// 变化次数
count: 0
},
watch: {
// 如果 `count` 发生改变,这个函数就会运行
num: function (newValue, oldValue) {
console.log('new', newValue)
console.log('old', oldValue)
console.log('==================')
// 变化次数+1
this.count++
}
},
methods: {
handleNum() {
this.num += 1
}
}
})
</script>
【2.3】案例(来自vue官网)
_.debounce
是 Lodash库提供的方法之一。它用于创建一个函数,该函数在连续调用之间至少间隔指定的毫秒数。
这种功能常用于延迟执行某个操作,例如在用户输入时延迟发送请求或执行某个耗时操作,以提高性能和用户体验
<body>
<div id="app">
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
</div>
</body>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#app',
data: {
question: '',
answer: '我不能回答,直到你提出了问题!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = '问题通常包含一个【?】. ;-)'
return
}
this.answer = '思考中...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
</script>
【五】组件使用
-
局部组件:只能在当前页面中使用
-
全局组件:全局都可以用
【1】全局组件
【1.1】使用
<body>
<div id="app">
<h1>组件</h1>
<h2>子组件child</h2>
<child></child>
<h3>可以重复使用</h3>
<child></child>
<child></child>
</div>
</body>
<script>
// Vue.component 创建全局组件
Vue.component('组件名', {
template: `
<!-- 组件内容 -->
`,
data() {
// 除了根组件,其余组件的data均需要使用函数返回
return {}
},
methods: {}, // 每一个组件有自己的方法
computed: {} // 有自己的计算属性等
// 组件都可以有自己的data,methods,computed等属性
})
var vm = new Vue({
// 通过el挂载在页面上的,我们称为根组件
el: '#app',
data: {},
methods: {},
computed: {},
})
</script>
【2】局部组件
【2.1】使用
<body>
<div id="app">
<h1>组件</h1>
<h2>子组件child</h2>
<child></child>
</div>
</body>
<script>
// Vue.component 创建全局组件
Vue.component('child', {
template: `
<div>
<p>child</p>
<!-- 在全局组件中使用局部组件 -->
<aaa></aaa>
</div>
`,
data() {
return {}
},
methods: {},
computed: {},
// 组件都可以有自己的data,methods,computed等属性
components: {
'aaa': {
template: `
<div>局部组件,只能在所属的组件中使用</div>`,
data() {
return {}
},
methods: {}
}
}
})
var vm = new Vue({
// 通过el挂载在页面上的,我们称为根组件
el: '#app',
data: {},
methods: {},
computed: {},
components: {
// 根组件中也可以注册局部组件
}
})
</script>
【六】生命周期钩子函数
【1】组件生命周期
【2】生命周期钩子函数
钩子函数 | 描述 |
---|---|
beforeCreate | 创建Vue实例之前调用 |
created | 创建Vue实例成功后调用(可以在此处发送异步请求后端数据) |
beforeMount | 渲染DOM之前调用 |
mounted | 渲染DOM之后调用 |
beforeUpdate | 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染) |
updated | 重新渲染完成之后调用 |
beforeDestroy | 销毁之前调用 |
destroyed | 销毁之后调用 |
【3】案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>生命周期</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<child v-if="isShow"></child>
<br>
<button @click="terminate">删除子组件</button>
<button @click="reborn">显示子组件</button>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div>
{{name}}
<button @click="name='Darker1'">更新数据1</button>
<button @click="name='Darker2'">更新数据2</button>
</div>`,
data() {
return {
name: 'Darker1',
}
},
beforeCreate() {
console.group('当前状态:beforeCreate')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
created() {
console.group('当前状态:created')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
beforeMount() {
console.group('当前状态:beforeMount')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
mounted() {
console.group('当前状态:mounted')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
beforeUpdate() {
console.group('当前状态:beforeUpdate')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
updated() {
console.group('当前状态:updated')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
beforeDestroy() {
console.group('当前状态:beforeDestroy')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
destroyed() {
console.group('当前状态:destroyed')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
})
let vm = new Vue({
el: '#box',
data: {
isShow: true
},
methods: {
terminate() {
this.isShow = false
},
reborn() {
this.isShow = true
}
}
})
</script>
</html>
【七】父组件与子组件通信
【1】父组件向子组件通信(自定义属性)
【1.1】基本使用
<body>
<div id="app">
<h1>根组件</h1>
<!-- 在子组件标签内部定义属性 -->
<child 自定义属性名="值"></child>
<child :自定义属性名="变量"></child>
<child v-bind:自定义属性名="变量"></child>
</div>
</body>
<script>
// 定义全局组件
Vue.component('child',{
template:`<div>{{自定义属性名}}</div>`,
props:['自定义属性名']
})
var vm = new Vue({
el: '#app',
components: {
child: {
// 定义局部组件
template: `<div></div>`,
data() {return {}},
// 在 【props】数组中,传入与自定义属性名一致的字符串即可在子组件中使用
props: ['自定义属性名'], // 使用数组接收父组件传递的数据
}
}
})
</script>
【1.2】示例
<body>
<div id="app">
<h1>根组件</h1>
<h2>根组件下的子组件child</h2>
<hr>
<p>自定义属性 【:属性名=变量】</p>
<child :datafromfather="value1"></child>
<hr>
<p>自定义属性 【v-bind:属性名=值】</p>
<child v-bind:data3="value2"></child>
<hr>
<p>自定义属性 【属性名=值】</p>
<child data2="value1"></child>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
value1: 'data from father',
value2: '222',
},
components: {
child: {
// 定义局部组件
template: `
<div>
<h1>child</h1>
<ul>
<template v-for="value in $props">
<!-- 遍历$props将没有定义的值过滤掉,只显示有的值-->
<li v-if="value !== undefined">
父组件传递的数据: {{ value }}
</li>
</template>
</ul>
</div>
`,
created() {
// 组件创建完毕后,父传子的数据就有了
console.log(this.$props)
console.log(this.datafromfather, this.data2, this.data3)
},
props: ['datafromfather', 'data2', 'data3'], // 使用数组接收父组件传递的数据
}
}
})
</script>
【2】子组将向父组件通信(自定义事件)
【2.1】基本使用
<body>
<div id="app">
<!-- 【1】在子组件标签内定义自定义事件-->
<child @myevent="handleChild"></child>
<p>定义变量接收子组件传回的数据:{{value}}</p>
</div>
</body>
<script>
Vue.component('child', {
// 【4】this.$emit('自定义事件名',传递的参数) 向父组件发送数据
template: `
<div><button @click="handleSend">向父组件中传数据</button></div>`,
methods: {
handleSend(){
this.$emit('自定义事件名',传递的参数)
}
}
})
var vm = new Vue({
el: '#app',
data: {
value: '', // 【2】定义一个变量接收子组件传入的数据
},
methods: {
// 【3】在父组件中定义方法接收并处理子组件的数据
handleChild(value) {
this.value = value
}
},
})
</script>
【2.2】示例
<body>
<div id="app">
<!-- 在子组件标签内定义自定义事件-->
<child @myevent="handleChild"></child>
<p>子组件向父组件传递的数据:{{value}}</p>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div><button @click="handleSend">向父组件中传数据</button></div>`,
methods: {
handleSend(){
// 可以传子组件中的变量
this.$emit('myevent','data from son')
// this.$emit('自定义事件名',传递的参数)
}
}
})
var vm = new Vue({
el: '#app',
data: {
value: '', // 定义一个变量接收子组件传入的数据
},
methods: {
// 在父组件中定义方法
handleChild(value) {
this.value = value
}
},
})
</script>
【3】ref参数
- 当
ref
被用在普通 HTML 元素上时,它会注册对应的 DOM 元素 - 当
ref
被用在组件标签上时,它会注册对应的子组件实例
<body>
<div id="app">
<div ref="normalLabel">普通标签</div>
<div>
组件标签
<child ref="childLabel"></child>
</div>
<p>
<button @click="handlePrint">看控制台输出内容</button>
</p>
</div>
</body>
<script>
let normalComponent = {
template: `
<div>组件</div>
`,
data() {
return {name: 'lea4ning'}
}
}
Vue.component('child', normalComponent)
var vm = new Vue({
el: '#app',
methods: {
handlePrint() {
console.log(this.$refs)
console.log('dom对象', this.$refs.normalLabel)
// 操作dom对象
this.$refs.normalLabel.style.color='red'
console.log('组件对象', this.$refs.childLabel)
console.log('组件中的属性', this.$refs.childLabel.name)
}
}
})
</script>
【八】动态组件
- 使用component标签,并指定【is】属性即可实现组件间切换
【1】使用演示
<component is='组件名'></component>
<body>
<div id="app">
<h1>动态组件</h1>
<p>使用按钮进行切换,什么方式均可,改变component的is的值即可</p>
<p><button @click="current='child1'">child1</button></p>
<p><button @click="current='child2'">child2</button></p>
<div>
<p>使用component标签,并指定【is】属性</p>
<component :is="current"></component>
</div>
<hr>
<div>
<p>也可以直接写个组件名,但就没有使用动态组件的必要了</p>
<component is="child1"></component>
</div>
</div>
</body>
<script>
let normalComponent1 = {
template: `
<div>组件1</div>
`
}
let normalComponent2 = {
template: `
<div>组件2</div>
`
}
// 注册多个全局组件
Vue.component('child1', normalComponent1)
Vue.component('child2', normalComponent2)
var vm = new Vue({
el: '#app',
data: {
current: ''
}
})
</script>
【2】使用keep-alive标签保持状态
<keep-alive>
<component is='xxx'></component>
</keep-alive>
<body>
<div id="app">
<h1>动态组件</h1>
<p>
<button @click="current='child1'">child1</button>
</p>
<p>
<button @click="current='child2'">child2</button>
</p>
<div>
<p>使用keep-alive标签包裹component标签即可实现状态保存</p>
<keep-alive>
<component :is="current"></component>
</keep-alive>
</div>
</div>
</body>
<script>
let normalComponent1 = {
template: `
<div>
<p>组件1</p>
<input type="text">
</div>
`
}
let normalComponent2 = {
template: `
<div>
<p>组件2</p>
<input type="text">
</div>
`
}
// 注册多个全局组件
Vue.component('child1', normalComponent1)
Vue.component('child2', normalComponent2)
var vm = new Vue({
el: '#app',
data: {
current: ''
}
})
</script>
【九】插槽
【1】5种插槽的基本模板
【1.1】默认插槽(Default Slot)
- 父组件模板:
<child-component>
<p>这是默认插槽的内容</p>
</child-component>
- 子组件模板:
<div>
<slot></slot>
</div>
【1.2】具名插槽(Named Slots):
- 父组件模板:
<div>
<child-component>
<template v-slot:header>
<h2>这是头部插槽的内容</h2>
</template>
<template v-slot:footer>
<p>这是底部插槽的内容</p>
</template>
</child-component>
</div>
- 子组件模板:
<div>
<header>
<slot name="header"></slot>
</header>
<footer>
<slot name="footer"></slot>
</footer>
</div>
【1.3】作用域插槽(Scoped Slots)
- 父组件模板:
<template>
<div>
<child-component v-slot:user="slotProps">
<p>{{ slotProps.name }}</p>
<p>{{ slotProps.age }}</p>
</child-component>
</div>
</template>
html复制代码
子组件模板:
<template>
<div>
<slot name="user" :name="user.name" :age="user.age"></slot>
</div>
</template>
<script>
export default {
data() {
return {
user: {
name: 'John',
age: 30
}
};
}
};
</script>
html复制代码
【1.4】作用域插槽的默认值(Scoped Slots with Default Value)
- 父组件模板:
<div>
<child-component>
<template #default="slotProps">
<p v-if="slotProps">{{ slotProps }}</p>
<p v-else>默认值</p>
</template>
</child-component>
</div>
- 子组件模板:
<template>
<div>
<slot :data="someData">默认值</slot>
</div>
</template>
<script>
export default {
data() {
return {
someData: '这是来自子组件的数据'
};
}
};
</script>
【1.5】动态插槽(Dynamic Slots)
- 父组件模板:
<template>
<div>
<child-component :slot-name="slotName">
<p>动态插槽的内容</p>
</child-component>
</div>
</template>
<script>
export default {
data() {
return {
slotName: 'header' // 或者根据条件动态设置
};
}
};
</script>
- 子组件模板:
<template>
<div>
<slot :name="slotName"></slot>
</div>
</template>
<script>
export default {
props: ['slotName']
};
</script>
【2】实例展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>插槽</title>
<script src="../js/vue/vue.js"></script>
</head>
<body>
<div id="app">
<h1>插槽</h1>
<h2>默认插槽</h2>
<child1><p>这是默认插槽的内容</p></child1>
<hr>
<h2>具名插槽</h2>
<child2>
<template v-slot:a>具名插槽:aaa</template>
<template v-slot:b>具名插槽:bbb</template>
</child2>
<hr>
<h2>作用域插槽</h2>
<child3 v-slot:person="slotProps">
<!-- v-slot:slot名="接收数据的变量-->
<p>{{ slotProps.obj.name }}</p>
<p>{{ slotProps.obj.age }}</p>
</child3>
<hr>
<h2>作用域插槽的默认值</h2>
<child4 v-slot:default="slotProps">
<!-- v-solt可以简写成【#】-->
<!-- <child4 #default="slotProps">-->
<p v-if="slotProps.age">{{ slotProps.age }}</p>
<p v-else>当slotProps没有数据,也就是组件中没有传递数据时,渲染默认值</p>
</child4>
<hr>
<h2>动态插槽</h2>
<child5 :slot-name="slotName">
<p>动态插槽:根据slot-name动态渲染到指定插槽</p>
</child5>
</div>
</body>
<script>
let normalComponent1 = {
template: `
<div>
<h3>组件1</h3>
<slot></slot>
</div>
`
}
let normalComponent2 = {
template: `
<div>
<h3>组件2</h3>
<p>slot-a:<slot name="a"></slot></p>
<p>slot-b:<slot name="b"></slot></p>
</div>
`
}
let normalComponent3 = {
template: `
<div>
<h3>组件3</h3>
<slot name="person" :obj="user"></slot>
</div>
`,
data() {
return {
user: {name: 'lea4ning', age: 20}
}
}
}
let normalComponent4 = {
template: `
<div>
<h3>组件4</h3>
<slot :age="isShow?user.age:undefined"></slot>
</div>
`,
data() {
return {
user: {name: 'lea4ning', age: 20},
// 使用变量动态表示渲染默认值或数据
isShow: true
}
}
}
let normalComponent5 = {
template: `
<div>
<h3>组件5</h3>
<slot :name="slotName"></slot>
</div>
`,
props:['slotName']
}
// 注册多个全局组件
Vue.component('child1', normalComponent1)
Vue.component('child2', normalComponent2)
Vue.component('child3', normalComponent3)
Vue.component('child4', normalComponent4)
Vue.component('child5', normalComponent5)
var vm = new Vue({
el: '#app',
data: {
slotName:'default'
}
})
</script>
</html>