Vue.js------Vue组件基础

embedded/2024/10/19 23:24:52/
  1. 能够理解Vue组件概念和作用
  2. 能够掌握封装创建组件能力
  3. 能够使用组件之间通信
  4. 能够完成todo案例

一.Vue组件创建和使用

1.折叠面板-实现多个 

 

创建一个文件夹demo 具体步骤请参考vue.js---vue基础

⚫ 解决方案: 采用vue提供的单.vue文件-组件方式来封装一套然后复用

在components文件夹下创建组件PanelComponent.vue

javascript"><template><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>
</template><script>
export default {data() {return {isShow: false,};},
};
</script><style 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

javascript"><template><div id="app"><h3>案例:折叠面板</h3><Pannel></Pannel><Pannel></Pannel><Pannel></Pannel></div>
</template><script>
import Pannel from './components/PanelComponent.vue'
export default {components: {Pannel: Pannel}
}
</script><style lang="less">
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>

下载less,less-loader第三方库

npm install less-loader --save-dev

启动服务器,打开网站

 

1. 遇到重复标签想复用?

      封装成组件

2. 组件好处?   各自独立, 便于复用

2.组件概念

  • 组件是可复用的 Vue 实例, 封装标签, 样式和JS代码
  • 组件化 :封装的思想,把页面上 `可重用的部分` 封装为 `组件`,从而方便项目的 开发 和 维护
  • 一个页面, 可以拆分成一个个组件,一个组件就是一个整体, 每个组件可以有自己独立的 结构 样式 和 行为(html, css和js)

组件是什么? 可复用的vue实例, 封装标签, 样式, JS

什么时候封装组件? 遇到重复标签, 可复用的时候

组件好处? 各自独立, 互不影响

 3.组件_基础使用

目标:每个组件都是一个独立的个体, 代码里体现为一个独立的.vue文件

创建组件, 封装要复用的标签, 样式, JS代码

2. 注册组件

  • 全局注册 – main.js中 – 语法如图

  • 局部注册 – 某.vue文件内 – 语法如图

3. 使用组件

 

 文件demo\src\components\PanelComponent_1.vue

javascript"><template><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>
</template><script>
export default {data() {return {isShow: true,};},
};
</script><style 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

javascript"><template><div id="app"><h3>案例:折叠面板</h3><!-- 4. 组件名当做标签使用 --><!-- <组件名></组件名> --><PannelG></PannelG><PannelL></PannelL></div>
</template><script>
// 目标: 局部注册 (用的多)
// 1. 创建组件 - 文件名.vue
// 2. 引入组件
import Pannel from './components/PanelComponent_1.vue'
export default {// 3. 局部 - 注册组件/*语法: components: {"组件名": 组件对象}*/components: {PannelL: Pannel}
}
</script><style lang="less">
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>

main.js

javascript">import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = false// 目标: 全局注册 (一处定义到处使用)
// 1. 创建组件 - 文件名.vue
// 2. 引入组件
import Pannel from './components/PanelComponent_1.vue'
// 3. 全局 - 注册组件
/*语法: Vue.component("组件名", 组件对象)
*/
Vue.component("PannelG", Pannel)new Vue({render: h => h(App),
}).$mount('#app')

 

创建和使用组件步骤?

      创建.vue文件 – 标签 – 样式 – JS进去

      注册组件 (全局 / 局部)

      使用组件 (组件名用作标签)

组件运行结果? 把组件标签最终替换成, 封装的组件内标签

4.组件-scoped作用 

  • 准备: 当前组件内标签都被添加 data-v-hash值 的属性
  • 获取: css选择器都被添加 [data-v-hash值] 的属性选择器

Vue组件内样式, 只针对当前组件内标签生效如何做? 给style上添加scoped

原理和过程是什么? 会自动给标签添加data-v-hash值属性, 所有选择都带属性选择

 二.Vue组件通信

1.组件通信_父传子_props 

目标:父组件 -> 子组件 传值

首先明确父和子是谁, 在父引入子 (被引入的是子)

  • 父: App.vue
  • 子: MyProduct.vue

创建MyProduct.vue如下图所示

子组件内, 定义变量, 准备接收, 然后使用变量

2. 父组件(App.vue)内, 要展示封装的子组件(MyProduct.vue)引入组件, 注册组件, 使用组件, 传值进去

App.vue

javascript"><template><div><!-- 目标: 父(App.vue) -> 子(MyProduct.vue) 分别传值进入需求: 每次组件显示不同的数据信息步骤(口诀):1. 子组件 - props - 变量 (准备接收)2. 父组件 - 传值进去--><Product title="好吃的口水鸡" price="50" intro="开业大酬宾, 全场8折"></Product><Product title="好可爱的可爱多" price="20" intro="老板不在家, 全场1折"></Product><Product title="好贵的北京烤鸭" price="290" :intro="str"></Product></div>
</template><script>
// 1. 创建组件 (.vue文件)
// 2. 引入组件
import Product from './components/MyProduct'
export default {data() {return {str: "好贵啊, 快来啊, 好吃"}},// 3. 注册组件components: {// Product: Product // key和value变量名同名 - 简写Product}
}
</script><style></style>

demo\src\components\MyProduct.vue

javascript"><template><div class="my-product"><h3>标题: {{ title }}</h3><p>价格: {{ price }}元</p><p>{{ intro }}</p></div>
</template><script>
export default {props: ['title', 'price', 'intro']
}
</script><style>
.my-product {width: 400px;padding: 20px;border: 2px solid #000;border-radius: 5px;margin: 10px;
}
</style>

什么时候需要父传子技术? 从一个vue组件里把值传给另一个vue组件(父->子)

父传子口诀(步骤)是什么?

子组件内, props定义变量, 在子组件使用变量

父组件内, 使用子组件, 属性方式给props变量传值

 2.组件通信_父向子-配合循环

目标:父组件 -> 子组件 循环使用-传值

每次循环obj和组件都是独立的, 新的

App.vue

javascript"><template><div><MyProduct v-for="obj in list" :key="obj.id" :title="obj.proname" :price="obj.proprice" :intro="obj.info"></MyProduct></div>
</template><script>
// 目标: 循环使用组件-分别传入数据
// 1. 创建组件
// 2. 引入组件
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: "炎热的夏天, 来个冰激凌了",},],};},// 3. 注册组件components: {// MyProduct: MyProductMyProduct}
};
</script><style></style>

 demo\src\components\MyProduct.vue

javascript"><template><div class="my-product"><h3>标题: {{ title }}</h3><p>价格: {{ price }}元</p><p>{{ intro }}</p></div>
</template><script>
export default {props: ['title', 'price', 'intro']
}
</script><style>
.my-product {width: 400px;padding: 20px;border: 2px solid #000;border-radius: 5px;margin: 10px;
}
</style>

循环使用组件注意事项? 每次循环, 变量和组件, 都是独立的 

3.单向数据流  

目标:从父到子的数据流向, 叫单向数据流

原因: 子组件修改, 不通知父级, 造成数据不一致性

Vue规定props里的变量, 本身是只读的

为何不建议, 子组件修改父组件传过来的值?

父子数据不一致, 而且子组件是依赖父传入的值

什么是单向数据流? 从父到子的数据流向, 叫单向数据流

props里定义的变量能修改吗?不能, props里的变量本身是只读的 

4.组件通信_子向父_自定义事件 

目标:子组件触发父自定义事件方法

  • 需求: 商品组件, 实现砍价功能

  • 前置补充, 父 -> 索引 -> 子组件 (用于区分哪个子组件)

父组件内, 绑定自定义事件和事件处理函数

语法: @自定义事件名="父methods里函数名"

子组件内, 恰当的时机, 触发父给我绑的自定义事件, 导致父methods里事件处理函数执行  

 App.vue

javascript"><template><div><!-- 目标: 子传父 --><!-- 1. 父组件, @自定义事件名="父methods函数" --><MyProduct v-for="(obj, ind) in list" :key="obj.id" :title="obj.proname" :price="obj.proprice" :intro="obj.info":index="ind" @subprice="fn"></MyProduct></div>
</template><script>
import MyProduct from './components/MyProduct_sub.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},methods: {fn(inde, price) {// 逻辑代码this.list[inde].proprice > 1 && (this.list[inde].proprice = (this.list[inde].proprice - price).toFixed(2))}}
};
</script><style></style>

demo\src\components\MyProduct_sub.vue

javascript"><template><div class="my-product"><h3>标题: {{ title }}</h3><p>价格: {{ price }}元</p><p>{{ intro }}</p><button @click="subFn">宝刀-砍1元</button></div>
</template><script>
import eventBus from '../EventBus'
export default {props: ['index', 'title', 'price', 'intro'],methods: {subFn() {this.$emit('subprice', this.index, 1) // 子向父eventBus.$emit("send", this.index, 1) // 跨组件}}
}
</script><style>
.my-product {width: 400px;padding: 20px;border: 2px solid #000;border-radius: 5px;margin: 10px;
}
</style>

javascript">import Vue from 'vue'
// 导出空白vue对象
export default new Vue()

 

什么时候使用子传父技术?

当子想要去改变父里的数据

子传父如何实现? 父组件内, 给组件@自定义事件="父methods函数" 子组件内, 恰当时机this.$emit('自定义事件名', 值)

总结:

组件是什么?

是一个vue实例, 封装标签, 样式和JS代码

组件好处? 便于复用, 易于扩展

组件通信哪几种, 具体如何实现? 父 -> 子 父

5.组件通信-EventBus  

目标:App.vue里引入MyProduct.vue和List.vue

目标:常用于跨组件通信时使用

⚫ 语法

  • src/EventBus/index.js – 创建空白Vue对象并导出
  • 在要接收值的组件(List.vue) eventBus.$on('事件名', 函数体)
  • 要传递值的组件(MyProduct.vue) eventBus.$emit('事件名', 值)

App.vue 

javascript"><template><div style="overflow: hidden;"><div style="float: left;"><MyProductv-for="(obj, ind) in list":key="obj.id":title="obj.proname":price="obj.proprice":intro="obj.info":index="ind"@subprice="fn"></MyProduct></div><div style="float: left;"><List :arr="list"></List></div></div>
</template><script>
import MyProduct from "./components/MyProduct_sub.vue";
import List from "./components/ProductList.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,List,},methods: {fn(inde, price) {this.list[inde].proprice > 1 &&(this.list[inde].proprice = (this.list[inde].proprice - price).toFixed(2));},},
};
</script><style>
</style>

 components/ProductList.vue

javascript"><template><ul class="my-product"><li v-for="(item, index) in productList" :key="index"><span>{{ item.proname }}</span><span>{{ item.proprice }}</span></li></ul>
</template><script>
import eventBus from "../EventBus/index";export default {props: ["arr"],data() {return {productList: []};},created() {this.productList = [...this.arr]; // 创建副本eventBus.$on("send", (index, price) => {this.handlePriceUpdate(index, price);});},methods: {handlePriceUpdate(index, price) {if (this.productList[index].proprice > 1) {// 更新副本而不是原始的 arrthis.productList[index].proprice = (this.productList[index].proprice - price).toFixed(2);// 发送事件通知父组件更新eventBus.$emit("priceUpdated", this.productList);}}}
};
</script><style>
.my-product {width: 400px;padding: 20px;border: 2px solid #000;border-radius: 5px;margin: 10px;
}
</style>

 components/MyProduct_sub.vue

javascript"><template><div class="my-product"><h3>标题: {{ title }}</h3><p>价格: {{ price }}元</p><p>{{ intro }}</p><button @click="subFn">宝刀-砍1元</button></div>
</template><script>
import eventBus from '../EventBus'
export default {props: ['index', 'title', 'price', 'intro'],methods: {subFn() {this.$emit('subprice', this.index, 1) // 子向父eventBus.$emit("send", this.index, 1) // 跨组件}}
}
</script><style>
.my-product {width: 400px;padding: 20px;border: 2px solid #000;border-radius: 5px;margin: 10px;
}
</style>

 

什么时候使用eventBus技术? 当2个没有引用关系的组件之间要通信传值

eventBus技术本质是什么? 空白Vue对象, 只负责$on和$emit


http://www.ppmy.cn/embedded/3895.html

相关文章

weblogic JSP action的配置

action(如xxx.do&#xff09;可以在Java文件中通过注解的方式配置&#xff0c;也可以在web.xml中进行配置 在java文件中配置的场合 WebServlet(xxxx.do) 并实现支持的方法&#xff1a;doGet或doPost等 或者 WebServlet(xxxx.do) 并实现service方法 所有method的处理方法都会…

mysql面试题七(集群)

目录 1.mySQL 中有哪些常见日志 错误日志&#xff08;Error Log&#xff09; 二进制日志&#xff08;Binary Log, Binlog&#xff09; 重做日志&#xff08;Redo Log&#xff09; 回滚日志&#xff08;Undo Log&#xff09; 慢查询日志&#xff08;Slow Query Log&#xf…

【面试八股总结】排序算法(二)

参考资料 &#xff1a;阿秀 一、堆排序 堆排序基本思想是先把数组构造成一个大顶堆(父亲节点大于其子节点)&#xff0c;然后把堆顶(数组最大值&#xff0c;数组第一个元素)和数组最后一个元素交换&#xff0c;这样就把最大值放到了数组最后边。把数组长度n-1,再进行构造堆把剩…

设计模式之观察者模式(下)

3&#xff09;JDK对观察者模式的支持 1.概述 在JDK的java.util包中&#xff0c;提供了Observable类以及Observer接口&#xff0c;它们构成了JDK对观察者模式的支持。 2.Observer接口 在java.util.Observer接口中只声明一个方法&#xff0c;它充当抽象观察者。 void update…

安全中级-环境安装(手动nginx以及自动安装php,mysql)

为了方便大家跟bilibili课程&#xff0c;出了第一节环境 bilibili搜凌晨五点的星可以观看相关的教程 一、环境 ubentu 二、nginx手动安装 2.1第一步 wget https://nginx.org/download/nginx-1.24.0.tar.gz 2.2下载好安装包以后解压 tar -zxvf nginx-1.21.6.tar.gz2.3安…

详解Qt中的JSON操作

JSON&#xff08;JavaScript Object Notation&#xff09;作为一种轻量级的数据交换格式&#xff0c;因其简洁的结构、易读性以及与多种编程语言的良好兼容性&#xff0c;在现代Web服务、API交互以及数据持久化场景中得到了广泛应用。Qt作为一款功能强大的跨平台应用开发框架&a…

架构权衡评估方法(ATAM):一种用于软件架构评估的方法,全称为Architecture Tradeoff Analysis Method

架构权衡评估方法(ATAM)是一种用于软件架构评估的方法,全称为Architecture Tradeoff Analysis Method。它由卡梅隆大学软件工程协会提出,旨在通过分析软件系统的各种架构特征,对系统进行全面的评估,以便在各种可能的方案中做出最佳的决策13。ATAM的核心是结合质量属性效用…

Golang | Leetcode Golang题解之第32题最长有效括号

题目&#xff1a; 题解&#xff1a; func longestValidParentheses(s string) int {left, right, maxLength : 0, 0, 0for i : 0; i < len(s); i {if s[i] ( {left} else {right}if left right {maxLength max(maxLength, 2 * right)} else if right > left {left, r…