1. Vue 基础
1) 环境准备
1. 安装脚手架
代码语言:javascript复制 npm install -g @vue/cli
- -g 参数表示全局安装,这样在任意目录都可以使用 vue 脚本创建项目
2. 创建项目
代码语言:javascript复制 vue ui
使用图形向导来创建 vue 项目,如下图:
- 输入项目名,包管理器选择npm
不想用git,可以取消勾选初始化git仓库,也可以创建完之后,删除.git文件夹
- 选择手动配置项目
- 添加 vue router 和 vuex
一个是实现组件之间的跳转,一个是实现组件之间数据的共享。
- 选择版本,创建项目
安装完毕后会跳转到一个页面:
3. 安装 devtools
官方浏览器插件,用于调试 Vue.js 应用。你可以检查组件、vuex store 和事件等。
- devtools 插件网址:https://devtools.vuejs.org/guide/installation.html
4. 运行项目
进入项目目录,执行
代码语言:javascript复制 npm run serve
启动成功:
5. 修改端口
前端服务器默认占用了 8080 端口,需要修改一下
- 文档地址:DevServer | webpack
- 打开 vue.config.js 添加
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ // ... devServer: { port: 8082 // 设置前端服务器端口 } })
6. 添加代理
- 文档地址:DevServer | webpack 不要使用第一段,使用这个:
为了避免前后端服务器联调时, fetch、xhr 请求产生跨域问题,需要配置代理
- 文档地址同上
- 打开 vue.config.js 添加
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
// ...
devServer: {
// 端口
port: 8082,
// 代理,将来只要以/api打头的请求,都会走代理的逻辑
proxy: {
'/api': {
target: 'http://localhost:8080', //设置成后端的服务器地址
changeOrigin: true
}
}
}
})
测试:
后端服务器在8080端口:
7. Vue 项目结构
代码语言:javascript复制 PS D:codeVScodeProjectsfountendstudystudy03-vue2> tree src
D:CODEVSCODEPROJECTSFOUNTENDSTUDYSTUDY03-VUE2SRC
├─assets
├─components
├─router
├─store
└─views
- assets - 静态资源
- components - 可重用组件
- router - 路由
- store - 数据共享
- views - 视图组件
以后还会添加
- api - 跟后台交互,发送 fetch、xhr 请求,接收响应
- plugins - 插件
2) Vue 组件
Vue 的组件文件以 .vue 结尾,每个组件由三部分组成
代码语言:javascript复制 <template></template>
<script></script>
<style></style>
- template 模板部分,由它生成 html 代码
- script 代码部分,控制模板的数据来源和行为
- style 样式部分,一般不咋关心
入口组件是 App.vue
先删除原有代码,来个 Hello, World 例子
代码语言:javascript复制 <template>
<!-- {{}} 文本插值 -->
<h1>{{msg}}</h1>
</template>
<script>
// vue组件的`<script>`中必须默认导出一个`options`对象
const options = {
data: function(){
// options的属性data,的函数返回值才是模板要使用的数据对象
return {msg:"Hello World!"};
}
};
export default options;
</script>
注意: vue组件的
<script>
中必须默认导出一个options
对象。
- export default 导出组件对象,供 main.js 导入使用
- 这个对象有一个 data 方法,返回一个对象,给 template 提供数据
{{}}
在 Vue 里称之为插值表达式,用来绑定 data 方法返回的对象属性,绑定的含义是数据发生变化时,页面显示会同步变化
那么是谁在使用App.vue这个组件?
main.js
导入了App.vue:
import Vue from 'vue'
// 1.
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
// 2.
render: h => h(App)
// 3.
}).$mount('#app')
import App from './App.vue'
:实这个导入我们可以简单理解为把App.vue的模板部分拿到了main.js,并对模板部分进一步解析(h => h(App)
),最终将{{msg}}解析成hello world。h => h(App)
:对模板进行解析,解析后生成一个虚拟节点(简单理解,他也是一种HTML元素,只不过还没有跟最终的页面结合到一起,还没有显示出来)$mount('#app')
:上面提到了虚拟节点未显示出来,那么哪一步将这个虚拟的节点显示到页面上呢?$mount('#app')
:会把解析后的虚拟节点放到页面上展示出来。 放到哪里去了呢?#app
就是一个id选择器:
可以看到/public/index.html
里有这个标签,所以解析后的虚拟节点放到这里。
我们打开F12,选中Hello world可以看到index.html里的<div id="app"></div>
被替换成了解析后的虚拟节点:
1. 文本插值
代码语言:javascript复制<template>
<div>
<h1>{{ name }}</h1>
<h1>{{ age > 60 ? '老年' : '青年' }}</h1>
</div>
</template>
<script>
const options = {
data: function () {
return { name: '张三', age: 70 };
}
};
export default options;
</script>
{{}}
里只能绑定一个属性,绑定多个属性需要用多个{{}}
分别绑定:
<template>
<h1>{{name age}}</h1>
</template>
// 会编译报错。
- template 内只能有一个根元素:
<template>
<h1>{{name}}</h1>
<h1>{{age}}</h1>
</template>
// 会报错:
// error The template root requires exactly one element vue/no-multiple-template-root
- 插值内可以进行简单的表达式计算
2. 属性绑定
对于标签中的文本数据,可以使用文本插值{{}}进行绑定,但是对于标签里的属性来讲,他的语法就不一样了,这就用到了属性绑定:
代码语言:javascript复制<template>
<div>
<div><input type="text" v-bind:value="name"></div>
<div><input type="date" v-bind:value="birthday"></div>
<div><input type="text" :value="age"></div>
</div>
</template>
<script>
const options = {
data: function () {
return { name: '王五', birthday: '1995-05-01', age: 20 };
}
};
export default options;
</script>
- 简写方式:可以省略 v-bind 只保留冒号
3. 事件绑定
代码语言:javascript复制<!-- 事件绑定 -->
<template>
<div>
<div><input type="button" value="点我执行m1" v-on:click="m1"></div>
<div><input type="button" value="点我执行m2" @click="m2"></div>
<div>{{count}}</div>
</div>
</template>
<script>
const options = {
data: function () {
return { count: 0 };
},
methods: {
m1() {
this.count ;
console.log("m1")
},
m2() {
this.count --;
console.log("m2")
}
}
};
export default options;
</script>
- optinos里
data
是给模板提供数据的,methods
是给模板提供方法的。 - 简写方式:可以把 v-on: 替换为 @
- 在 methods 方法中的 this 代表的是 data 函数返回的数据对象
4. 双向绑定
先阅读下面的代码:
代码语言:javascript复制<template>
<div>
<div>
<label>请输入姓名:</label>
<input type="text" v-bind:value="name">
</div>
<div>
<label>请输入年龄:</label>
<input type="text" v-bind:value="age">
</div>
</div>
</template>
<script>
const optinos = {
data: function () {
return { name: '李刚', age: null }
},
methods: {
}
};
export default optinos;
</script>
这段代码就是将javaScript的数据与标签中的属性进行绑定,但是这种绑定是单向的,只能将javaScript中的数据传到文本框中,但是文本框中用户输入的数据无法同步到javaScript这边。
这里的双向绑定就是用户输入的数据也同步到javaScript这边:
代码语言:javascript复制<template>
<div>
<div>
<label for="">请输入姓名</label>
<input type="text" v-model="name">
</div>
<div>
<label for="">请输入年龄</label>
<input type="text" v-model="age">
</div>
<div>
<label for="">请选择性别</label>
男 <input type="radio" value="男" v-model="sex">
女 <input type="radio" value="女" v-model="sex">
</div>
<div>
<label for="">请选择爱好</label>
游泳 <input type="checkbox" value="游泳" v-model="fav">
打球 <input type="checkbox" value="打球" v-model="fav">
健身 <input type="checkbox" value="健身" v-model="fav">
</div>
</div>
</template>
<script>
const options = {
data: function () {
return { name: '', age: null, sex:'男' , fav:['打球']};
},
methods: {
}
};
export default options;
</script>
- 用 v-model 实现双向绑定,即
- javascript 数据可以同步到表单标签
- 反过来用户在表单标签输入的新值也会同步到 javascript 这边
- 双向绑定只适用于表单这种带【输入】功能的标签,其它标签的数据绑定,单向就足够了
- 复选框
<checkbox>
这种标签,双向绑定的 javascript 数据类型一般用数组
vue的调试工具: F12-->vue,就可以看到之前下载的devtools调试工具了:
可以在这里看到data
返回的数据对象的变化:
5. 计算属性
代码语言:javascript复制<!-- 计算属性 -->
<template>
<div>
<!-- 方法1:直接拼接-->
<!-- <h2>{{lastName firstName}}</h2>-->
<!-- 方法2:使用方法-->
<!-- <h2>{{fullName()}}</h2>-->
<!-- 方法3:采用计算属性的写法(推荐)-->
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
</div>
</template>
<script>
const options = {
data: function () {
return { firstName: '三', lastName: '张' };
},
/* methods: {
fullName() {
console.log('进入了 fullName')
return this.lastName this.firstName;
}
},*/
computed: {
fullName() {
console.log('进入了 fullName')
return this.lastName this.firstName;
}
}
};
export default options;
- 为什么把他叫做计算属性呢? 因为计算属性使用时就把它当属性来用,无需加 (),
- 计算属性和方法的区别:
可以发现两种方式非常接近,只不过调用时一个有()一个没有(),那么计算属性有什么有点呢?
普通方法没有缓存功能,计算属性有缓存功能:
一次
fullName()
发生计算后,会将结果缓存,下次再计算时,只要数据没有变化,不会重新计算,直接返回缓存结果。 使用methods:
<template>
<div>
<h1>{{fullName()}}</h1>
<h1>{{fullName()}}</h1>
<h1>{{fullName()}}</h1>
</div>
</template>
使用computed:
代码语言:javascript复制<template>
<div>
<h1>{{fullName}}</h1>
<h1>{{fullName}}</h1>
<h1>{{fullName}}</h1>
</div>
</template>
6. axios
axios 它的底层是用了 XMLHttpRequest(xhr)方式发送请求和接收响应,xhr 相对于之前讲过的 fetch api 来说,功能更强大,但由于是比较老的 api,不支持 Promise,axios 对 xhr 进行了封装,使之支持 Promise,并提供了对请求、响应的统一拦截功能(相当于后端的过滤器,拦截器)
axios就是 ajax的一种实现。因为axios的底层是XMLHttpRequest,所以会发生跨域,下面因为使用了代理,所以没有出现跨域的问题。
1. 安装
代码语言:javascript复制 npm install axios -S
2. 导入
代码语言:javascript复制 import axios from 'axios'
- axios 默认导出一个对象,这里的 import 导入的就是它默认导出的对象,源码: export default axios;
3. 示例:
代码语言:javascript复制 <template>
<div>
<input type="button" value="获取远程数据" v-on:click="sendRequest()">
</div>
</template>
<script>
// 导入axiso
import axios from 'axios'
const options = {
methods:{
async sendRequest(){
const resp = await axios.get("/api/students");
console.log(resp)
}
}
};
export default options
</script>
F12,查看控制台:
4. 方法
请求 | 备注 |
---|---|
axios.get(url[, config]) | ⭐️ |
axios.delete(url[, config]) | |
axios.head(url[, config]) | |
axios.options(url[, config]) | |
axios.post(url[, data[, config]]) | ⭐️ |
axios.put(url[, data[, config]]) | |
axios.patch(url[, data[, config]]) |
- config - 选项对象、例如查询参数、请求头...
- data - 请求体数据、最常见的是 json 格式数据
- get、head 请求无法携带请求体,这应当是浏览器的限制所致(xhr、fetch api 均有限制)
- options、delete 请求可以通过 config 中的 data 携带请求体
例子
代码语言:javascript复制<template>
<div>
<input type="button" value="获取远程数据" @click="sendReq()">
</div>
</template>
<script>
import axios from 'axios'
const options = {
methods: {
async sendReq() {
//因为我们配置了代理,以/api打头的请求都会代理到8080,所以axiso发起的请求不用写那么完整。
------------------------------------------------------------------------
// 1. 演示 get, post
// const resp = await axios.get('/api/a1');
// const resp = await axios.post('/api/a2');
------------------------------------------------------------------------
// 2. 发送请求头
// go使用r.Header.Get()接收
// const resp = await axios.post('/api/a3',{},{
// headers:{
// Authorization:'abc'
// }
// });
------------------------------------------------------------------------
// 3. 发送请求时携带查询参数 ?name=xxx&age=xxx
// go使用r.FormValue()接收
// 方法1:拼字符串
// const name = encodeURIComponent('&&&');
// const age = 18;
// const resp = await axios.post(`/api/a4?name=${name}&age=${age}`);
// 方法2(推荐):
// 不想自己拼串、处理特殊字符、就用下面的办法
// const resp = await axios.post('/api/a4', {}, {
// params: {
// "name":'&&&&',
// "age": 20
// }
// });
------------------------------------------------------------------------
// 4. 用请求体发数据,格式为 urlencoded
// go使用r.FormValue()接收
// const params = new URLSearchParams();
// params.append("name", "张三");
// params.append("age", 24)
// const resp = await axios.post('/api/a4', params);
------------------------------------------------------------------------
// 5. 用请求体发数据,格式为 multipart,
// go使用r.ParseMultipartForm()接收
// const params = new FormData();
// params.append("name", "李四");
// params.append("age", 30);
// const resp = await axios.post('/api/a5', params);
------------------------------------------------------------------------
// 6. 用请求体发数据,格式为 json
// go 使用 io.ReadAll(r.Body) json.Unmarshal() 接收
const resp = await axios.post('/api/a5json', {
name: '王五',
age: 50
});
------------------------------------------------------------------------
console.log(resp);
}
}
};
export default options;
</script>
- 拼字符的时候需要注意:有些特殊字符必须经过URL编码,否则一些特殊字符是无法正确发给服务器的,例如&&&: 后端接收到的值: name: age: 10 所以需要进行编码:
const name = encodeURIComponent('&&&');
- 使用请求体发数据(格式为 urlencoded)的时候,不可以直接传入一个普通对象,因为这里的普通对象默认是json格式:
const resp = await axios.post('/api/a4', {
name: "123",
age: 20
});
console.log(resp)
- 我们打开F12,查看这个请求的信息,可以看到我们这样写,对应的数据格式Content-Type: application/json。后端对于json类型,需要配合对象去接收:
× //fmt.Println("name: " r.FormValue("name"), "age: " r.FormValue("age"))
---------------------------------------------------------------------
type student struct {
Name string
Age int
}
stu := new(student)
body, _ := io.ReadAll(r.Body)
json.Unmarshal(body, stu)
fmt.Println(stu)
- 而是要以上面的例子的格式发送。
5. 默认设置:
上面使用axios,是import之后直接使用它里面那些发送请求的方法,这样做是有一个问题的,这种情况下,我们发送每个请求的时候使用的都是默认设置,如果你发请求的时候不想用他的默认设置了,那每个请求方法里都需要跟上config参数,这样不够通用。
解决办法就是,自己创建axios对象,进行配置。
创建实例
代码语言:javascript复制const _axios = axios.create(config);
- axios 对象可以直接使用,但使用的是默认的设置
- 用 axios.create 创建的对象,可以覆盖默认设置,config 见下面说明
常见的 config 项有
名称 | 含义 |
---|---|
baseURL | 将自动加在 url 前面 |
headers | 请求头,类型为简单对象 |
params | 跟在 URL 后的请求参数,类型为简单对象或 URLSearchParams |
data | 请求体,类型有简单对象、FormData、URLSearchParams、File 等 |
withCredentials | 跨域时是否携带 Cookie 等凭证,默认为 false |
responseType | 响应类型,默认为 json |
注意: 开发环境:开发环境是程序猿们专门用于开发的服务器,配置可以比较随意, 为了开发调试方便,一般打开全部错误报告。简单讲就是项目尚且处于编码阶段,一般这时候会把代码放在开发环境中,不会放在生产环境中。 生产环境:是指正式提供对外服务的,一般会关掉错误报告,打开错误日志。简单讲就是所谓的线上,就是正式给用户使用的环境。
例子:
代码语言:javascript复制const _axios = axios.create({
baseURL: 'http://localhost:8080',
withCredentials: true
});
await _axios.post('/api/a6set')
await _axios.post('/api/a6get')
- 生产环境希望 xhr 请求不走代理,可以用 baseURL 统一修改(前端不用代理时,后端记得使用
Access-Control-Allow-Origin
头。) 使用代理的方式主要是用在开发环境,中间经过代理,性能肯定会受到影响,真正生存环境中解决跨域问题是不用代理的。 - 希望跨域请求携带 cookie,需要配置 withCredentials: true,服务器也要配置 allowCredentials = true,否则浏览器获取跨域返回的 cookie 时会报错 w.Header().Set("Access-Control-Allow-Credentials", "true")
6. 响应格式
名称 | 含义 |
---|---|
data | 响应体数据 ⭐️ |
status | 状态码 ⭐️ |
headers | 响应头 |
- 200 表示响应成功
- 400 请求数据不正确 age=abc
- 401 身份验证没通过
- 403 没有权限(这个是身份验证通过了,但是你要访问更高权限的资源时,会出现403)
- 404 资源不存在
- 405 不支持请求方式 post
- 500 服务器内部错误
注意: 这个status响应状态码与后端经常返回的code不一样,后端返回的code可以根据项目来设置,比如用1001表示错误1,1002表示错误2... 后端经常返回的code时候应用程序的状态码 这个status则是整个响应的状态码,是HTTP协议固定好的。
例子:
响应状态码200以下都会正常进行,200以上会出现异常,不在往下执行。
代码语言:javascript复制<template>
<div>
<input type="button" value="获取远程数据" v-on:click="sendRequest()">
</div>
</template>
<script>
// 导入axiso
import axios from 'axios'
const options = {
methods: {
async sendRequest() {
const newAxios = new axios.create({
baseURL: "http://localhost:8080",
withCredentials: true
})
// 访问一个不存在的资源--->404,
const resp = await newAxios.get('/api/students2');
console.log(resp)
}
}
};
export default options
</script>
可以看到,报错了,且没有继续往下执行:
可以使用try-catch捕获异常
代码语言:javascript复制try {
const resp = await newAxios.get('/api/students2');
console.log(resp)
} catch (error) {
console.log(error.response)
}
7. 拦截器
1. 请求拦截器
代码语言:javascript复制_axios.interceptors.request.use(
function(config) {
// 比如在这里添加统一的 headers
return config;
},
function(error) {
return Promise.reject(error);
}
);
代码语言:javascript复制// 拦截器:
newAxios.interceptors.request.use(
function (config) {
// 比如在这个添加统一的headers
config.headers = {
Authorization: "aaa.bbb.ccc"
}
return config;
},
function (error) {
return Promise.reject(error);
}
)
2. 响应拦截器
- 参数为两个函数,第一个函数时响应正常的情况下执行的拦截操作,第二个是响应出错的情况下执行的拦截操作。
- 例子: 可以帮助我们统一处理异常,之前的时候,一旦响应出现异常,都需要自己加try-catch,而如果加了响应拦截器,所有异常都可以放在第二个函数里处理。
_axios.interceptors.response.use(
function(response) {
// 状态码在 2xx 范围内走这里
return response;
},
function(error) {
// 状态码 超出 2xx, 比如 4xx, 5xx 走这里
return Promise.reject(error);
}
);
return Promise.reject(error);
相当于抛出了异常
外层如果没有捕捉的话,还是会在控制台显示出错误的,如果想要达到类似于捉住异常的效果,应该这样写:
代码语言:javascript复制// 响应拦截器:
newAxios.interceptors.response.use(
function (response) {
return response;
},
function (error) {
switch (error.response.status) {
case 400:
console.log("请求参数不正确")
return
case 401:
console.log("认证未通过,跳转至登录页面")
return
case 403:
console.log("权限不够")
return
case 404:
console.log("资源未找到")
return
case 500:
console.log("服务器异常")
return
}
//
return Promise.reject(error);
}
)
newAxios.get("/api/jwt")
在本部分我们自己创建了axiso对象,并且配置了请求拦截器和响应拦截器,这些代码具有一定通用性,我们没有必要在每个vue组件里都写一遍,所以像这种具有通用性的代码,我们可以把他们单独抽到一个js文件里:
/src/util/myaxiso.js
// 导入axiso
import axios from 'axios'
const newAxios = new axios.create({
baseURL: "http://localhost:8080",
withCredentials: true
});
// 请求拦截器:
newAxios.interceptors.request.use(
function (config) {
// 比如在这个添加统一的headers
config.headers = {
Authorization: "aaa.bbb.ccc"
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
// 响应拦截器:
newAxios.interceptors.response.use(
function (response) {
return response;
},
function (error) {
switch (error.response.status) {
case 400:
console.log("请求参数不正确")
return Promise.resolve(400)
case 401:
console.log("认证未通过,跳转至登录页面")
return Promise.resolve(401)
case 403:
console.log("权限不够")
return Promise.resolve(403)
case 404:
console.log("资源未找到")
return Promise.resolve(404)
case 500:
console.log("服务器异常")
return Promise.resolve(500)
}
return Promise.reject(error);
}
);
// 将自己的axiso默认导出,让其他地方使用
export default newAxios;
之后我们就可以在vue组件里,使用这个js文件了:
代码语言:javascript复制<template>
<div>
<input type="button" value="获取远程数据" v-on:click="sendRequest()">
</div>
</template>
<script>
// 导入自己的axiso
import axios from "../util/myaxiso";
const options = {
methods: {
async sendRequest() {
const resp = await axios.get("/api/students")
console.log(resp)
}
}
};
export default options
</script>
7. 条件渲染 列表渲染
上面讲述的axios
知识主要是为了接下来的vue小案例,这个案例里就可以使用axios
,获取服务端的一些真实数据了,通过这个案例可以学到vue里的条件渲染与列表渲染。
<template>
<div>
<input type="button" value="获取远程数据" v-on:click="sendReq()">
<div class="title">学生列表</div>
<div class="thead">
<div class="row bold">
<div class="col">编号</div>
<div class="col">姓名</div>
<div class="col">性别</div>
<div class="col">年龄</div>
</div>
</div>
<!-- 要求:如果没有学生数据,做出处理 -->
<!-- vue里v打头的这个叫做指令 -->
<div class="tbody">
<div v-if="students.length>0">
<!-- v-for 循环遍历,in of 都可以 -->
<!-- 注意:使用v-for的时候,需要v-bind:key='可以唯一标识的字段' -->
<div class="row" v-for="stu of students" v-bind:key="stu.ID">
<div class="col">{{stu.ID}}</div>
<div class="col">{{stu.Name}}</div>
<div class="col">{{stu.Sex}}</div>
<div class="col">{{stu.Age}}</div>
</div>
</div>
<div v-else>
暂无学生数据
</div>
</div>
</div>
</template>
<script>
import axios from '../util/myaxiso'
const options = {
data: function () {
return { students: [] };
},
methods: {
async sendReq() {
const resp = await axios.get("/api/students")
// 要把服务端返回的data数据赋值给我们的data方法里的students
// 因为我们页面上的这些模板需要进行数据绑定,或者数据需要进行条件判断,
// 数据必须来自我们options的data数据对象,不可以直接来自response数据
// console.log(resp.data.data)
this.students = resp.data.data
}
},
};
export default options
</script>
<!-- scoped: 样式仅影响当前组件,不影响其他组件 -->
<style scoped>
div {
font-family: 华文行楷;
font-size: 20px;
}
.title {
margin-bottom: 10px;
font-size: 30px;
color: #333;
text-align: center;
}
.row {
background-color: #fff;
display: flex;
justify-content: center;
}
.col {
border: 1px solid #007acc;
width: 15%;
height: 35px;
text-align: center;
line-height: 35px;
}
.bold .col {
background-color: #f1f1f1;
}
</style>
但是当前的页面实现是,我们必须点一下按钮,才去服务器获取学生数据,能不能加载页面的时候就获取呢?
只需要在options对象里再加入一个方法属性mounted
:
<script>
import axios from '../util/myaxiso'
const options = {
data: function () {
return { students: [] };
},
methods: {
async sendReq() {
const resp = await axios.get("/api/students")
this.students = resp.data.data
}
},
mounted:function(){
this.sendReq()
}
};
export default options
</script>
这样就可以在加载页面的时候就获取数据了。
注意:
- v-if 和 v-for 不能用于同一个标签
- v-for 需要配合特殊的标签属性 key 一起使用,并且 key 属性要绑定到一个能起到唯一标识作用的数据上,本例绑定到了学生编号上
- options 的 mounted 属性对应一个函数,此函数会在组件挂载后(准备就绪)被调用,可以在它内部发起请求,去获取学生数据
8. 重用组件
我们页面上肯定有很多HTML 或者JS 代码,具备一定的重用性,那么我们可不可以吧这些可重用的代码集中起来,形成一个可重用的组件呢? 可重用的组件一般放在/src/components
里:
按钮组件
代码语言:javascript复制 <template>
<div class="button primary middle">
a<slot></slot>b
</div>
</template>
<script>
const options = {};
export default options;
</script>
<style scoped>
...
</style>
- 注意,省略了样式部分
<slot>
:插槽,起到占位的作用,后面你在父组件里my-button
标签里写的数据会被展示到页面,否则子组件是不会使用父组件里写在my-button
里的数据的。
使用组件
- 导入子组件。
- 页面内导入子组件标签。
<template>
<div>
<h1>父组件</h1>
<!--2. 页面内导入子组件标签-->
<my-button>1</my-button>
<my-button>2</my-button>
<my-button>3</my-button>
</div>
</template>
<script>
// 导入子组件
import MyButton from '../components/MyButton.vue'
const options = {
components: {
// 简写形式:
// "MyButton":MyButton
MyButton
}
};
export default options;
</script>
components
属性:表示当前父组件要使用哪些子组件。- vue里子组件名字为大驼峰对应的HTML标签就是
my-button
但是上面那种子组件还不够通用,他的颜色和大小样式是写死的,那能不能让他采用什么样式都是由父组件传入的呢?
采用自定义属性
代码语言:javascript复制 <template>
<div>
<h1>父组件</h1>
<!--2. 页面内导入子组件标签,-->
<my-button type="primary" size="small">1</my-button>
<my-button type="danger" size="middle">2</my-button>
<my-button type="success" size="large">3</my-button>
</div>
</template>
<script>
// 导入子组件
import MyButton from '../components/MyButton.vue'
const options = {
components: {
// 简写形式:
// "MyButton":MyButton
MyButton
}
};
export default options;
</script>
代码语言:javascript复制 <template>
<div class="button" v-bind:class="[type,size]">
a<slot></slot>b
</div>
</template>
<script>
const options = {
props: ["type", "size"]
};
export default options;
</script>
<style>
...
</style>
props
:自定义属性,父组件向子组件传值。
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!