前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅学前端:Vue篇(一)

浅学前端:Vue篇(一)

原创
作者头像
传说之下的花儿
修改2023-11-12 17:37:17
2490
修改2023-11-12 17:37:17
举报

1. Vue 基础

1) 环境准备

1. 安装脚手架
代码语言:javascript
复制
 npm install -g @vue/cli
  • -g 参数表示全局安装,这样在任意目录都可以使用 vue 脚本创建项目
2. 创建项目
代码语言:javascript
复制
 vue ui

使用图形向导来创建 vue 项目,如下图:

  1. 输入项目名,包管理器选择npm

不想用git,可以取消勾选初始化git仓库,也可以创建完之后,删除.git文件夹

  1. 选择手动配置项目
  1. 添加 vue router 和 vuex

一个是实现组件之间的跳转,一个是实现组件之间数据的共享。

  1. 选择版本,创建项目

安装完毕后会跳转到一个页面:

3. 安装 devtools

官方浏览器插件,用于调试 Vue.js 应用。你可以检查组件、vuex store 和事件等。

4. 运行项目

进入项目目录,执行

代码语言:javascript
复制
 npm run serve

启动成功:

5. 修改端口

前端服务器默认占用了 8080 端口,需要修改一下

  • 打开 vue.config.js 添加
代码语言:javascript
复制
 const { defineConfig } = require('@vue/cli-service')  module.exports = defineConfig({    // ...    devServer: {      port: 8082 // 设置前端服务器端口    }  })

6. 添加代理

为了避免前后端服务器联调时, fetch、xhr 请求产生跨域问题,需要配置代理

  • 文档地址同上
  • 打开 vue.config.js 添加
代码语言:javascript
复制
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:\code\VScodeProjects\fountendstudy\study03-vue2> tree src
 D:\CODE\VSCODEPROJECTS\FOUNTENDSTUDY\STUDY03-VUE2\SRC
 ├─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:

代码语言:javascript
复制
 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>
  • {{}} 里只能绑定一个属性,绑定多个属性需要用多个 {{}} 分别绑定:
代码语言:javascript
复制
<template>
    <h1>{{name age}}</h1>
</template>

// 会编译报错。
  • template 内只能有一个根元素:
代码语言:javascript
复制
<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:
代码语言:javascript
复制
<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 所以需要进行编码:
代码语言:javascript
复制
const name = encodeURIComponent('&&&');
  • 使用请求体发数据(格式为 urlencoded)的时候,不可以直接传入一个普通对象,因为这里的普通对象默认是json格式:
代码语言:javascript
复制
const resp = await axios.post('/api/a4', {
    name: "123",
    age: 20
});
console.log(resp)
  • 我们打开F12,查看这个请求的信息,可以看到我们这样写,对应的数据格式Content-Type: application/json。后端对于json类型,需要配合对象去接收:
代码语言:javascript
复制
× //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,而如果加了响应拦截器,所有异常都可以放在第二个函数里处理。

代码语言:javascript
复制
_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

代码语言:javascript
复制
 // 导入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里的条件渲染与列表渲染。

代码语言:javascript
复制
 <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

代码语言:javascript
复制
<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里的数据的。

使用组件

  1. 导入子组件。
  2. 页面内导入子组件标签。
代码语言:javascript
复制
 <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腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Vue 基础
    • 1) 环境准备
      • 1. 安装脚手架
      • 2. 创建项目
      • 3. 安装 devtools
      • 4. 运行项目
      • 5. 修改端口
      • 6. 添加代理
      • 7. Vue 项目结构
    • 2) Vue 组件
      • 1. 文本插值
      • 2. 属性绑定
      • 3. 事件绑定
      • 4. 双向绑定
      • 5. 计算属性
      • 6. axios
      • 7. 条件渲染+列表渲染
      • 8. 重用组件
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档