组件是 可复用的 Vue 实例,封装标签,样式和 JS 代码。
可重用的部分
封装为 组件
,从而方便项目的 开发 和 维护。简单理解:一个页面, 可以拆分成一个个组件,一个组件就是一个整体,每个组件可以有自己独立的 结构 样式 和 行为 (html, css和js)
创建组件:创建.vue文件 – 标签 – 样式 – JS进去
注册组件:(全局 / 局部)
使用组件:(组件名用作标签)
执行结果:把组件标签最终替换成封装组件内的标签。
创建组件 (components 下的 Pannel.vue)
<template>
<div>
<div>
<div class="title">
<h4>芙蓉楼送辛渐h4>
<span class="btn" @click="isShow = !isShow">
{{ isShow ? '收起' : '展开' }}
span>
div>
<div class="container" v-show="isShow">
<p>寒雨连江夜入吴, p>
<p>平明送客楚山孤。p>
<p>洛阳亲友如相问,p>
<p>一片冰心在玉壶。p>
div>
div>
div>
template>
<script>
export default {
// 数据
data () {
return {
isShow: false
}
}
}
script>
<style lang="less" scoped>
.title {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #ccc;
padding: 0 1em;
}
.title h4 {
line-height: 2;
margin: 0;
}
.container {
border: 1px solid #ccc;
padding: 0 1em;
}
.btn {
/* 鼠标改成手的形状 */
cursor: pointer;
}
style>
局部注册组件,并使用 (App.vue)
<template>
<div id="app">
<h3>案例:折叠面板h3>
<pannel>pannel>
<pannel>pannel>
<pannel>pannel>
div>
template>
<script>
// 2. 注册组件
import Pannel from './components/Pannel'
export default {
components: {
Pannel
},
}
script>
<style lang="less" scoped>
body {
background-color: #ccc;
#app {
width: 400px;
margin: 20px auto;
background-color: #fff;
border: 4px solid blueviolet;
border-radius: 1em;
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.5);
padding: 1em 2em 2em;
h3 {
text-align: center;
}
}
}
style>
App.vue
<template>
<div>
<MyProduct title="俺是标题" price="100" info="俺是描述,这玩意儿真不错">MyProduct>
div>
template>
<script>
// 引入子组件
import MyProduct from './components/MyProduct.vue'
export default {
// 注册组件
components: {
MyProduct,
},
};
script>
MyProduct.vue
<template>
<div class="my-product">
<h3>标题: {{ title }}h3>
<p>价格: {{ price }}元p>
<p>{{ info }}p>
div>
template>
<script>
export default {
props: ["title", "price", "info"],
};
script>
<style scoped>
.my-product {
width: 400px;
padding: 20px;
border: 2px solid #000;
border-radius: 5px;
margin: 10px;
}
style>
指定类型,是否必传
props: {
title: {
typeof: String,
require: true
},
}
App.vue
<template>
<div>
<MyProduct v-for="v in list"
:title="v.proname"
:price="v.proprice"
:info="v.info"
:key="v.id">
MyProduct>
div>
template>
<script>
import MyProduct from './components/MyProduct.vue'
export default {
// 数据
data () {
return {
list: [
{ id: 1, proname: "超级好吃的棒棒糖", proprice: 18.8, info: '开业大酬宾, 全场8折' },
{ id: 2, proname: "超级好吃的大鸡腿", proprice: 34.2, info: '好吃不腻, 快来买啊' },
{ id: 3, proname: "超级无敌的冰激凌", proprice: 14.2, info: '炎热的夏天, 来个冰激凌了' },
],
}
},
// 注册组件
components: {
MyProduct,
}
}
script>
MyProduct.vue
<template>
<div class="my-product">
<h3>标题: {{ title }}h3>
<p>价格: {{ price }}元p>
<p>{{ info }}p>
div>
template>
<script>
export default {
props: ["title", "price", "info"],
};
script>
<style scoped>
.my-product {
width: 400px;
padding: 20px;
border: 2px solid #000;
border-radius: 5px;
margin: 10px;
}
style>
单项数据流
简单理解:父组件向子组件发送事件,子组件触发。
触发父组件的自定义方法
this.$emit("", 参数1, 参数2);
跨组件通信使用。
在监听方(List)接收,发送方(MyProduct)发送。
在 App.vue
父组件中写主体代码
<template>
<div>
<div style="float: left;">
<Product v-for="(v, i) in list" :key="v.id"
:title="v.proname"
:price="v.proprice"
:info="v.info"
:index="i">
Product>
div>
<div style="float: left;">
<List :arr="list">List>
div>
div>
template>
<script>
// 1.导入组件
import Product from './components/MyProduct.vue'
import List from './components/List.vue'
export default {
// 2.注册组件
components: {
Product,
List
},
// 数据
data () {
return {
price: 1,
list: [
{id: 1, proname: "超级好吃的棒棒糖", proprice: 18.8, info: "开业大酬宾, 全场8折",},
{id: 2, proname: "超级好吃的大鸡腿", proprice: 34.2, info: "好吃不腻, 快来买啊",},
{id: 3, proname: "超级无敌的冰激凌", proprice: 14.2, info: "炎热的夏天, 来个冰激凌了",},
],
}
},
}
script>
在 MyProduct.vue
外部组件中使用
<template>
<div class="my-product">
<h3>标题: {{ title }}h3>
<p>价格: {{ price }}元p>
<p>{{ info }}p>
<button @click="subFn">宝刀-砍1元button>
div>
template>
<script>
import eventBus from '../EventBus/index.js'
export default {
props: ["title", "price", "info", "index"],
methods: {
subFn () {
// 发送
eventBus.$emit('subPrice', this.index, 1);
}
}
};
script>
<style scoped>
.my-product {
width: 400px;
padding: 20px;
border: 2px solid #000;
border-radius: 5px;
margin: 10px;
}
style>
在 src 下创建 EventBus
文件夹,下新建 index.js
,并创建空白 Vue 对象并导出 (只负责监听和触发)
import Vue from 'vue'
export default new Vue();
在 components 文件夹下新建 List.vue
箭头函数没有 this,可以直接指向
<template>
<div>
<ul class="my-product">
<li v-for="(item, index) in arr" :key="index">
<span>{{ item.proname }}span>
<span>{{ item.proprice }}span>
li>
ul>
div>
template>
<script>
import eventBus from "../EventBus/index.js";
export default {
props: ["arr"],
// 生命周期 函数 vue创建完毕以后调用created
// created :处于loading结束后,还做一些初始化,实现函数自执行(data数据已经初始化,但是DOM结构渲染完成,组件没有加载)
// mounted :处于发起后端请求,获取数据,配合路由钩子执行操作(DOM渲染完成,组件挂载完成 )
created() {
// 接收(监听)
eventBus.$on("subPrice", (index, price) => {
if (this.arr[index].proprice > 1) {
this.arr[index].proprice = (this.arr[index].proprice - price).toFixed(2);
}
});
},
};
script>
<style scoped>
.my-product {
width: 400px;
padding: 20px;
border: 2px solid #000;
border-radius: 5px;
margin: 10px;
}
style>
数据在父组件中,修改父组件数据时
因为指针问题,复杂类型访问的是指针。不管是什么类型的数据,都推荐在父组件中修改数据。
创建工程和组件
创建组件 todoHeader.vue、todoMain.vue、todoFooter.vue
todoHeader.vue
<template>
<header class="header">
<h1>todosh1>
<input id="toggle-all" class="toggle-all" type="checkbox" >
<label for="toggle-all">label>
<input
class="new-todo"
placeholder="输入任务名称-回车确认"
autofocus
/>
header>
template>
<script>
export default {
}
script>
todoMain.vue
<template>
<ul class="todo-list">
<li class="completed" >
<div class="view">
<input class="toggle" type="checkbox" />
<label>任务名label>
<button class="destroy">button>
div>
li>
ul>
template>
<script>
export default {
}
script>
todoFooter.vue
<template>
<footer class="footer">
<span class="todo-count">剩余<strong>数量值strong>span>
<ul class="filters">
<li>
<a class="selected" href="javascript:;" >全部a>
li>
<li>
<a href="javascript:;">未完成a>
li>
<li>
<a href="javascript:;" >已完成a>
li>
ul>
<button class="clear-completed" >清除已完成button>
footer>
template>
<script>
export default {
}
script>
导入组件和样式
App.vue
<template>
<div class="todoapp">
<TodoHeader>TodoHeader>
<TodoMain>TodoMain>
<TodoFooter>TodoFooter>
div>
template>
<script>
import './styles/base.css'
import './styles/index.css'
import TodoHeader from './components/todoHeader.vue'
import TodoMain from './components/todoMain.vue'
import TodoFooter from './components/todoFooter.vue'
export default {
components: {
TodoHeader,
TodoMain,
TodoFooter
},
}
script>