使用脚手架搭建工程
vue-cli
vue-cli集成了许多前端技术,包括但不限于:
- webpack
- babel
- eslint
- http-proxy-middleware
- typescript
- css pre-prosessor
- css module
- ...
这些工具大部分都依赖于node环境和npm
vue-cli 使用
使用以下命令,根据提示创建即可
vue creat 项目名称
项目结构
bili-app
├─ .gitignore
├─ babel.config.js
├─ jsconfig.json
├─ node_modules
│ └─ ...
├─ package-lock.json
├─ package.json
├─ public
│ ├─ favicon.ico
│ └─ index.html
├─ README.md
├─ src
│ ├─ App.vue
│ ├─ assets
│ │ └─ logo.png
│ ├─ components
│ │ └─ HelloWorld.vue
│ └─ main.js
└─ vue.config.js
开发
芝士
插槽
<template>
<div class="item">
<slot></slot>
</div>
</template>
<item>
<h1>Hello Bilibili</h1>
</item>
item
标签中的内容会被放到slot
标签处。
具名插槽
<template>
<div class="item">
<div class="left">
<slot name="title"></slot>
</div>
<div class="right">
<slot name="icon"></slot>
</div>
</div>
</template>
<item>
<template v-slot:title>xxx</template>
<template v-slot:icon><img src="" /></template>
</item>
动态绑定类样式
<template>
<div class="item" :class="{active: isActive}">
<slot></slot>
</div>
</template>
通过给:class
传入一个对象,属性名是需要动态添加的样式,属性值的true
或false
影响属性名的样式是否添加,如果属性值结果为true
则添加对应类样式。
<template>
<div class="item" :class="isExpand ? 'style1' : 'style2'">
<slot></slot>
</div>
</template>
也可通过三目表达式
动态绑定style
<template>
<div class="item" :style="{
width: width + 'px',
height: height + 'px'
}">
<slot></slot>
</div>
</template>
当然也可以写一个计算属性返回一个对象:
<template>
<div class="item" :style="style">
<slot></slot>
</div>
</template>
若属性名含有"-"之类的比如
margin-top
,将其使用引号包裹
export default {
computed: {
style() {
return {
'margin-top': '3px',
width: width + 'px',
height: height + 'px'
}
}
}
}
约束属性
如何避免向使用组件时传入其他类型的数据,如何保证传入对应数据呢?
export default {
props: {
isActive: {
type: Boolean, // 约束属性类型
required: true, // 约束属性是否必须传递
//default: false, // 默认值
},
}
};
若传入的值不是Boolean
类型,将会得到以下警告:
[Vue warn]: Invalid prop: type check failed for prop "isActive". Expected Boolean, got String with value "true".
若默认值为对象,必须使用函数,函数的返回值为对象。
我们在配置data时同样使用函数,函数返回一个对象。
原因,组件可能被使用多次,若不写成函数,那么多个组件之间会共享一个对象,因此需要使用函数,数据来着函数调用,返回的不是同一个对象,保证组件之间独立。
图标库,图标组件
<template>
<i class="iconfont" :class="iconClass"></i>
</template>
<script>
// 映射关系
let iconMap = {
'big-left': 'icon-chevron_big_left',
'big-right': 'icon-chevron_big_right',
'big-up': 'icon-chevron_big_up',
'big-down': 'icon-chevron_big_down',
...
};
export default {
props: {
type: {
type: String,
required: true,
}
},
computed: {
iconClass() {
return iconMap[this.type];
}
}
};
</script>
<style scoped>
// 引入css
@import "//at.alicdn.com/t/c/font_4633489_dx291zwcocm.css";
</style>
使用
<icon :type="'big-right'"></icon>
问题
类样式冲突
当我们开发组件时如何防止类样式冲突
<template>
<div class="item">item components</div>
</template>
<style scoped>
.item {
cursor: pointer;
}
.item:hover {
background: #f4f4f4;
}
</style>
我们给style加上一个scoped标签后,生成的元素如下
<div data-v-186c01a3 class="item">item components</div>
对应的css选择器如下
.item[data-v-186c01a3] {
cursor: pointer;
}
会生成一个唯一的自定义属性,避免类样式冲突,借鉴于CSS module的做法。
盒子宽高如何处理
外部使用组件时可能会使用不同的宽高,针对这个问题,将组件的设置为撑满父元素
.item {
width: 100%;
height: 100%;
}
事件与数据
数据是父组件的,事件是子组件的,父子组件之间需要通信
子组件可以抛出事件:
export default {
methods: {
handleClick() {
// 通知父组件
// this.$emit("事件名", ...参数)
this.$emit("active")
}
}
};
父组件接收事件
<item :isActive="curActive === 'A'" @active="curActive = 'A'"> A </item>
也可以是函数,函数的参数为子组件传递的参数。
开发环境解决跨域问题
在vue.config.js中添加内容:
// vue-cli的配置文件,大部分都是webpack的配置
const { defineConfig } = require("@vue/cli-service");
// commonjs规范
// webpack在加载配置时是node.js环境,node.js环境默认支持commonjs规范
// webpack在运行打包的时候是webpack环境,webpack环境默认都支持
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
proxy: {
// 配置代理
"/x": { // 以/x开头的请求都会被代理
target: "https://api.bilibili.com",
changeOrigin: true,
onProxyReq(proxyReq) {
// 添加请求头
proxyReq.setHeader("origin", "https://www.bilibili.com");
proxyReq.setHeader("referer", "https://www.bilibili.com/v/channel");
}
}
},
},
});
给子组件设置样式
通常我们希望组件独立,而不受其他影响,因此不建议直接给子组件设置样式,可通过属性传递方式,将样式传递给子组件。
<template>
<i class="iconfont" :class="[iconClass, extraClass]"></i>
</template>
<script>
let iconMap = {
...
};
export default {
props: {
type: {
type: String,
required: true,
},
extraClass: {
type: String,
default: "",
}
},
computed: {
iconClass() {
return iconMap[this.type];
}
}
};
</script>
<style scoped>
@import "//at.alicdn.com/t/c/font_4633489_dx291zwcocm.css";
</style>
使用
<icon :type="'search'" extraClass="red"></icon>
<style scoped>
.red {
color: red;
}
</style>