01-v-model语法糖
-
v-model本质上是 value属性和input事件的一层包装
-
v-model的作用:提供数据的双向绑定
-
数据发生了改变,页面会自动变 v-bind:value
-
页面输入改变 , 数据会自动变化 v-on:input
-
-
v-model是语法糖, v-model等价于 给一个input框提供了 :value属性以及 @input事件
很显然如果每次使用input框,都需要提供value和input事件,比较麻烦,所以使用v-model
<template>
<div>
<h1>根组件App.vue</h1>
<!--
1.v-model = "msg"
(1)data中的数据变化,表单的值也会变化 :value="msg"
(2)表单的值发生变化,data中的数据也会变化 @input="msg=$event.target.value"
-->
<input type="text" v-model="msg" />
<hr />
<!-- 这种写法与上面写法功能一致 -->
<input type="text" :value="msg" @input="msg = $event.target.value" />
<hr />
<!-- 这种写法也与上面写法一致 -->
<input type="text" :value="msg" @input="doInput" />
<hr />
</div>
</template>
<script>
export default {
data() {
return {
msg: ""
};
},
methods: {
doInput(e) {
this.msg = e.target.value;
}
}
};
</script>
<style>
</style>
02-组件使用v-model
-
我们经常遇到一种场景:
-
父组件提供一个数据给子组件使用(父传子)
-
子组件又需要修改父组件传过来的这个数据,所以需要子传父把值传给父组件。
-
-
这种场景可以使用v-model进行简写。
-
定义组件的时候,注意接收的值叫value, 子传父触发的事件叫 input
-
如果父传子的props值叫 value, 且 子传父触发的事件叫 input 。 那么这两个功能就可以使用v-model来简写
-
03-ref和$refs(vue操作dom)
-
ref作用:在vue中操作dom元素或组件vm实例
-
vue不推荐我们直接操作dom。如果真的要在vue中操作dom,可以使用ref语法
-
说人话 : vue不能直接操作dom,真的要操作也要按vue规定的语法来。(ref语法)
-
-
-
每个 vue 的组件实例上,都包含一个$refs 对象,里面存储着对应的DOM 元素或组件的引用。
ref语法使用流程语法
(1)给标签添加自定义属性red :
<button ref="属性名"></button>
vue会自动把页面所有的ref属性,挂载到vue实例的$ref对象中
(2)通过
vm.$refs.属性名
获取该标签
一定要注意
: vue在mounted勾子中完成页面真实DOM渲染,所以最早能获取dom的就是mounted钩子
ref易错点
1.添加的的时候是:
ref
2.获取的时候是:
$refs
1 给需要获取的 dom 元素或者组件, 添加 ref 属性
<template>
<div>
<h1>根组件App.vue</h1>
<div ref="box">我是div盒子</div>
<Goods ref="goods"></Goods>
<button @click="fn">点我获取ref</button>
</div>
</template>
2 通过 this.$refs.xxx
获取, 拿到组件可以调用组件的方法
<script>
//导入子组件
import Goods from "./components/Goods.vue";
export default {
//注册组件
components: { Goods },
//方法
methods: {
fn() {
// 如果ref给dom元素添加,获取的就是dom对象
console.log(this.$refs.box);//DOM对象
// 如果ref给组件添加,获取的就是组件vm实例
console.log(this.$refs.goods);//组件vue实例
this.$refs.goods.sayHi();
}
}
};
</script>
子组件代码Goods.vue
<template>
<div>
<h2>我是子组件</h2>
</div>
</template>
<script>
export default {
methods: {
sayHi(){
console.log('你好我是子组件')
}
},
}
</script>
<style>
</style>
04-$nextTick使用
<template>
<div>
<!-- 需求1: 点击按钮, 切换显示输入框
需求2: 显示输入框的同时, 要获取焦点
-->
<input type="text" v-if="showInput" ref="inp">
<button @click="fn" v-else>点此搜索</button>
</div>
</template>
<script>
export default {
data () {
return {
showInput: false
}
},
methods: {
fn () {
// 显示输入框
this.showInput = true
// 输入框获取焦点
/* 报错原因:
(1) vue更新DOM是一个异步的过程。(虽然设置了showInput为true,但是不会立即显示输入框)
(2) 异步代码需要等当前队列同步代码全部执行完毕之后才会执行
解决方案:
this.$nextTick(callback) : 会等组件的DOM刷新之后再来执行callback回调函数
*/
// this.$refs.inp.focus() // 报错
this.$nextTick( ()=>{
this.$refs.inp.focus()
} )
}
}
}
</script>
<style>
</style>
05-dynamic动态组件
什么是动态组件: 让多个组件使用同一个挂载点,并动态切换,这就是动态组件。
-
混淆点解读:动态组件 看起来和v-if v-else功能有些类似,但其实两者是不同的。
-
v-if v-else : 只是根据条件来决定渲染哪一个盒子,不能像组件那样复用。
-
动态组件:通过设置组件名,让一个挂载点可以切换不同的组件
-
06-自定义指令
-
1.添加一个自定义指令
v-focus
,作用是让input表单自动聚焦 -
2.添加一个自定义指令
v-color
,作用是设置标签文本颜色
<template>
<div>
<h1>根组件</h1>
<!-- 使用指令 v-指令名 -->
<input type="text" v-focus/>
<br />
<p v-color=" bgc ">我是p标签,我使用了自定义指令v-red</p>
</div>
</template>
<script>
export default {
data() {
return {
bgc:'green'
}
},
//自定义指令都写在这个对象里面
directives: {
//1.指令名: focus
focus: {
// inserted(el) : 当指令被使用的时候会执行一次
inserted(el) {
//el : 你的指令写在哪一个标签上,这个el就是标签dom对象
el.focus()
},
},
//2.指令名: color
color: {
inserted(el,binding) {
console.log(el)//指令所绑定的元素
console.log(binding)//一个对象,包含指令名、指令值等数据
console.log(binding.value)//指令值
el.style.color = binding.value
},
// update(el,binding) : 当指令的值发生改变时触发
update(el,binding) {
console.log(el,binding)
el.style.color = binding.value
},
}
}
}
</script>
<style></style>
1.2-自定义指令:全局注册
全局注册: 在main.js中注册,任何地方可用
// 全局指令 - 任何组件内"直接"使用
Vue.directive("focus", {
inserted(el) {
el.focus() // 触发标签的事件方法
}
})
07-slot匿名插槽
插槽使用2个步骤
第一步:在子
组件中定义一个插槽 <slot>默认值:如果父组件没有传递则默认显示</slot>
第二步:在父
组件中传递结构: <子组件>父组件需要传递的结构</子组件>
子组件goods.vue
<template>
<div class="son">
<h3>我是子组件</h3>
<h4>商品名称</h4>
<!-- 插槽:可以让父组件决定这里放什么。 也可以设置默认值 -->
<slot>我是默认值</slot>
</div>
</template>
<script>
export default {
name: "goods",
data() {
return {}
}
}
</script>
<style scoped>
.son {
border: 1px solid red;
}
</style>
父组件App.vue
<template>
<div id="app">
<h1>我是父组件</h1>
<!-- 子组件1:插入购买链接 -->
<goods>
<button>
<a href="http://www.jd.com">点击购买</a>
</button>
</goods>
<!-- 子组件2:插入禁用点击的按钮 -->
<goods>
<button disabled>已卖完</button>
</goods>
<!-- 子组件3:没有插入内容,则显示默认插槽 -->
<goods></goods>
</div>
</template>
<script>
//导入局部组件
import goods from "./components/goods.vue"
export default {
data() {
return {}
},
components: {
goods
}
}
</script>
<style>
#app {
border: 1px solid #000;
}
</style>
08-slot具名插槽
-
1.插槽作用: 父组件
传递html结构
给子组件-
给所有slot分发相同内容
-
-
2.具名插槽作用: 父组件
传递多个html结构
给子组件-
给不同slot分发不同内容
-
具名插槽语法如下
1.给子组件的<slot>添加name属性 :
name="插槽名"
2.父组件使用
v-slot:插槽名
: 给指定的插槽传递结构
注意:这个v-slot指令必须要写在
<template>
标签中,否则会报错
<template>
是HTML5新增的一个语义化标签,模板的意思。 这个标签本身不会被渲染,因此最终在页面是看不见的。 这个标签类似于div,就是一个空盒子容器。 与div唯一的区别就是它不会渲染。
vue中并不是所有的指令都能简写,有简写符号的指令主要有三个
v-on 指令 可以简写成
@
v-bind指令 可以简写成
:
v-slot指令 可以简写成
#
子组件cell.vue
<template>
<div class="cell">
<div class="title" >
<slot name="a">我是标题</slot>
</div>
<div class="content" >
<slot name="b">我是内容</slot>
</div>
<div class="right" >
<slot name="c">我是图标</slot>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style>
.cell{
border: 1px solid #f00;
height: 60px;
padding: 10px;
position: relative;
}
.title{
float: left;
}
.content{
position: absolute;
bottom: 10px;
left: 10px;
}
.right{
float: right;
}
</style>
父组件
<template>
<div id="app">
<h1>我是父组件</h1>
<cell>
<template v-slot:a>
<strong>我是h3</strong>
<span>标题内容</span>
</template>
<template v-slot:b>
<a href="#">我是链接</a>
</template>
<template #c>
<button>我是按钮</button>
</template>
</cell>
</div>
</template>
<script>
//导入局部组件
import cell from "./components/cell.vue"
export default {
data() {
return {}
},
components: {
cell
}
}
</script>
<style>
#app {
border: 1px solid #000;
}
</style>
09-v-slot作用域插槽(难点)
1.插槽与props的异同点
相同点: 都是父传子
不同点:
props: 传递的是数据
插槽:传递的是html结构
2.作用域插槽和$emit异同点
相同点:都是子传父
不同点:
$emit : 子传父的数据通过事件来接收
作用域插槽:子传父的数据是通过插槽v-slot接收 (子传父的数据,只能给插槽用)
-
1.插槽作用:父组件 传递
html结构
给 子组件 -
2.具名插槽作用:父组件 传递
多个html结构
给 子组件 -
3.作用域插槽作用:父组件 给 子组件 传递插槽 时,可以使用子组件内部的数据
作用域插槽语法如下
1.给子组件的<slot>添加一个自定义属性 :
<slot :属性名="属性值" ></slot>
2.给父组件的<template>添加v-slot属性接收数据:
<template v-slot="对象名"></template>
父组件使用子组件内部数据语法:
对象名.属性名
注意点
: 不要把具名插槽语法
和作用域插槽
语法搞混淆具名插槽:
<template v-slot:name值></slot>
作用域插槽:
<template v-slot="对象名"></slot>
父组件
<template>
<div>
<!--
1.匿名插槽 : 父组件传递 一个html结构 给子组件
(1)子组件: <slot> 插槽默认内容 </slot>
(2)父组件: <子组件> html结构 </子组件>
2.具名插槽 : 父组件传递 多个html结构 给子组件
(1)子组件: 给插槽添加一个name(插槽名)
<slot name="插槽名"> 插槽默认内容 </slot>
(2)父组件: 使用 v-slot:插槽名 或 #插槽名
<子组件>
<template v-slot:插槽名>
html结构
</template>
</子组件>
3.作用域插槽: 子组件传递 数据 给父组件插槽
(1)子组件 : 给<slot>内置组件添加自定义属性
<slot 属性名="属性值" > 插槽默认内容 </slot>
(2)父组件 : 使用 v-slot="对象名"
-->
<scope>
<template v-slot="obj">
<p>{{ obj.a }}</p>
<p>{{ obj.b }}</p>
<p>{{ obj.c }}</p>
</template>
</scope>
</div>
</template>
<script>
//导入局部组件
import scope from './components/scope.vue'
export default {
//注册组件
components: {
scope
},
data() {
return {
}
},
};
</script>
<style>
#app {
border: 1px solid #000;
}
</style>
子组件
<template>
<div class="box">
<h2>学习作用域插槽</h2>
<input v-model="msg" type="text" placeholder="输入搜索内容">
<br>
<!-- 定义插槽 -->
<slot a="1" b="2" :c="msg"> 插槽默认内容 </slot>
</div>
</template>
<script>
export default {
data() {
return {
msg:''
}
},
}
</script>
<style scoped>
.box{
border: 1px solid #000;
}
</style>