评论([[comments.sum]])
vue.extend()
Vue.component()
简单示例:
<div id="app">
<my-cpn></my-cpn>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const cpn = Vue.extend({
template: `
<div>
<h1>title</h1>
</div>
`,
})
// 注册组件(全局组件,可以在多个Vue的实例下使用
Vue.component("my-cpn", cpn)
const app = new Vue({
el: "#app",
data: {},
methods: {},
})
</script>
事实上,这神写法在 Vue2.x 的文档中已经看不到了,它会直接使用一些语法糖,但是在很多资料还是提到这种方式,而且这种方式是学习后面方式的基础。
Vue.component("my-cpn", cpn)
注册组件(全局组件,可以在多个 Vue 的实例下使用new Vue({components:{cpn: cpn}})
在 Vue 实例初始化时传入的对象中创建的组件为局部组件,只能在当前实例绑定的挂载的里面生效const cpnSon = Vue.extend({
template: `
<div>
<h4>footer</h4>
</div>
`,
})
// 父组件
const cpn = Vue.extend({
template: `
<div>
<h1>title</h1>
<cpnSon></cpnSon>
</div>
`,
components: {
// 注册子组件,它的作用域是在 父组件下的,不能直接在组件下使用<cpnSon>,除非也在根节点注册
cpnSon: spcSon
}
})
// Vue 实例也是一个组件,根组件
当前作用域下组件的查找也是根据就近原则的,先查找其自身的子组件,没有查找全局组件
直接创建并注册
Vue.component("my-cpn", {
template: `
<div>
<h4>footer</h4>
</div>
`,
components: {
cpnSon: {}
}
})
Vue 提供了两种方案来定义 HTML 模块内容:
<!-- script标签,类型必须为text/x-template -->
<script type="text/x-template" id="cpn3">
<div>
<h2>cpn3</h2>
</div>
</script>
<!-- 直接使用 template标签 -->
<template id="cpn4">
<div>
<h2>cpn4</h2>
</div>
</template>
<script>
Vue.component(cpn4, {
template: '#cpn4'
}
})
</script>
组件不能直接访问 Vue 实例里面的数据
组件的原型也是指向 Vue 实例的,所以 Vue 实例有的东西(生命周期,计算属性...)它都支持
组件的 data 为什么是一个函数:
<div id="app">
<cpn></cpn>
<cpn></cpn>
<!-- 每个 相同组件里面的data数据有自己的作用域,更改第一个cpn,不会影响第二个 -->
</div>
<template id="cpn">
<div>
<button @click="counter > 0 ? counter-- : ''" :disabled="counter < 1">-</button>
<span>{{counter}}</span>
<button @click="counter++">+</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component("cpn", {
template: "#cpn",
// data:{} 组件中的data属性不能是一个对象
data() {
// 必须是一个函数,这个函数返回一个对象,对象内部保存这数据
return {
counter: 0,
}
},
})
const app = new Vue({
el: "#app",
data: {},
methods: {},
})
</script>
Tips: 组件的模板必须被一个根节点包裹,
<div>content</div>
子组件是不能引用父组件或者 ue 实例的数据的。但是,在开发中,往往一些数据确实需要从上层传递到下层.
Tips: vue 实例和子组件的通信和父组件和子组件的通信过程是一样的。
props 的值有两种方式:
<cpn :msg="msg"></cpn>
<body>
<!-- 父组件 -->
<div id="app">
<!-- 接受参数 -->
<cpn :msg="msg"></cpn>
</div>
<template id="cpn">
<section>
<h2>{{msg}}</h2>
<p>{{valmovies}}</p>
</section>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const cpn = {
template: "#cpn",
// 字符串数组,数组中的字符串就是传递时数据的名称。
// props: ["valmovies", "msg"],
// 对象可以设置传递时的类型,也可以设置默认值等。
props: {
msg: String,
valmovies: {
type: Array,
default() {
// 如果是设置数组或者对象的默认值,必须使用函数返回值的形式
return []
},
// 必须传入此参数
// required: true,
},
},
data() {
return {}
},
}
const app = new Vue({
el: "#app",
data: {
msg: "hello!",
movies: ["航海王", "22", "肖申克的救赎"],
},
components: {
cpn,
},
methods: {},
})
</script>
</body>
验证都支持的数据类型:
Tips: html 标签属性不支持(大写)驼峰命名,所以在父组件传值子组件是如果传入的变量命名为驼峰式
props: ["valMovies",]
的话需要:<cpn :val-movies="[]"></cpn>
. 将驼峰命名转为转为-
链接形式.不要直接在子组件中改变父组件传递过来的值, 需要修改最好是 在 data 中使用传递值的副本进行修改:
data(){ return{ dMsg: this.msg}}
, 同时通过自定义事件传递给父组件
<body>
<div id="app">
<!-- 通过自定义事件接受子组件传递过来的值, v-on用来监听自定义事件的 -->
<!-- 注意转换为驼峰命名法,这里自定义事件是不支持的 itemClick != item-click -->
<cpn @item-click="cpnClick"></cpn>
</div>
<template id="cpn">
<section>
<button v-for="item in goodsType" @click="btnClick(item)">{{item.name}}</button>
</section>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const cpn = {
template: "#cpn",
data() {
return {
goodsType: [
{ id: 0, name: "热门推荐" },
{ id: 1, name: "3C数码" },
{ id: 2, name: "日常百货" },
{ id: 4, name: "加用电器" },
],
}
},
methods: {
btnClick(item) {
// 子组件发出一个事件, 自定义事件
this.$emit("item-click", item)
},
},
}
const app = new Vue({
el: "#app",
data: {},
components: {
cpn,
},
methods: {
cpnClick(item) {
console.log(item)
},
},
})
</script>
</body>
Tips: html 标签属性不支持(大写)驼峰命名, 在在子组件相父组件传值时 如果自定义的事件名是 驼峰命名在此处是不被支持的.
this.$emit('itemClick', item)
Vue 不会将@click="btnClick(item)"
转换为 itemClick. 同时 html 标签属性不支持(区分大小写) 所以此处并不会触发自定义事件.
<body>
<div id="app">
<cpn></cpn>
<cpn ref="cpn3"></cpn>
<hr>
<button @click="btnClick">访问子组件属性</button>
</div>
<template id="cpn">
<section>
<h2>子组件 cpn</h2>
<soncpn></soncpn>
</section>
</template>
<template id="soncpn">
<section>
<h3>cpn - son</h3>
<button @click="sonBtnClick">访问父组件</button>
</section>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {},
components: {
cpn: {
template: "#cpn",
data() {
return {
dataMsg: "data msg",
}
},
methods: {
showMsg() {
console.log("父访问子$children")
},
},
components: {
soncpn: {
template: "#soncpn",
methods: {
sonBtnClick() {
// this.$parent 访问父组件 cpn
console.log(this.$parent)
console.log(this.$parent.dataMsg)
// 访问根组件 Vue 实例
console.log(this.$root)
},
},
},
},
},
},
methods: {
btnClick() {
// 访问子组件 cpn
console.log(this.$children) // array 已使用的组件列表
this.$children[0].showMsg()
console.log(this.$children[0].dataMsg)
console.log(this.$refs)
console.log(this.$refs.cpn3.dataMsg)
},
},
})
</script>
</body>
\<slot>中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容
<slot name="title"></slot>
具名插槽可以在组件内部定义多个插槽,同时传入内容也要定义需要替换的参数名 <p slot="title"></p>
.
一个不带 name 的
出口会带有隐含的名字“default”。未命名插槽,也就是默认插槽,捕获所有未被匹配的内容。
<div id="app">
<!-- 使用默认值 -->
<cpn></cpn>
<cpn>
<p>插槽 slot 接收组件调用时标签内部的内容,同时替换内部slot已有内容</p>
</cpn>
<!-- 替换多个插槽的某个名为 footer的插槽 -->
<cpn2><button slot="footer">替换后面</button></cpn2>
</div>
<template id="cpn">
<section>
<h2>组件 cpn</h2>
<slot>
<button>插槽默认值</button>
</slot>
</section>
</template>
<template id="cpn2">
<section>
<h2>插槽 cpn2</h2>
<!-- 定义多个插槽, 使用name区分 -->
<slot name="header"><div>上面</div></slot>
<slot name="center"><div>中间</div></slot>
<slot name="footer"><div>下面</div></slot>
</section>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {},
components: {
cpn: {
template: "#cpn",
},
cpn2 : {
template: '#cpn2'
}
},
methods: {},
})
</script>
编译作用域:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
<div id="app">
<cpn3>
<!-- 直接使用子组件的 languages 是不行的 -->
</cpn3>
<cpn3>
<!-- 获取子组件的 languages -->
<template slot-scope="slot">
<!-- <span v-for="item in slot.val">{{item}} - </span> -->
<span>{{slot.val.join(' - ')}}</span>
</template>
</cpn3>
</div>
<template id="cpn3">
<section>
<slot :val="languages">
<ul>
<li v-for="item in languages">{{item}}</li>
</ul>
</slot>
</section>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {},
components: {
cpn3: {
template: "#cpn3",
data() {
return {
languages: ["java", "javaScript", "c", "c++", "c++++", "golang"],
}
},
},
},
methods: {},
})
</script>
Tips: 在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的 attribute。规范对其的支持截至到 Vue3.新语法 v-slot
<!-- 比较与上面 -->
<div id="app">
<!-- 替换多个插槽的某个名为 footer的插槽 -->
<cpn2>
<template v-slot:header>
<button slot="footer">替换后面</button>
</template>
</cpn2>
</div>
<template id="cpn2">
<section>
<h2>插槽 cpn2</h2>
<!-- 定义多个插槽, 使用name区分 -->
<slot name="header"><div>上面</div></slot>
<slot name="center"><div>中间</div></slot>
<slot name="footer"><div>下面</div></slot>
</section>
</template>
Tips: 注意 v-slot 只能添加在
<template>
上 (只有一种例外情况),这一点和已经废弃的 slot attribute 不同。
<!-- 相较与上 -->
<cpn3>
<!-- 获取子组件的 languages -->
<template v-slot:default="slot">
<span>{{slot.val.join(' - ')}}</span>
</template>
</cpn3>
<template id="cpn3">
<section>
<!-- 一个不带 name 的 <slot>出口会带有隐含的名字“default”。 -->
<slot v-bind:val="languages">
<ul>
<li v-for="item in languages">{{item}}</li>
</ul>
</slot>
</section>
</template>
当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上:
<cpn3 v-slot:default="slot">
<!-- 获取子组件的 languages -->
<span>{{slot.val.join(' - ')}}</span>
</cpn3>
Tips: 不带参数的 v-slot 被假定对应默认插槽
v-slot="slot"
. 注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确.Tips: 动态指令参数也可以用在 v-slot 上,来定义动态的插槽名,
<template v-slot:[dynamicSlotName]>
Tips: v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如
v-slot:header
可以被重写为#header
相关推荐:
来自系列:Vue 笔记评论([[comments.sum]])
[[item.name]] [[item.email]] [[item.date_time]]
[[itemSon.name]] [[itemSon.email]] [[itemSon.date_time]]
回复 @[[itemSon.reply_user.name]]:
加载更多([[item.son.length-2]])...