Vue - 6 组件与属性

Vue - 6 组件与属性


1.Vue组件

image-20230217145541570

在 Vue.js 中,组件是一种可复用的 Vue 实例,可以定义自己的模板、样式和逻辑,并且可以被其他 Vue 实例复用。使用组件可以将复杂的页面分解为多个独立的小组件,从而使代码更加简洁、可维护、可复用。

组件可以通过 Vue.component() 方法进行注册,也可以使用 .vue 文件进行定义。在注册组件时,需要指定组件的名称和组件选项。

组件选项包括组件的数据data【但是data需要写成函数的形式,并且将数据在return中返回】、模板template、方法methods、生命周期钩子函数等。定义好组件之后,就可以在其它 Vue 实例中使用该组件了。

(1)全局组件

通过Vue.component()方法进行注册的组件,被称之为全局组件

全局组件放在Vue实例【根组件】中

Vue.component('my-component', {
data: function () {
return {
message: 'Hello Vue!'
}
},
template: '<div>{{ message }}</div>'
})

(2)局部组件

在Vue实例中定义或者全局组件中定义的,以关键字components:{}中注册的组件,称之为局部组件。

局部组件常用的方式:是用一个变量名接收后,通过注册在不同的【全局组件】中或【根组件】中重复使用。

  • 案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- vue 文件 -->
<script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
<my-component>
</my-component>
</div>
</body>
<script>
// 定义全局组件
Vue.component('my-component', {
// data需要以方法的形式出现,data中的数据可以重复使用
data() {
return {
name: 'duoduo',
show: false,
}
},
// 在全局中设计局部组件
template: `
<div>
<button @click="handleShow">展示名字</button>
<sections></sections>
<div v-if="show">名字{{ name }}</div>
</div>`,
methods: {
handleShow() {
this.show = !this.show
}
},
// 局部组件
components: {
sections: {
template: `
<div>
<div>年龄{{ age }}</div> </div>
`,
data() {
return {
age: 19
}
},
},
}})
let vm = new Vue({
el: '.app',
data: {},
methods: {},
})
</script>
</html>

2.组件注意

注意点:

(1)根组件

定义的组件(body中的位置)必须要放在Vue实例【这也是一个组件:根组件】中,new Vue()管理的div通常被称为根组件

(2)局部组件无法单独使用

必须放在全局组件/根组件中,无法单独使用

(3)定义的组件的位置

定义的组件必须放在Vue实例的上方,在渲染的时候,组件必须已经加载完毕

(4)组件中的配置项

  • 相同点:都有 数组、模版、方法等

组件选项包括组件的数据data【但是data需要写成函数的形式,并且将数据在return中返回】、模板template、方法methods、生命周期钩子函数等

①②③④⑤⑥⑦⑧

  • 不同点:

①data在组件中要写成函数的形式,数据在return中以返回值的形式返回

②在组件中this指代的不再是Vue实例,而是组件对象

③父子组件的data是无法共享的

(5)自定义组件需要有1个根标签

自定义组件需要有1个 root element,一般包裹在 1个div

3.组件间通信

组件间的数据是相互隔离的,无法共享。但是对于不同关系的组件间通信,Vue给出了不同的方法。

1.父传子:自定义属性

通过在子组件中【自定义属性】,就可以在子组件中通过【插值语法】来获得父组件的数据

(1)props关键字来声明需要通信的数据

  • props属性验证

通过给props传一个对象,键是变量,值是数据类型,则可以限制变量的类型

props:{age:Number}

(2)父传子:自定义属性

父传子使用自定义属性

<child :自定义属性="变量"></child>

1.自定义属性不可以使用驼峰体

2.父子组件之间,避免出现变量名冲突

  • 案例
<body>
<div class="app">
<child :name1="name1"></child>
</div>
</body>
<script>
// 定义子组件
let child = {
data() {
return {
mymsg: '这里是子组件的msg'
}
},
template: `
<div style="background-color: cornflowerblue">
<h2>我是子组件</h2>
<p>父传子:{{ name1 }}</p>
</div>
`,
// 通过props配置项来声明 父组件传给子组件的值,并且可以限定数据的类型
props:{name1:String},
}
// vue实例
let vm = new Vue({
el: '.app',
data: {
name1:'我是根组件',
},
// 在父组件中注册子组件
components:{
child
}
})
</script>

2.子传父:自定义事件

(1)在子组件中自定义事件,但是该自定义事件绑定的函数写在父组件的methods方法

<父组件>
<child @自定义事件="函数"></child>
</父组件>

(2)在子组件中,通过$emit方法触发一个自定义事件,会执行父组件自定义事件绑定的函数

// 定义局部组件
var child = {
...
// 子组件中的方法,通过$emit方法触发一个自定义事件,并传递数据。
methods: {
mySend(){
this.$emit('myroot',this.msg)
}
},
}

(3)在父组件的methods方法中,将子组件传过来的数据值赋值给父组件中对应的值

var vm = new Vue({
el: '.app',
data: {
name:'根组件',
// 一定要定义一个变量来接受子组件传递过来的值
msg:''
},
methods: {
// 自定义事件,触发后,将子组件传过来的数据值赋值给父组件中对应的值
// 即可完成子组件给父组件传值
getMsg(msg){
this.msg = msg
console.log(msg)
}
},
components: {
child
}
})
  • 案例
<body>
<div class="app">
<h4>这里是根组件:{{msg}}</h4>
<h4>根组件:{{name}}</h4>
// 在子组件中自定义事件,通过触发事件来传递数据
<child @myroot="getMsg"></child>
</div>
</body>
<script>
// 定义局部组件
var child = {
// 在模版中定义方法,通过点击事件来使用$emit方法触发一个自定义事件,并传递数据
template: `
<div>
<h3>##-- {{ msg }} --##</h3>
<button @click="mySend">点击发送</button>
</div>
`,
// 定义在子组件中需要传递的数据,必须要return出去数据
data() {
return {
msg: '来自子组件'
}
},
// 子组件中的方法,通过$emit方法触发一个自定义事件,并传递数据。
methods: {
mySend(){
this.$emit('myroot',this.msg)
}
},
}
var vm = new Vue({
el: '.app',
data: {
name:'根组件',
msg:''
},
methods: {
// 子定义事件,触发后,将子组件传过来的数据值赋值给父组件中对应的值
// 即可完成子组件给父组件传值
getMsg(msg){
this.msg = msg
console.log(msg)
}
},
components: {
child
}
})
</script>

3.ref属性

自定义属性和自定义事件可以实现父子传值,但是通过vue提供的ref属性,可以更方便的事项父子组件间的通信

因此不需要关注是子传父,还是父传子,直接通过ref属性获取组件对象即可

(1)ref属性放在普通标签上,拿到标签的dom对象

ref属性放在普通标签上,通过this.$refs可以拿到所有写了ref属性的标签

vue将其封装成了对象,keyref属性对应的变量名,value原生dom对象,则可以通过ref属性直接修改原生dom对象的属性

(2)ref属性放在组件上,拿到组件对象

通过this.$refs.组件名,拿到组件对象,既可以拿到组件的属性,也可以拿到组件的方法

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- vue 文件 -->
<script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
<h3>根组件---{{msg}}</h3>
根组件中的input框:<input type="text" ref="myinput">
<button @click="mySend">【父传子】发送消息</button>
<hr>
<h3>根组件中的子组件</h3>
<child ref="mychild"></child>
<hr>
</div>
</body>
<script>
// 定义局部组件
var child = {
template: `
<div>
<p ref="childp">{{msg}}</p>
<h3>子组件中的信息##-- {{ msg }} --##</h3>
<button @click="mySend">【子传父】发送消息</button>
</div>
`,
data() {
return {
msg:"一条来自子组件的信息",
name:'子组件的信息'
}
},
methods: {
mySend(){
// alert(this.name)
this.$emit('fu',this.msg)
// this.msg=this.$refs..msg
},
},
}
var vm = new Vue({
el: '.app',
data: {
msg: '来自根组件'
},
methods: {
mySend() {
console.log(this.$refs)
},
fu(msg){
console.log(msg)
}
},
// 在跟组件中注册子组件
components: {
child
}
})
</script>
</html>

4.动态组件

(1)原始

绑定点击事件,并且通过 v-if判断来显示不同的页面

<body>
<div class="app">
<span @click="handleClick('home')">首页</span>| <span @click="handleClick('order')">订单</span> | <span
@click="handleClick('goods')">商品</span>
<home v-if="chooseType=='home'"></home>
<order v-else-if="chooseType=='order'"></order>
<goods v-else></goods>
</div>
</body>
<script>
var home = {
template: `
<div>
<h1>home页面</h1>
</div>`,
}
var order = {
template: `
<div>
<h1>order页面</h1>
</div>`,
}
var goods = {
template: `
<div>
<h1>商品页面</h1>
</div>`,
}
var vm = new Vue({
el: '.app',
data: {
chooseType: 'home'
},
methods: {
handleClick(type) {
this.chooseType = type
}
},
components: {
home,
order, goods
}
})
</script>

(2)动态组件:component标签

通过component标签,绑定对应的数据值,根据组件对应的值不同来显示不同的组件

<body>
<div class="app">
<span @click="handleClick('home')">首页</span>| <span @click="handleClick('order')">订单</span> | <span
@click="handleClick('goods')">商品</span>
<!-- 通过component标签,绑定is属性来动态判断-->
<component :is="who"></component>
</div>
</body>
<script>
var home = {
template: `
<div>
<h1>home页面</h1>
</div>`,
}
var order = {
template: `
<div>
<h1>order页面</h1>
</div>`,
}
var goods = {
template: `
<div>
<h1>商品页面</h1>
</div>`,
}
var vm = new Vue({
el: '.app',
data: {
// data中绑定 component标签对应的value值,来通过value值的不同来显示不同页面
who: 'home'
},
methods: {
handleClick(type) {
this.who = type
}
},
components: {
home,
order,
goods
}
})
</script>
</html>

(3)keep-alive:防止销毁组件

当组件部分的input框中,我们有输入的内容时,切换组件后,该内容会被销毁。而通过keep-alive标签,将component标签包裹起来后,key保持组件活跃状态不被销毁

<body>
<div class="app">
<span @click="handleClick('home')">首页</span>| <span @click="handleClick('order')">订单</span> | <span
@click="handleClick('goods')">商品</span>
<!-- 用keep-alive来包裹,保持组件活跃状态不被销毁-->
<keep-alive>
<component :is="who"></component>
</keep-alive>
</div>
</body>
<script>
var home = {
template: `
<div>
<h1>home页面</h1>
</div>`,
}
var order = {
template: `
<div>
<h1>order页面</h1>
<input type="text">输入的内容
</div>`,
}
var goods = {
template: `
<div>
<h1>商品页面</h1>
</div>`,
}
var vm = new Vue({
el: '.app',
data: {
// data中绑定 component标签对应的value值,来通过value值的不同来显示不同页面
who: 'home'
},
methods: {
handleClick(type) {
this.who = type
}
},
components: {
home,
order,
goods
}
})
</script>

5.插槽

通过在组件内添加<slot></slot>标签,就可以在组件标签内添加不同的内容,并插在<slot></slot>标签的位置,增加组件的拓展性

(1)匿名插槽

<body>
<div class="app">
<home>
<div>
<h2>我是插槽!!!</h2>
</div>
</home>
</div>
</body>
<script>
let home = {
template: `
<div>
<h1>home页面开始</h1>
<slot></slot>
<slot></slot>
<h1>home页面结束</h1>
</div>`,
}
let vm = new Vue({
el:'.app',
data:{},
components:{
home
}
})
</script>

(2)具名插槽

通过在<slot name='xxx'></slot>标签中的name属性给插槽起名字,并在想要添加在插槽内的标签添加 slot="xxx",指定插入的标签,当存在多个插入的标签时,可以通过名字来管理

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- vue 文件 -->
<script src="js/vue.js"></script>
</head>
<body>
<div class="app">
<home>
<div slot="a">
<h2>我是插槽AAA</h2>
</div>
<div slot="b">
<h2>我是插槽BBB</h2>
</div>
</home>
</div>
</body>
<script>
let home = {
template: `
<div>
<h1>home页面开始</h1>
<slot name="a"></slot>
<slot name="a"></slot>
<h1>home页面结束</h1>
</div>`,
}
let vm = new Vue({
el:'.app',
data:{},
components:{
home
}
})
</script>
</html>

6.计算属性

计算属性是一种特殊的属性,计算属性的值是基于现有的状态计算得出的,并且只有在其依赖的状态发生变化时才会重新计算

(1)特性

1.延缓计算,只有发生依赖关系也就是只有使用的变量发生变化时候,才重新计算

2.可以将方法当做属性来用

(2)定义方式

通过配置项的关键字computed来定义

computed: {
// 计算属性的名称
propertyName () {
// 计算属性的计算逻辑
// 可以使用 this 来访问组件的状态
return computedValue;
}
}

计算属性的值可以通过在模板中使用该属性来获取:

<p>{{ propertyName }}</p>
  • 案例
<body>
<div class="app">
<h1>过滤案例</h1>
<p>请输入要搜索的内容:<input type="text" v-model="searchText"></p>
<ul>
<li v-for="item in newList">{{item}}</li>
</ul>
</div>
</body>
<script>
let vm = new Vue({
el: '.app',
data: {
searchText: '',
dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf']
},
methods: {},
// 通过计算属性 computed 将newList方法包装成一个属性,每当使用的变量发生变化的时候,才会重新计算
computed: {
newList() {
return this.dataList.filter(item => item.indexOf(this.searchText) >= 0)
}
}
})
</script>

7.监听属性

在data中定义的变量,只要变量发生变化,Vue实例就会自动调用指定的回调函数

定义

通过配置项的关键字watch来定义

watch: {
// 被监听的状态
propertyName(newValue, oldValue) {
// 回调函数,newValue表示新的值,oldValue表示旧的值
// 在这里可以进行一些响应式的逻辑处理
}
}

注意

  • watch选项监听的状态必须是响应式的。也就是说,它必须是通过data选项或props属性定义的
  • watch选项不支持使用计算属性或方法
  • 案例
<body>
<div>
<div class="app">
<div @click="handleVar=1"><h3>变量111</h3></div>
<div @click="handleVar=2"><h3>变量222</h3></div>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '.app',
data: {
handleVar: '0'
},
created() {
this.getData()
},
methods: {
getData() {
// 可以发送ajax,与后端交互,获取数据值,重新渲染页面
console.log('与后端交互')
},
},
watch: {
handleVar() {
console.log('点击了不同的标签,变量发生了变化')
this.getData()
}
}
})
</script>
posted @   Duosg  阅读(233)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示