Vue
的重要思想创建组件构造器
注册组件
使用组件。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<style>
style>
head>
<body>
<div id="vue">
<my-con>my-con>
div>
body>
<script>
// 组件的注册
const con = Vue.extend({
template: `
我是组件
`
});
// 注册组件
Vue.component('my-con', con);
const app = new Vue({
el: '#vue',
data() {
return {
msg: '',
}
},
methods: {
},
});
script>
html>
Vue
的实例下面使用) // 组件的注册
const con = Vue.extend({
template: `
我是组件
`
});
// 注册组件
Vue.component('my-con', con);
疑问:那怎么样是注册局部组件呢?
<script>
// 组件的注册
const con = Vue.extend({
template: `
我是组件
`
});
const app = new Vue({
el: '#vue',
data() {
return {
msg: '',
}
},
methods: {
},
// 注册局部组件
components: {
cpn: con
}
});
</script>
这样就可以在单个
Vue
实例中注册了,不影响其他页面效果。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
head>
<body>
<div id="vue">
<cpn>cpn>
div>
body>
<script>
// 创建子组件
const cn = Vue.extend({
template: `
我是子组件
`
})
// 父组件的注册
const con = Vue.extend({
template: `
我是组件
`,
components: {
cn1: cn
}
});
const app = new Vue({
el: '#vue',
data() {
return {
msg: '',
}
},
methods: {
},
// 注册局部组件
components: {
cpn: con
}
});
script>
html>
// 注册全局组件
Vue.component('my-con', {
template: `
我是组件
`
});
<my-con>my-con>
就不用再写extend属性来创建一个构造器了
那局部组件怎么创建呢?
const app = new Vue({
el: '#vue',
data() {
return {
msg: '',
}
},
methods: {
},
// 注册局部组件
components: {
cpn: {
template: `
我是局部组件
`
}
}
});
这样就方便我们不用上下去寻找我们到底用到那个组件了,比较一目了然。
标签。<script type="text/x-template" id="con">
<div>
<h1>我是组件</h1>
</div>
</script>
Vue.component('my-con', {
template: '#con'
});
template
标签的方式。 <template id="cn">
<div>
<h1>我是组件2h1>
div>
template>
Vue.component('my-con', {
template: '#cn'
});
Vue
实例的数据答案是: 不能
组件是一个单独功能模块的封装:
组件中的数据是保存在哪里呢?顶层的Vue
实例中吗?
Vue
实例中的data<body>
<div id="vue">
<my-con></my-con>
<cpn></cpn>
</div>
<template id="cn">
<div>
<h1>{{msg}}</h1>
</div>
</template>
</body>
<script>
// 注册全局组件
Vue.component('my-con', {
template: '#cn'
});
const app = new Vue({
el: '#vue',
data() {
return {
msg: '你好!!',
}
},
});
</script>
Vue
实例中, Vue
实例就会变的非常臃肿。Vue
组件应该有自己保存数据的地方。component
中有template
属性,也有conponents
属性,同时也有一个自身储存数据的属性。就是data
属性。(也有methods属性···)
注意:组件的data必须是函数类型,而且这个函数要求返回一个对象
// 注册全局组件
Vue.component('my-con', {
template: '#cn',
components:{
},
// data属性(必须是这个格式的)
data() {
return {
}
},
// 方法属性
methods: {
},
// ·····
});
那么为什么是data函数?
组件是可复用的vue
实例,一个组件被创建好之后,就可能被用在各个地方,而组件不管被复用了多少次,组件中的data
数据都应该是相互隔离,互不影响的,基于这一理念,组件每复用一次,data
数据就应该被复制一次,之后,当某一处复用的地方组件内data
数据被改变时,其他复用地方组件的data
数据不受影响,如下面这个例子:
<template>
<div class="title">
<h1>按钮被点击了{{ count }}次</h1>
<button v-on:click="count++">点击</button>
</div>
</template>
<script>
export default {
name: 'BtnCount',
data () {
return {
count: 0
}
}
}
</script>
<style scoped>
.title {
background-color: red
}
</style>
该组件被复用了三次,但每个复用的地方组件内的count
数据相互不受影响,它们各自维护各自内部的count
。
能有这样效果正是因为上述例子中的data
不是一个单纯的对象,而是一个函数返回值的形式,所以每个组件实例可以维护一份被返回对象的独立拷贝,如果我们将上述例子中的data
修改为:
data : {
count: 0
}
那么就会造成无论在哪个组件里改变了count
值,都会影响到其他两个组件里的count
。
这是因为当data
如此定义后,这就表示所有的组件实例共用了一份data
数据,因此,无论在哪个组件实例中修改了data
,都会影响到所有的组件实例。
在上一个小节中,我们提到了子组件是不能引用父组件或者Vue
实例的数据的。
但是,在开发中,往往一些数据确实需要从上层传递到下层:
如何进行父子组件间的通信呢?Vue
官方提到
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
head>
<body>
<div id="vue">
<cpn :cmovies='movies'>cpn>
div>
<template id="cn">
<div>
{{cmovies}}
div>
template>
body>
<script>
const cpn = {
template: '#cn',
props: ['cmovies'],
data() {
return {
}
},
}
const app = new Vue({
el: '#vue',
data() {
return {
msg: '你好!!',
movies: ['海王', '海贼王', '还上网吗?']
}
},
methods: {
},
// 注册局部组件
components: {
cpn
}
});
script>
html>
在前面,我们的props选项是使用一个数组。
我们说过,除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。
验证都支持哪些数据类型呢?
当我们有自定义构造函数时,验证也支持自定义的类型
props: ['cmovies','books'],
props:{
cmovies:Array,
books:Number
},
props:{
// 1. 类型限制
// cmovies: Array,
// cmessage: string,
// 2.提供一些默认值
cmessage: {
type: string ,
default: 'aaaavaaa'
}
}
props
驼峰命名标识再复习一下父传子的代码
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
head>
<body>
<div id="vue">
{{msg}}
<cpn :cinfo="info">cpn>
div>
<template id="cn">
<div>
{{cinfo}}
div>
template>
body>
<script>
const cpn = {
template: '#cn',
props: {
cinfo: Object,
default () {
return {}
}
},
}
const app = new Vue({
el: '#vue',
data() {
return {
msg: '你好!!',
info: {
name: '木木',
age: 18,
sex: '男'
}
}
},
components: {
cpn
},
});
script>
html>
cinfo
变成cInfo
,如果使用 <cpn :cinfo="info"></cpn>
//必须变成==>
<cpn :c-info="info"></cpn>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
head>
<body>
<div id="vue">
<cpn @btnclick="sonclick">cpn>
div>
<template id="cn">
<div>
<button v-for="(item, index) in categories" :key="index" @click="btnclick(item.name)">
{{item.name}}
button>
div>
template>
body>
<script>
// 子组件
let cpn = {
template: '#cn',
data() {
return {
categories: [{
id: 'aaa',
name: "热门推荐"
}, {
id: 'bbb',
name: "手机家电"
}, {
id: 'ccc',
name: "电脑办公"
}, {
id: 'ddd',
name: "美图秀秀"
}]
}
},
methods: {
btnclick(item) {
console.log(item);
// 将这个结果,传给父组件
this.$emit("btnclick", item);
}
},
}
const app = new Vue({
el: '#vue',
data() {
return {
msg: '你好!!',
info: {
name: '木木',
age: 18,
sex: '男'
}
}
},
methods: {
sonclick: function(item) {
console.log("子组件传来了数据", item);
}
},
components: {
cpn
},
});
script>
html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cZbaeQ58-1604748969299)(F:\vue的终极总结\第二章\image-20201106202034167.png)]
vue
官方不推荐我们这样做,会报出异常,影响我们的开发。data
函数,在data
函数中进行双向绑定。<body>
<div id="vue">
<cpn :dname1="name" :bname1="name1">cpn>
div>
<template id="cn">
<div>
<h1>{{dname1}}h1>
<input type="text" v-model="dname1"/>
<h1>{{bname1}}h1>
<input type="text" v-model="bname1"/>
div>
template>
body>
<script>
const app = new Vue({
el: '#vue',
data() {
return {
name: 0,
name1: 1
}
},
components: {
cpn: {
template: '#cn',
props: {
dname1: Number,
bname1: Number
}
}
},
});
script>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" integripty>script>
head>
<body>
<div id="vue">
<cpn :dname1="name" :bname1="name1" @num1change='num1change' @num2change='num2change'>cpn>
div>
<template id="cn">
<div>
<h1>props:{{dname1}}h1>
<h1>data:{{dataDName1}}h1>
<h1>props:{{bname1}}h1>
<h1>data:{{dataBName1}}h1>
div>
template>
body>
<script>
const app = new Vue({
el: '#vue',
data() {
return {
name: 0,
name1: 1
}
},
methods: {
num1change: function(event) {
// 默认传值是string类型,需要我们在转换
this.name = Number(event);
},
num2change: function(event) {
this.name1 = Number(event);
}
},
components: {
cpn: {
template: '#cn',
props: {
dname1: Number,
bname1: Number
},
data() {
return {
dataDName1: this.dname1,
dataBName1: this.bname1
}
},
methods: {
father1: function(event) {
this.dataDName1 = event.target.value;
this.$emit('num1change', this.dataDName1)
},
father2: function(event) {
this.dataBName1 = event.target.value;
this.$emit('num2change', this.dataBName1)
}
},
}
},
});
script>
html>
$children
的方法来调用子组件的方法。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" integripty>script>
head>
<body>
<div id="vue">
<cpn :dname1="name" :bname1="name1">cpn>
<button @click="child">父访问button>
div>
<template id="cn">
<div>
<h1>{{dname1}}h1>
<h1>{{bname1}}h1>
div>
template>
body>
<script>
const app = new Vue({
el: '#vue',
data() {
return {
name: 0,
name1: 1
}
},
methods: {
// 父访子
child: function() {
console.log(this.$children);
console.log(this.$children[0].father1())
}
},
components: {
cpn: {
template: '#cn',
props: {
dname1: Number,
bname1: Number
},
methods: {
father1: function() {
console.log("123123")
},
},
}
},
});
script>
html>
通过refs访问子组件**【重要】**
refs是一个对象类型。他需要我们在我们的子组件上加入一个ref
属性。我们就可以通过这个唯一的ID来获取我们对应的子组件,就规避了前面我们所说的内容
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" integripty>script>
head>
<body>
<div id="vue">
<cpn :dname1="name" :bname1="name1" ref="aaaa">cpn>
<button @click="child">父访问button>
div>
<template id="cn">
<div>
<h1>{{dname1}}h1>
<h1>{{bname1}}h1>
div>
template>
body>
<script>
const app = new Vue({
el: '#vue',
data() {
return {
name: 0,
name1: 1
}
},
methods: {
// 父访子
child: function() {
console.log(this.$refs);
console.log(this.$refs.aaa.father1());
}
},
components: {
cpn: {
template: '#cn',
props: {
dname1: Number,
bname1: Number
},
methods: {
father1: function() {
console.log("123123")
},
},
}
},
});
script>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" integripty>script>
head>
<body>
<div id="vue">
<cpn>cpn>
div>
<template id="cn">
<div>
<h1>{{name}}h1>
<button @click="parent">子访问父组件button>
div>
template>
body>
<script>
const app = new Vue({
el: '#vue',
data() {
return {
name: '我叫父亲'
}
},
methods: {
father: function() {
console.log("我等我儿子吊我");
}
},
components: {
cpn: {
template: '#cn',
data() {
return {
name: "我是子组件"
}
},
methods: {
parent: function() {
console.log(this.$parent);
console.log(this.$parent.name);
console.log(this.$parent.father());
},
},
}
},
});
script>
html>
Vue
实例
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" integripty>script>
head>
<body>
<div id="vue">
<cpn>cpn>
div>
<template id="cn">
<div>
<h1>{{name}}h1>
<button @click="parent">子访问父组件button>
div>
template>
body>
<script>
const app = new Vue({
el: '#vue',
data() {
return {
name: '我叫父亲'
}
},
methods: {
father: function() {
console.log("我等我儿子吊我");
}
},
components: {
cpn: {
template: '#cn',
data() {
return {
name: "我是子组件"
}
},
methods: {
parent: function() {
console.log(this.$root);
console.log(this.$root.name);
console.log(this.$root.father());
},
},
}
},
});
script>
html>
slot翻译为插槽:
USB
我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。组件的插槽:
栗子:移动网站中的导航栏。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" integripty>script>
head>
<body>
<div id="vue">
<p>{{name}}p>
<cpn><i>插槽的作用i>cpn>
<cpn><button>
我又变成一个按钮哩!!
button>cpn>
div>
<template id="cn">
<div>
<h1>我是子组件h1>
<slot><i>我是默认值。可以不谢哦!!i>slot>
div>
template>
body>
<script>
const app = new Vue({
el: '#vue',
data() {
return {
name: '李玉森'
}
},
components: {
cpn: {
template: '#cn'
}
}
});
script>
html>
了解了为什么用slot ,我们再来谈谈如何使用slot ?
在子组件中,使用特殊的元素就可以为子组件开启一个插槽
该插槽插入什么内容取决于父组件如何使用。
我们通过一个简单的例子,来给子组件定义一个插槽。
中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容 <div id="vue">
<cpn>cpn>
div>
<template id="cn">
<div>
<slot><i>我是走左边的i>slot>
<slot><i>我是走中间的i>slot>
<slot><i>我是走右边的i>slot>
div>
template>
这样的话我们如果就想改中间的插槽的格式,那么浏览器就不知道到底是哪个要改,如果写一个,那么实际效果就全改了,所以我们就要给我们的插槽起名字。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" integripty>script>
head>
<body>
<div id="vue">
<cpn><span slot="mid">我改的是中间的是吧span>cpn>
div>
<template id="cn">
<div>
<slot name="left"><i>我是走左边的i>slot>
<slot name="mid"><i>我是走中间的i>slot>
<slot name="right"><i>我是走右边的i>slot>
div>
template>
body>
<script>
const app = new Vue({
el: '#vue',
data() {
return {
name: '李玉森'
}
},
components: {
cpn: {
template: '#cn'
}
}
});
script>
html>