目录
Vue cli工具安装
vue cli脚手架使用
?脚手架目录介绍:
组件基本使用
组件的三个组成部分
组件里面的data为什么必须是一个函数?
vue的css作用域中scoped作用和原理分别是什么?
注册局部组件
子组件部分:组件名:goods.vue
父组件引入
注册全局组件
全局组件:组件名:mybutton.vue
在main.js中实现全局引入
组件的name属性
vue组件传值
父组件传值子组件(props)
父组件部分传值
子组件通过props获取父组件传输的数据
单向数据流
子组件传递数据给父组件($emit)
子组件传递数据$emit
父组件接收数据
组件的自定义事件触发条件是什么?
Vue cli工具安装
打开cmd输入以下代码:
npm install -g @vue/cli
等待安装
安装好后输入
vue -V
出现版本号则表示安装成功
vue cli脚手架使用
在vs code中想要创建的文件右键打开终端cmd
创建vue项目输入以下代码:
vue create 项目名称??
注意项目名称不能为中文和大写字母
然后选择创建vue2或者vue3
?脚手架目录介绍:
?vuecil-demo ? ? ? ? # 项目目录 ? ? ├── node_modules # 项目依赖的第三方包 ? ? ├── public ? ? ? # 静态文件目录 ? ? ? ├── favicon.ico# 浏览器小图标 ? ? ? └── index.html # 单页面的html文件(网站首页,vue会帮我们配置好,使用较少) ? ? ├── src ? ? ? ? ?# 业务文件夹(项目核心文件夹,我们写的项目代码都放在这个文件夹里面) ? ? ? ├── assets ? ? # 静态资源(一般项目图片、css都放在这里) ? ? ? ? └── logo.png # vue的logo图片(没啥用,vue打广告的,可删除) ? ? ? ├── components # 组件目录一般我们写的组件都放在这里) ? ? ? ? └── HelloWorld.vue # 欢迎页面vue代码文件 (打广告的,可删除) ? ? ? ├── App.vue ? ?# 整个应用的根组件(网站首页index.htm默认会渲染这个根组件) ? ? ? └── main.js ? ?# 入口js文件(入口文件,vue实例的创建,根组件的挂载都是在这里完成) ? ? ├── .gitignore ? # git提交忽略配置(默认已经帮我们配置好 ) ? ? ├── babel.config.js ?# babel配置(ES6转换ES5工具,一般不用管) ? ? ├── package.json # 依赖包列表 ? ? ├── README.md ? ?# 项目说明(一般公司代码规范,人员组成之类的可以写在这里) ?? ?└── package-lock.json ? ?# 项目包版本锁定和缓存地址 ?? ?└── vue.config.js ? ?# 项目webpack配置项
组件基本使用
组件的三个组成部分
1.html模板部分(template)
注意点: 一个template只能有一个子元素,vue会自动把<template>里面的根元素作为当前组件(vue实例)的挂载点
组件HTML结构:每一个组件vue实例会默认把template的根元素作为挂载点
注意点:一个组件内部template只能有一个根元素
<template>
错误:<div></div> <div></div>
正确:<div> <div></div> </div>
</template>
2.script部分
注意点: 以前vue实例的代码写在 export default { } 里面。 它的本质是一个ES6模块化语法,作用就是让组件可以实现复用(导入导出到其他组件)
注意点 : 组件里面的data必须是一个函数, 这个函数返回值就是之前vue实例的data对象
组件里面的data为什么必须是一个函数?
因为组件需要复用,用引用类型,一个地方更改其他地方也会更改,
用函数的返回值返回的是普通数据类型,可以避免这种情况.
<script>
// 2.js业务逻辑
// (1)导入局部组件
import goods from "./components/goods.vue";
console.log(goods);
// 默认导出
export default {
//组件data必须是一个函数
// (2)注册组件:
components: {
goods,
},
data() {
return {};
},
methods: {},
commputed: {},
};
</script>
3.<style>标签,这里写组件的css代码
注意:在style标签中使用scoped,可以实现在不同组件之间存在样式覆盖情况下,保留自己样式不被更改
vue的css作用域中scoped作用和原理分别是什么?
1.默认情况下,如果父组件和子组件有相同的选择器权重,优先加载父组件样式 2.如果希望子组件加载自己的样式,就可以使用scoped (1)scoped作用:设置组件的css作用域 (2)scoped工作原理:给组件添加一个自定义属性data-v-xxxx,通过css属性选择器增加权重 div[data-v-xx]
<style scoped>
div {
border: 2px solid #0f0;
}
</style>
注册局部组件
子组件部分:组件名:goods.vue
<template>
<div>
<h4>商品名:{{goodName}}</h4>
<h4>商品价格:{{goodPrice}}</h4>
<h4>商品编号:{{goodId}}</h4>
<button v-on:click="doclick">砍一刀</button>
</div>
</template>
<script>
export default {
components: { },
methods: {
},
};
</script>
<style scoped>
div {
border: 2px solid #0f0;
}
</style>
父组件引入
(1)导入局部组件
import goods from "./components/goods.vue";
?(2)注册组件:
? ?components: {
//标签名:组件名? 两个命名相同时可以用结构赋值,这样只用写一个goods
? ? goods,
? },
<template>
<!-- 1.组件HTML结构:每一个组件vue实例会默认把template的根元素作为挂载点
注意点:一个组件内部template只能有一个根元素
错误:<div></div> <div></div>
正确:<div> <div></div> </div> -->
<div>
<h1>我是父组件</h1>
<!-- (3)使用组件 :组件相当于一个自定义的html标签 -->
<goods></goods>
<mybutton></mybutton>
</div>
</template>
<script>
// 2.js业务逻辑
// (1)导入局部组件
import goods from "./components/goods.vue";
// 默认导出
export default {
//组件data必须是一个函数
// (2)注册组件:
components: {
goods,
},
data() {
return {};
},
methods: {},
commputed: {},
};
</script>
<style>
</style>
注册全局组件
<template>
<button >砍一刀</button>
</template>
<script>
export default {
}
</script>
<style>
button{
width: 100px;
height: 22px;
background: #9ff;
}
</style>
在main.js中实现全局引入
1.引入到main.js中
import mybutton from './components/mybutton.vue'
2.注册全局组件
Vue.component('mybutton', mybutton)
// 导入vue
import Vue from 'vue'
// 导入根组件
import App from './App.vue'
// 控制台打印开关
Vue.config.productionTip = false
// 创建vue实例,并且将App.vue文件挂载到 index.html的 id为app的盒子
// 全局组件
import mybutton from './components/mybutton.vue'
Vue.component('mybutton', mybutton)
new Vue({
render: h => h(App),
}).$mount('#app')
// $mount挂载点 等同于el
组件的name属性
写在什么地方?? 写在script的export default中
作用是什么??
💎1.name属性的作用是给这个组件一个标识符,用于快速查找组件
💎2.允许组件模板递归地调用自身。
注意,组件在全局用Vue.component()注册时,全局ID自动作 为组件的 name。
💎3.指定 name 选项的另一个好处是便于调试。有名字的组件有更友好的警告信息。另外,当在有 vue-devtools,未命名组件将显示成<AnonymousComponent>,这很没有语义。通过提供 name 选项,可以获得更有语义信息的组件树。
name属性特点
-
a. 必须是唯一,不能与其他组件name属性冲突
-
b.name属性值不能是中文
<script>
import goods from "./components/goods.vue";
export default {
name: "App",
// 注册组件
components: {
goods,
},
data() {
return {
};
},
methods: {
};
</script>
vue组件传值
父组件传值子组件(props)
父组件部分传值
? 在父组件的模板的对应子组件的标签中获取父组件的data中的数据传给子组件
<goods ? ? ? v-for="item in list" ? ? ? :goodName="item.goodName" ? ? ? :goodPrice="item.goodPrice" ? ? ? :key="item.goodId" ? ? ? :goodId="item.goodId" ? ? ? @price="doprice" ? ? ></goods>
<template>
<div class="box">
<!-- 子组件 -->
<goods
v-for="item in list"
:goodName="item.goodName"
:goodPrice="item.goodPrice"
:key="item.goodId"
:goodId="item.goodId"
@price="doprice"
></goods>
</div>
</template>
<script>
import goods from "./components/goods.vue";
export default {
name: "App",
// 注册组件
components: {
goods,
},
data() {
return {
list: [
{ goodName: "iPhone12", goodPrice: "3211", goodId: 1 },
{ goodName: "oppo r90", goodPrice: "1000", goodId: 2 },
{ goodName: "mi 38", goodPrice: "3000", goodId: 3 },
{ goodName: "huawei mate70", goodPrice: "8900", goodId: 4 },
],
};
},
methods: {
},
};
</script>
<style>
</style>
子组件通过props获取父组件传输的数据
在export default中
? props:['goodName','goodPrice','goodId'],
注意props数组中的字符串名要和父组件中设置的属性名相同
即下面代码的左边部分
? ? ? :goodName="item.goodName"
? ? ? :goodPrice="item.goodPrice"
? ? ? :key="item.goodId"
? ? ? :goodId="item.goodId"
<template>
<div>
<h4>商品名:{{goodName}}</h4>
<h4>商品价格:{{goodPrice}}</h4>
<h4>商品编号:{{goodId}}</h4>
<button v-on:click="doclick">砍一刀</button>
</div>
</template>
<script>
export default {
// 父传子
props:['goodName','goodPrice','goodId'],
components: { },
methods: {
},
};
</script>
<style scoped>
div {
border: 2px solid #0f0;
}
</style>
单向数据流
// 🏆父传子
// ·1.单向数据流:vue规定,父组件 传递给子组件的数据是只读的.
// 说人话:当数据是从父组件的属性中传递过来的时候,子组件不要直接去修改。
// 2.单向数据流原因:子组件修改了父组件传递过来的数据,不会通知父组件。就会造成数据不统一问题
// 3.细节:引用类型赋值本质是赋值地址,一但修改互相影响,非常不便于维护
子组件传递数据给父组件($emit)
子组件传递数据$emit
子组件部分使用$emit传输自定义事件和事件数据
💎1.首先现在子组件设定一个触发事件,
<button v-on:click="doclick">砍一刀</button>
💎2.在触发事件中使用$emit
export default {
// 父传子
props:['goodName','goodPrice','goodId'],
components: { },
methods: {
doclick(){
// 子传父
// this.$emit('事件名',事件参数)
this.$emit('price',this.goodId)
}
},
};
触发后事件后组件内部执行$emit发送事件名和事件数据
💎3.可以合并简写为:
此时this要去掉
<button v-on:click="$emit('price',goodId)">砍一刀</button>
<template>
<div>
<h4>商品名:{{goodName}}</h4>
<h4>商品价格:{{goodPrice}}</h4>
<h4>商品编号:{{goodId}}</h4>
<button v-on:click="doclick">砍一刀</button>
</div>
</template>
<script>
export default {
// 父传子
props:['goodName','goodPrice','goodId'],
components: { },
methods: {
doclick(){
// 子传父
// this.$emit('事件名',事件参数)
this.$emit('price',this.goodId)
}
},
};
</script>
<style scoped>
div {
border: 2px solid #0f0;
}
</style>
父组件接收数据
?💎1.在父组件的html模板的对应的自组件的标签中
使用子组件传输的自定义事件,绑定一个方法
@price="doprice"
💎2.在methods中根据命名的方法名(doprice)和子组件传输的数据来处理数据
methods: {
doprice(e) {
// console.log(e);
// 根据传递的参数id来砍价
// (1)根据id找到下标 findindex
const index = this.list.findIndex((item) => item.goodId == e);
console.log(index);
// (2)通过下标来修改元素
this.list[index].goodPrice--
},
注意:此处的方法doPrice(e)中的e(事件对象)为子组件传输的数据,如果子组件没有传数据,则为空
<template>
<div class="box">
<!-- 子组件 -->
<goods
v-for="item in list"
:goodName="item.goodName"
:goodPrice="item.goodPrice"
:key="item.goodId"
:goodId="item.goodId"
@price="doprice"
></goods>
</div>
</template>
<script>
// 🏆子传父
import goods from "./components/goods.vue";
export default {
name: "App",
// 注册组件
components: {
goods,
},
data() {
return {
list: [
{ goodName: "iPhone12", goodPrice: "3211", goodId: 1 },
{ goodName: "oppo r90", goodPrice: "1000", goodId: 2 },
{ goodName: "mi 38", goodPrice: "3000", goodId: 3 },
{ goodName: "huawei mate70", goodPrice: "8900", goodId: 4 },
],
};
},
methods: {
doprice(e) {
// console.log(e);
// 根据传递的参数id来砍价
// (1)根据id找到下标 findindex
const index = this.list.findIndex((item) => item.goodId == e);
console.log(index);
// (2)通过下标来修改元素
this.list[index].goodPrice--
},
},
};
</script>
<style>
</style>
组件的自定义事件触发条件是什么?
组件内部执行$emit
|