vue基本概述
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。
Vue.js是一套构建用户界面的渐进式框架,采用自底向上增量开发的设计。Vue的核心库关注于视图(html),不仅易上手,还便于与第三方库或项目整合。
渐进式:一步一步,不是将所有的东西都学完才能使用。
自底向上设计:一种设计程序的过程和方法,就是先编写出基础程序段,然后在逐步扩大规范、补充和升级某些 功能,实际上是一种自底向上构造程序的过程。
Vue.js的核心是允许采用简洁式模板语法来声明的将数据渲染进DOM的系统
在使用数据之前需要先进性声明才可以使用
为什么要学习Vue?
简单,前端三大框架(Vue,React,angler)中是对小白最友好的框架
另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue基本语法
插值表达式
使用{{ }}进行渲染data:{}里面的变量
也可以是函数,不过在data里面的方法,在插值表达式中需要补充大括号
例如
<div id="app">
<div>{{ msg }}</div>
<div>{{ getInfo() }}</div>
</div>
<script src="../vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
msg: '枫枫知道',
getInfo() {
// 函数的返回值就是插值表达式中的结果
return "床前明月光"
}
}
})
</script>
在插值表达式中,支持运算符,以及一些方法
vue指令:
渲染文本,和插值表达式类似
v-text
<div v-text="msg"></div>
<div>{{ msg }}</div>
也是支持运算符的
<div v-text="2 > 4 ? '成立': '不成立'"></div>
v-html
渲染标签,如果字符串是含标签的特殊字符,那么vue会将它渲染成标签
如果是v-text或者是使用插值表达式,则会原样输出
注意:
v-html一般是用来渲染信任的文本,例如文章的详情内容等,最好不要用在用户提交的地方
容易造成XSS攻击
v-bind
可以给标签动态添加内容,也可以给动态的修改标签属性
不过在属性上的操作稍微和操作内容不太一样,我们使用v-bind指令
例如我想动态修改img标签的src属性,希望它去读取data里面的值
但是我们不能在属性中使用插值表达式
这样写src直接将我的内容原样输出了,所以我们需要使用v-bind,全称为动态属性
那么我可以这么做
<img v-bind:src="src" alt="">
当然,v-bind: 可以简写为 :
<img :src="src" alt="">
v-bind不仅可以用于HTML存在的属性,还可以应用在自定义属性上
例如
<p :id="'p' + '_01'" :data="msg" :还可以是中文="msg"></p>
实际结果:
<p id="p_01" data="haha" 还可以是中文="haha"></p>
在vue所有的指令中,都是支持表达式的
例如:
<div class="name">
{{ a.length === 0 ? '没有数据' : a }}
-{{ a.split('.')[1] }}
</div>
什么是表达式?
// 这是语句
var a = 1;
// 这是表达式
a.length === 0 ? '没有数据' : a
条件渲染
v-if和v-else的普通使用
v-if中的布尔值为true,则渲染这个div
如果if不成立,则渲染else中的代码块
<div id="app">
<div>{{ num }}</div>
<div id="if">
<div v-if="num > 0.9">大于0.9的概率</div>
<div v-else>v-if不满足显示我</div>
</div>
</div>
<script src="../vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: Math.random(), // 一个0-1之间的随机数字
}
})
</script>
v-else-if多条件语句
<div id="v-else-if">
<div v-if="num > 0.9">大于0.9的概率</div>
<div v-else-if="num > 0.6">大于0.6的概率</div>
<div v-else-if="num > 0.4">大于0.4的概率</div>
<div v-else-if="num > 0.2">大于0.2的概率</div>
<div v-else>所有条件都不成立</div>
</div>
v-if=”flag”,为true的时候显示
为false的时候消失
<div id="app">
<div class="name" v-if="flag">
{{ name }}
</div>
<div v-else>
if没匹配到就显示我
</div>
</div>
<script>
var vue = new Vue({
el: '#app', // vue挂载的位置,不能是body
data: {
flag: false,
name: '枫枫'
}
})
</script>
v-show与v-if的区别
v-if如果是false,不会渲染
v-show如果是false,不会显示 style=“display: none;”
体会一下v-if和v-show
列表渲染
主要分为遍历列表和遍历对象
遍历列表
lis: [
'张三',
'王伟',
'张伟',
'王五',
]
此时的item就是每个元素
<ul>
<li v-for="item in lis" :key="item">
{{ item }}
</li>
</ul>
key要唯一!!!
如果需要遍历出每个元素的索引
则在遍历的时候指定index
<ul>
<li v-for="(item, index) in lis" :key="item">
{{ index }} -- {{ item }}
</li>
</ul>
遍历对象
obj:{
name: '张三',
age: 21,
addr: '北京市',
}
一个参数,就是遍历对象的值
二个参数,值和键
三个参数,值,键,索引
<ul>
<li v-for="item in obj" :key="item">
对象的值:{{ item }}
</li>
</ul>
<ul>
<li v-for="(item, key) in obj" :key="item">
对象的值:{{ item }}
对象的键:{{ key }}
</li>
</ul>
<ul>
<li v-for="(item, key, index) in obj" :key="item">
对象的值:{{ item }}
对象的键:{{ key }}
变量的索引:{{ index }}
</li>
</ul>
Vue事件
v-on:或者@
<div id="app">
<div>
{{ num }}
</div>
<div>
<!-- 执行的方法必须在methods中-->
<button v-on:click="add">点我 +</button>
<button @dblclick="num--">点我 -1</button>
</div>
</div>
事件所执行的方法是要被定义在methods里面
methods: {
add() {
this.num ++
}
}
参数问题
可以通过传参进行参数传递
<button v-on:click="add(10)">点我 +</button>
...
add(number) {
this.num += number
}
// 此时的add函数就能接收到传递进来的参数值
默认参数
默认参数就是触发当前事件的事件对象
<button id="add" class="add_cls" v-on:click="add">点我 +</button>
一定是v-on:click=“add”,只写一个函数名,
而不是v-on:click=“add()”,这样获取不到事件对象
// 获取触发当前事件的标签
add(event) {
// 触发当前事件的事件对象
console.log(event)
// 获取标签
console.log(event.target)
// 获取id,class
console.log(event.target.id)
console.log(event.target.className)
}
如果有参数,想接收事件对象
使用$event进行传递
<button id="add" class="add_cls" v-on:click="add(10, $event)">点我 +</button>
...
add(number, event) {
this.num += number
// 触发当前事件的事件对象
console.log(event)
// 获取标签
console.log(event.target)
// 获取id,class
console.log(event.target.id)
console.log(event.target.className)
}
图片轮播案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图片轮播</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<div>
<img :src="img_list[index]" alt="">
</div>
<div>
<button @click="prevImag(index, img_list.length)">上一张</button>
<button @click="nextImag">下一张</button>
</div>
</div>
<script>
var vue = new Vue({
el: '#app', // vue挂载的位置,不能是body
data: {
index: 0,
img_list: [
'http://h2.ioliu.cn/bing/SalzburgKrampus_ZH-CN7355658592_640x480.jpg?imageslim',
'http://h2.ioliu.cn/bing/MistyTor_ZH-CN7520952555_640x480.jpg?imageslim',
'http://h2.ioliu.cn/bing/Koenigsbourg_ZH-CN7675452866_640x480.jpg?imageslim',
'http://h2.ioliu.cn/bing/CuvervilleIsland_ZH-CN9814166047_640x480.jpg?imageslim',
'http://h2.ioliu.cn/bing/ElanValley_ZH-CN9533069637_640x480.jpg?imageslim',
'http://h2.ioliu.cn/bing/WinterWaxwing_ZH-CN9435499385_640x480.jpg?imageslim',
]
},
methods: {
// 下一张
nextImag() {
// 让索引加1
// 判断是不是最后一张,如果是就回到第一张
if (this.index === this.img_list.length - 1) {
this.index = 0
return
}
this.index++
},
// 上一张
prevImag(index, len){
// 我希望把索引和列表长度传递进来
if (index === 0) {
this.index = len - 1
return
}
this.index --
}
}
})
</script>
</body>
</html>
事件修饰符
在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!--阻止默认事件-->
<a href="http://www.fengfengzhidao.com" @click.prevent="my_alert">枫枫知道</a>
事件冒泡
<div class="parent" @click="log('外元素')">
<div class="center" @click="log('中元素')">
<div class="child" @click="log('里元素')">
</div>
</div>
</div>
点击里元素,执行顺序
点击中间的元素
被父元素包裹的元素,点击事件发送后会逐级将事件向上传递
<p>阻止事件冒泡</p>
<div class="parent" @click="log('外元素')">
<div class="center" @click="log('中元素')">
<div class="child" @click.stop="log('里元素')">
</div>
</div>
</div>
添加stop事件修饰符之后,点击里元素,会阻止事件继续向上传播
键盘事件
@keydown 键盘按下
@keyup 键盘回弹
按下回车触发
支持组合键
<input type="text" v-model="msg" @keyup.enter.ctrl="get_msg('上')">
<input type="text" v-model="msg" @keyup.enter="get_msg('上')">
按键修饰符
最常见的可能就是在一个输入框中,判断用户是否按下了回车键
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
一些必要的按键名称
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
组合按键
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>
计算属性
调用的时候不用加括号(只是一个属性)
可以监听属性变化,属性变化,计算属性重新执行
并且有缓存(多个计算属性,只执行一次)
和methods的区别
属性变化,methods方法全部重新获取
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<div>{{ name }}</div>
<div>{{ name.split('').reverse().join('') }}</div>
<div>{{ name.length === 5 ? '五言绝句' : '七言绝句' }}</div>
<div v-if="name.length === 5">五言绝句</div>
<div v-else-if="name.length === 7">七言绝句</div>
<div v-else>错了</div>
<!-- 计算属性 -->
<div>{{ getName }}</div>
<div>{{ getName }}</div>
<div>{{ getName }}</div>
<div>{{ getName }}</div>
<div>{{ getName }}</div>
<div>{{ getName }}</div>
<div>{{ getName }}</div>
<div>{{ get_data_name() }}</div>
<div>{{ get_data_name() }}</div>
<div>{{ get_data_name() }}</div>
<div>{{ get_data_name() }}</div>
<div>{{ get_data_name() }}</div>
<button @click="getsub">
点我
</button>
<span>{{ num }}</span>
<button @click="set_name">计算属性</button>
</div>
<script>
var vue = new Vue({
el: '#app', // vue挂载的位置,不能是body
data: {
name: '床前明月光',
num: 0
},
methods: {
get_data_name() {
console.log('属性方法')
return this.name.split('').reverse().join('')
},
getsub(e) {
this.num ++
},
set_name(){
this.name += 'a'
}
},
computed: {
getName() {
console.log('计算属性')
return this.name.split('').reverse().join('')
}
}
})
</script>
</body>
</html>
computed与watch,methods的区别
methods:可以放入函数,并且没有缓存
watch:
监听,当数据发送变化时,才会触发
可以得到现在的值和过去的值
还可以监听路由变化
和属性同名
自定义过滤器
创建一个过滤器
// 自定义过滤器
filters:{
// 截取最后一个字符
getLastChar(item){
return item.substr(item.length-1,1)
}
}
使用过滤器
<li v-for="item in student_list" :key="item.id">
{{item.name|getLastChar }} -- {{ item.addr }}
</li>
时间过滤器
<div id="app">
<div>
当前时间:{{ now|get_date }}
</div>
<ul>
<li v-for="item in date_list" :key="item.id">
id:{{ item.id }} 时间:{{ item.date|get_date }}
</li>
</ul>
<div>
时间过滤
</div>
<ul>
<li v-for="item in date_list" :key="item.id">
id:{{ item.id }} 时间:{{ item.date|time_to_filter }}
</li>
</ul>
</div>
<script src="../vue.js"></script>
<script>
function getDateDiff(datestamp) {
var publishTime = datestamp / 1000,
d_seconds,
d_minutes,
d_hours,
d_days,
timeNow = parseInt(new Date().getTime() / 1000),
d,
date = new Date(publishTime * 1000),
Y = date.getFullYear(),
M = date.getMonth() + 1,
D = date.getDate(),
H = date.getHours(),
m = date.getMinutes(),
s = date.getSeconds();
//小于10的在前面补0
if (M < 10) {
M = '0' + M;
}
if (D < 10) {
D = '0' + D;
}
if (H < 10) {
H = '0' + H;
}
if (m < 10) {
m = '0' + m;
}
if (s < 10) {
s = '0' + s;
}
d = timeNow - publishTime;
d_days = parseInt(d / 86400);
d_hours = parseInt(d / 3600);
d_minutes = parseInt(d / 60);
d_seconds = parseInt(d);
if (d_days > 0 && d_days < 30) {
return d_days + '天前';
} else if (d_days <= 0 && d_hours > 0) {
return d_hours + '小时前';
} else if (d_hours <= 0 && d_minutes > 0) {
return d_minutes + '分钟前';
} else if (d_seconds < 60) {
if (d_seconds <= 0) {
return '刚刚发表';
} else {
return d_seconds + '秒前';
}
} else if (d_days >= 30) {
return Y + '-' + M + '-' + D + ' ' + H + ':' + m;
}
}
var vue = new Vue({
el: '#app',
data: {
now: '2021-12-8 22:01:11',
date_list: [
{id: 1, date: '2021-12-8 22:02:11'},
{id: 2, date: '2021-12-6 22:02:21'},
{id: 3, date: '2021-12-8 21:01:14'},
{id: 4, date: '2021-12-5 20:12:11'},
]
},
filters: {
// 年-月-日
get_date(date_str) {
// date,传递的参数
// 字符串转时间对象
let date = new Date(date_str)
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
},
time_to_filter(date_str) {
// 字符串->对象->时间戳
// 和当前时间做差,算出相差的时间(多少秒,多少分)
// 字符串转时间对象->时间戳
let datestamp = new Date(date_str).getTime()
return getDateDiff(datestamp)
}
}
})
</script>
参数问题
自定义过滤器也是可以接受参数,它的书写语法是
<li v-for="item in date_list" :key="item.id">
id:{{ item.id }} 时间:{{ item.date|time_to_filter('a', 'b') }}
</li>
...
filters: {
...
time_to_filter(date_str, a, b) {
// date_str -> '自身的值'
// a -> 'a'
// b -> 'b'
return date_str
}
}
过滤器方法的第一个参数就是调用者本身的值,第二个参数之后就是调用的实参
并且支持链式过滤器
<div>{{now|get_now|get_now1}}</div>
全局方法
需要将属性和方法挂载到Vue.prototype上
Vue.prototype.$com = "全局变量"
let global_method = ()=>{
return "全局方法"
}
function add(){
return "全局 add 方法"
}
Vue.prototype.$global_method = global_method
Vue.prototype.$add = add
使用
<div>
{{ $global_method() }}
</div>
<div>
{{ $add() }}
</div>
全局过滤器
// 全局过滤器
let global_filter = (item) => {
return item + '--global'
}
// 注册全局过滤器 (过滤器名称,方法)
Vue.filter('global_filter', global_filter)
使用全局过滤器
<div>
{{ $com|global_filter }}
</div>
局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>局部组件</title>
</head>
<body>
<div id="app">
<App></App> <!--使用子组件-->
</div>
<script src="../vue.js"></script>
<script>
// app 组件 html css js
const App = {
data() {
// 在组件中使用数据,需要 使用函数,返回值返回对象 data(){ return {} }
return {msg: 'hello'}
},
template: `
<div>
<h3>我是app组件</h3>
<p>{{ msg }}</p>
<button @click="handleClick">按钮</button>
</div>
`,
methods: {
handleClick() {
this.msg = 'world'
}
}
}
new Vue({
el: '#app',
data: {},
components: {
App // 挂载子组件
}
})
</script>
</body>
</html>
全局组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>局部组件</title>
</head>
<body>
<div id="app">
<App></App> <!--使用子组件-->
</div>
<script src="../vue.js"></script>
<script>
// app 组件 html css js
// 只要创建组件,就可以在template中使用
Vue.component('Vheader', {
template: `
<div>
<span>我是导航组件</span>
</div>
`
})
Vue.component('Vfooter', {
template: `
<div>
<span>我是底部组件</span>
</div>
`
})
Vue.component('Vsider', {
data() {
return {msg: '侧边栏'};
},
template: `
<div>
<span class="sider_title">我是侧边栏组件</span>
<span>{{ msg }}</span>
</div>
`,
})
const Vbtn = {
template: `
<button>按钮</button>
`
}
const App = {
data() {
// 在组件中使用数据,需要 使用函数,返回值返回对象 data(){ return {} }
return {msg: 'hello'}
},
template: `
<div>
<Vheader></Vheader>
<Vbtn></Vbtn>
<Vbtn></Vbtn>
<Vbtn></Vbtn>
<Vsider></Vsider>
<Vfooter></Vfooter>
<h3>我是app组件</h3>
<p>{{ msg }}</p>
<button @click="handleClick">按钮</button>
</div>
`,
components: {
Vbtn
},
methods: {
handleClick() {
this.msg = 'world'
}
}
}
new Vue({
el: '#app',
data: {},
components: {
App // 挂载子组件
}
})
</script>
</body>
</html>
组件通信
父传子
父传子:通过props来进行通信
- 在自组件中声明props接收在父组件挂载的属性
- 可以在自组件的template在任意使用
3, 在父组件绑定自定义的属性
props传入一个对象
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
props: {
data: {
type: String, // 类型
required: true, // 必填项
default: '张三' // 如果没传值,那么这个默认值就是它
}
}
<div id="app">
<App></App> <!--使用子组件-->
</div>
<script src="../vue.js"></script>
<script>
Vue.component('Child', {
template: `
<div>
<h3>我是子组件</h3>
<h4>{{ childData }}</h4>
</div>
`,
props: ['childData']
})
const App = {
data() {
// 在组件中使用数据,需要 使用函数,返回值返回对象 data(){ return {} }
return {msg: '我是父组件传递的值'}
},
template: `
<div>
<Child :childData="msg"></Child>
<p>{{ msg }}</p>
</div>
`,
}
new Vue({
el: '#app',
data: {},
components: {
App // 挂载子组件
}
})
</script>
created与mounted
created(){
console.log(this.data, 1)
},
mounted(){
console.log(this.data, 2)
}
子传父
- 在父组件中,自组件上绑定自定义事件
- 在自组件中,触发原生的事件,在事件函数通过this.$emit触发自定义的事件
父组件
<comment1 v-on:eff="eff"></comment1>
components: {
comment1
},
methods: {
eff(data) {
// data 是子组件传递的数据
console.log('父组件被调用了', data)
}
}
子组件
let comment1 = {
template: `
<div>
<ul>
<li>兰州拉面</li>
<li>哈尔滨啤酒</li>
<li>四川担担面</li>
<button @click="add">点我触发父组件方法</button>
</ul>
</div>`,
methods: {
add() {
this.$emit('eff', {name: '子组件传来的数据'})
}
}
}
平行组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>平行组件</title>
<style>
body {
margin: 0;
}
#app {
display: flex;
}
#app > div {
width: 50%;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
}
#gouwuc {
background-color: #3a8ee6;
}
#get {
background-color: #b3d9d9;
}
</style>
</head>
<body>
<div id="app">
<App1 id="gouwuc"></App1> <!--使用子组件-->
<App2 id="get"></App2> <!--使用子组件-->
</div>
<script src="../vue.js"></script>
<script>
let Bus = new Vue()
let App1 = {
data() {
return {
num: 100
}
},
template: `
<div>
购物车 商品总数{{ num }}
</div>`,
mounted(){
Bus.$on('add', (data)=>{
this.num ++
})
}
}
let App2 = {
data() {
return {
num: 100
}
},
methods: {
add() {
Bus.$emit('add', {msg: '你的好兄弟又下单啦'})
}
},
template: `
<div>
<button @click="add">加入购物车</button>
</div>`
}
new Vue({
el: '#app',
data: {},
components: {
App1,
App2,
}
})
</script>
</body>
</html>
多次嵌套取值
1. provide 提供变量 函数(){return {} },
2. inject 接收变量 inject: [],
匿名插槽
let base_layout = {
data() {
return {}
},
template: `
<div>
<header>
<slot>我是页头</slot>
</header>
</div>`
}
new Vue({
el: '#app',
components: {
base_layout
}
})
在模板中把想要替换的东西放在标签中,这就是一个占位符
<base_layout>实际的内容</base_layout>
这样就会将标签中的内容去代替slot中的内容
如果slot都没有名字,那么如果有多个slot,就会全部进行替换
具名插槽
如果你的模板中需要有多个地方被替换
那么匿名插槽就不太合适了,我们给每个插槽都起一个别名
let base_layout = {
data() {
return {}
},
template: `
<div>
<header>
<slot name="header">我是页头</slot>
</header>
<main>
<slot name="main">我是内容</slot>
</main>
<footer>
<slot name="footer">我是页脚</slot>
</footer>
</div>`
}
这样我们在进行替换的时候,指明要替换哪个slot就OK了
<base_layout>
<template v-slot:header>
头部
</template>
<template v-slot:main>
身体
</template>
<template v-slot:footer>
尾部
</template>
</base_layout>
注意v-slot的写法
v-slot:header
v-slot: 可以简写为 #
<base_layout>
<template v-slot:header>
<child></child>
<div>
哈哈哈哈
</div>
</template>
<template #main>
身体
</template>
<template v-slot:footer>
尾部
</template>
</base_layout>
我们在替换的时候,是可以写任意标签的,也就是说,在替换的时候,你也可以将组件写入插槽中
<base_layout>
<template v-slot:header>
<child></child>
<div>
哈哈哈哈
</div>
</template>
<template v-slot:main>
身体
</template>
<template v-slot:footer>
尾部
</template>
</base_layout>
作用域插槽
let base_layout = {
data() {
return {
user: {
name: '枫枫',
xin: '知道'
}
}
},
template: `
<div>
<main>
<slot :user="user">{{ user.xin }}</slot>
</main>
</div>`
}
在子组件中,我在插槽里面显示的是user的xin,如果我想让它显示user的name应该怎么做呢
如果我们直接在父组件调用的时候这样写
<base_layout>
{{ user.name }}
</base_layout>
这是错误的写法,因为我们的user是被定义再自组件中的,在父组件中就无法使用这个user,所以就会报错啦
那么我们就应该将这个user对象传递给父组件
在子组件中
<slot :user="user">{{ user.xin }}</slot>
通过动态属性的方式将user传递给父组件
在父组件中
<base_layout>
<template v-slot:default="slotProps">
{{ slotProps.user.name }}
</template>
</base_layout>
接收传递来的user即可
slotProps可以是你自己定义的名字,它里面存储的是这样的
{ "user": { "name": "枫枫", "xin": "知道" } }
所以我们将slotProps中的user中的name传递给子组件,就可以做到数据动态替换
如果你的组件中,有且只有一个默认插槽,那么在替换的时候,是可以这么做的
<base_layout v-slot:default="slotProps">
{{ slotProps }}
</base_layout>
但是,如果出现了具名插槽,这样会导致作用域混乱
我们应该这样使用
let base_1 = {
data(){
return {
user: {
name: '枫枫知道',
age: 21
}
}
},
template: `
<div>
<header>
我的名字是 <slot :user="user" name="name">{{ user.name }}</slot>,年龄是<slot :user="user" name="age">{{ user.age }}</slot>
</header>
</div>`
}
<base_1>
<template v-slot:name>张子枫</template>
<template v-slot:age="slotBase">{{ slotBase }}</template>
</base_1>
动态组件
元素是vue 里面的一个内置组件。
在里面使用 v-bind: is,可以实现动态组件的效果。
自定义指令
前面使用的v-if, v-show,以及v-for这些都是Vue为我们提供的内置指令
当然,我们也可以自己自定义一个指令
局部自定义指令
directives: {
focus: {
// 指令的定义
// 使用这个指令就会聚焦在输入框中
inserted: function (el) {
el.focus()
}
}
}
使用
<input type="text" v-focus>
在focus中有几个钩子函数,需要了解
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。