组件是什么
组件是可复用的 Vue 实例,主要用于开发中 具有相同特征不同数据的模块 把它集成为一个组件 供重复利用
全局组件
规则:
- 组件的属性不能用大写字母
- 组件的名字可以用驼峰命名法,但是使用的时候必须用连字符
- 全局注册的组件使用时不能使用单标签(不会报错,但是只能使用一次 多次使用只显示第一个)
- 注册的组件不要跟系统标签同名
创建全局组件语法:
//注册全局组件
Vue.component("box", { //标签名
template: "<div><h1>box组件</h1></div>" //标签内容
//template里面内容只能用一个唯一的div包裹住,如果template的儿子元素中有两个元素,那么就会报错。局部组件也是
})
全局组件完成后相对于局部组件来说不用注册在任何vue管辖的html中(也就是vue的el元素下)都可以调用。
局部组件
一个vm实例可以有多个局部组件,但是只能供当前vm实例使用
创建局部组件语法:
<div id="app">
<box></box>
</div>
<script>
new Vue({
el: '#app',
data:{
name:"ljy"
},
components:{
box:{
template:`<div><h1>{{name}}{{fn()}}</h1></div>`,
//下面的组件只能在box里面使用
data(){
return {
name:"LJY",
age:21
}
},
methods:{
fn(){
if(this.age>=18){
return "成年人"
}else{
return "未成年"
}
}
}
}
}
})
单文件组件
vue中的单文件组件是以.vue扩展名结尾的文件,在这个文件中封装了html、js、css的代码,它自身是一个独立 的组件,所以成为单文件组件;
引入:1官方脚手架 2挂载vm对象 3组件引入并渲染到vm中
环境配置命令:
1. npm install @vue/cli -g //下载官方脚手架
2. vue create app //项目名称
3. 接下来让你选择一些默认要生成的工具,不管直接回车
4. 进入项目文件夹: cd app //进入项目文件夹,也可以直接在项目文件夹中打开终端
5. 启动:
npm run serve //生成的打包文件在内存中不会写入磁盘用于开发阶段
或者
npm run build //生成的打包文件在dist中 用于项目上线
单文件组件也有全局组件和局部组件
只是把一个组件单独写在一个.vue文件中,供别的组件引入然后注册
引入文件时:一般使用相对路径 上一下用…/ 同级使用./ 下级使用/ @ 代表src文件夹
vue文件结构:
由于.vue封装了html、js、css的代码,所以它由以下几部分组成;
template -> 组件的模板结构
script -> 组件的 JavaScript 行为
style -> 组件的样式
基于webpack的单文件组件项目基本结构
index.html 基本页面
App.vue vue根组件
main.js 入口文件
package.json 项目配置文件
webpack.config.js webpack配置文件
.babelrc babel配置文件,babel可以将es6转成es5
引入组件方法
//App.vue文件中
<template>
<div v-cloak>
<h1>App组件中</h1>
<box></box>
</div>
</template>
<script>
//引入Box.vue文件
import box from "@/components/Box.vue" //@代表了src目录的意思
export default {
data() {
return {
msg: "APP组件",
arr: ["ljy", 666, 888]
}
},
components:{
//注册的组件名不能跟vue中的和原生DOM的重名,注册的名字是驼峰 使用时就用连字符
box
}
}
</script>
<style>
</style>
//Box.vue文件中
<template>
<h1>{{msg}}</h1>
</template>
<script>
export default {
data() {
return {
msg:"Box组件"
}
},
}
//这份.vue文件 打包时 被loader解析为了一个对象
// {
// template:`<h1>{{msg}}</h1>`,
// data(){
// return {
// msg:"Box组件"
// }
// },
// ...所有功能
// }
</script>
<style>
</style>
小结:
如果.vue的script注释了 在打包的时候 vue的打包环境 会帮我们把这个文件解析为一个对象 然后给这个对象添加一个template属性 值为解析的<template>页面模板。
每个组件中必须包含 template 模板结构,而 \script 行为和 \style 样式是可选的组成部分。vue 规定:每个组件对应的模板结构,需要定义到\ 节点中。
这里<template> 是 vue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的 DOM 元素。
在 template 中定义根节点
在 vue 2.x 的版本中, 节点内的 DOM 结构仅支持单个根节点:
但是,在 vue 3.x 的版本中, 中支持定义多个根节点:
组件的属性Props
Vue组件通过props属性来声明一个自己的属性,然后父组件就可以往里面传递数据。
同样传递父组件里面的变量时,使用v-bind绑定。
属性有两种写法:简单声明和详细描述:
简单声明
props:[“prop1”,“prop2”]
对属性做详细的描述
props: {
propA: Number, // 基础的类型检查 (`null` 匹配任何类型)
propB: [String, Number], // 多个可能的类型
propC: { type: String,
required: true // 必填的字符串
},
propD: { type: Number,
default: 100 // 带有默认值的数字
},
propE: { type: Object, // 带有默认值的对象或者数组填Array
default: function () { // 不建议直接填对象(因为对象直接量会一直占用内存),一般使用工厂函数,调用时才创建对象节省资源(面试)
return { message: 'hello' }
}
},
propF: {
validator: function (value) {// 自定义验证函数返回为true就代表数据符合我们规定
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
通过属性Props 传值
父组件通过属性给子组件传值: 子组件的props接受数据
在页面模板中 使用变量名:属性 data 计算属性
注意:属性传值是单向的
案例:
//再父组件App.vue文件中
<template>
<div v-cloak>
<h1>App组件中</h1>
<box :pro="msg"></box> //属性名不能取官方定义
</div>
</template>
<script>
import box from "@/components/user.vue"
export default {
data() {
return {
msg: "父组件传递的值",
}
},
components:{
box
}
}
</script>
<style>
</style>
<template>
<h1>{{msg}}{{pro}}</h1>
</template>
<script>
export default {
props:['pro'], //接受这个属性
data() {
return {
msg:"Box组件中"
}
},
}
</script>
<style>
</style>
CSS相关技术[scoped]
全局样式的写法:
在.vue文件中的style中写的样式 打包后就是全局样式
写一个css文件 在项目中导入就是全局样式
如果全局样式出现了相同的选择器. 就看是哪个最后打包引入项目 哪个的优先级就最高
//父组件App.vue
<template>
<div v-cloak>
<h1>App组件中</h1>
<box :pro="msg"></box>
<user :pro2="msg2"></user>
</div>
</template>
<script>
import box from "@/components/box.vue"
import user from "@/components/user.vue" //由于user后引入,css同样式优先级高
export default {
data() {
return {
msg: "父组件传递给box的值",
msg2: "父组件传递给user的值",
}
},
components:{
box,
user
}
}
</script>
<style>
</style>
//子组件box.vue
<template>
<h1>{{msg}}{{pro2}}</h1>
</template>
<script>
export default {
props: ['pro2'],
data() {
return {
msg: "Box组件中"
}
},
}
</script>
<style>
h1 {
color: red;
}
</style>
//子组件user.vue
<template>
<h1>{{msg}}{{pro}}</h1>
</template>
<script>
export default {
props:['pro'],
data() {
return {
msg:"user组件中"
}
},
}
</script>
<style>
h1{
color: aqua;
}
</style>
全局样式会出先组件样式污染,那么如何解决?
使用局部样式scoped;
局部样式/CSS作用域的实现和原理
在style标签中添加一个scoped
原理就是vue的插件webpack打包时会:
把当前组件模板中的每一个元素添加一个相同的哈希值命名的属性名
并且为添加了scoped的style中的样式选择器上添加一个属性选择器
//修改box.vue中的style
<style scoped="scoped">
h1 {
color: red;
}
</style>
//修改user.vue中的style
<style scoped="scoped">
h1{
color: aqua;
}
</style>