当前位置: 首页 > news >正文

【Vue2基础】Vue项目搭建及组件使用

1. Vue2 基础

1) 环境准备

安装脚手架

npm install -g @vue/cli
  • -g 参数表示全局安装,这样在任意目录都可以使用 vue 脚本创建项目

创建项目

vue ui

使用图形向导来创建 vue 项目,如下图,输入项目名

image-20220815141136895

选择手动配置项目

image-20220815141312244

添加 vue router 和 vuex

image-20220815141412380

选择版本,创建项目

image-20220815141459878

安装 devtools

  • devtools 插件网址:https://devtools.vuejs.org/guide/installation.html

image-20220815141648040

运行项目

进入项目目录,执行

npm run serve

修改端口

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

  • 文档地址:DevServer | webpack

  • 打开 vue.config.js 添加

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
      
      // ...
        
      devServer: {
        port: 7070
      }
      
    })
    

添加代理

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

  • 文档地址同上

  • 打开 vue.config.js 添加

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
        
      // ...
        
      devServer: {
        port: 7070,
        proxy: {
          '/api': {		//如localhost:8080/api/**的所有请求都会走代理
            target: 'http://localhost:8080',
            changeOrigin: true
          }
        }
      }
        
    })
    

Vue 项目结构

PS D:\2022.js\代码\第3章\client> tree src
D:\2022.JS\代码\第3章\CLIENT\SRC
├─assets
├─components
├─router
├─store
└─views
  • assets - 静态资源
  • components - 可重用组件
  • router - 路由
  • store - 数据共享
  • views - 视图组件

以后还会添加

  • api - 跟后台交互,发送 fetch、xhr 请求,接收响应
  • plugins - 插件

2) Vue 组件

Vue 的组件文件以 .vue 结尾,每个组件由三部分组成

<template></template>

<script></script>

<style></style>
  • template 模板部分,由它生成 html 代码
  • script 代码部分,控制模板的数据来源和行为
  • style 样式部分,一般不咋关心

入口组件是 App.vue

先删除原有代码,来个 Hello, World 例子

<template>
  <h1>{{msg}}</h1>
</template>

<script>
export default {
  data() {
    return {
      msg: "Hello, Vue!"
    }
  }
}
</script>

解释

  • export default 导出组件对象,供 main.js 导入使用
  • 这个对象有一个 data 方法,返回一个对象,给 template 提供数据
  • {{}} 在 Vue 里称之为插值表达式,用来绑定 data 方法返回的对象属性,绑定的含义是数据发生变化时,页面显示会同步变化

文本插值

<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 内只能有一个根元素
  • 插值内可以进行简单的表达式计算

属性绑定

<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 只保留冒号

事件绑定

<!-- 事件绑定 -->
<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>
  • 简写方式:可以把 v-on: 替换为 @
  • 在 methods 方法中的 this 代表的是 data 函数返回的数据对象

双向绑定

<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 这边
  • 双向绑定只适用于表单这种带【输入】功能的标签,其它标签的数据绑定,单向就足够了
  • 复选框这种标签,双向绑定的 javascript 数据类型一般用数组

计算属性

<!-- 计算属性 -->
<template>
    <div>
        <!-- <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;
  • 普通方法调用必须加 (),没有缓存功能
  • 计算属性使用时就把它当属性来用,不加 (),有缓存功能
    • 一次计算后,会将结果缓存,下次再计算时,只要数据没有变化,不会重新计算,直接返回缓存结果

axios

axios 它的底层是用了 XMLHttpRequest(xhr)方式发送请求和接收响应,xhr 相对于之前讲过的 fetch api 来说,功能更强大,但由于是比较老的 api,不支持 Promise,axios 对 xhr 进行了封装,使之支持 Promise,并提供了对请求、响应的统一拦截功能

安装

npm install axios -S

导入

import axios from 'axios'
  • axios 默认导出一个对象,这里的 import 导入的就是它默认导出的对象

方法

请求备注
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 携带请求体

例子

<template>
    <div>
        <input type="button" value="获取远程数据" @click="sendReq()">
    </div>
</template>
<script>
import axios from 'axios'
const options = {
    methods: {
        async sendReq() {
            // 1. 演示 get, post
            // const resp = await axios.post('/api/a2');

            // 2. 发送请求头
            // const resp = await axios.post('/api/a3',{},{
            //     headers:{
            //         Authorization:'abc'
            //     }
            // });

            // 3. 发送请求时携带查询参数 ?name=xxx&age=xxx
            // const name = encodeURIComponent('&&&');
            // const age = 18;
            // const resp = await axios.post(`/api/a4?name=${name}&age=${age}`);

            // 不想自己拼串、处理特殊字符、就用下面的办法
            // const resp = await axios.post('/api/a4', {}, {
            //     params: {
            //         name:'&&&&',
            //         age: 20
            //     }
            // });

            // 4. 用请求体发数据,格式为 urlencoded
            // const params = new URLSearchParams();
            // params.append("name", "张三");
            // params.append("age", 24)

            // const resp = await axios.post('/api/a4', params);

            // 5. 用请求体发数据,格式为 multipart
            // const params = new FormData();
            // params.append("name", "李四");
            // params.append("age", 30);
            // const resp = await axios.post('/api/a5', params);

            // 6. 用请求体发数据,格式为 json
            const resp = await axios.post('/api/a5json', {
                name: '王五',
                age: 50
            });

            console.log(resp);
        }
    }
};
export default options;
</script>

创建实例

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

const _axios = axios.create({
    baseURL: 'http://localhost:8080',
    withCredentials: true
});
await _axios.post('/api/a6set')
await _axios.post('/api/a6get')
  • 生产环境希望 xhr 请求不走代理,可以用 baseURL 统一修改
  • 希望跨域请求携带 cookie,需要配置 withCredentials: true,服务器也要配置 allowCredentials = true,否则浏览器获取跨域返回的 cookie 时会报错

响应格式

名称含义
data响应体数据 ⭐️
status状态码 ⭐️
headers响应头
  • 200 表示响应成功
  • 400 请求数据不正确 age=abc
  • 401 身份验证没通过
  • 403 没有权限
  • 404 资源不存在
  • 405 不支持请求方式 :如接受的请求为Get,发送的请求post
  • 500 服务器内部错误

请求拦截器(发送请求到服务端时拦截)

_axios.interceptors.request.use(
  function(config) {
    // 比如在这里添加统一的 headers
    return config;
  },
  function(error) {
    return Promise.reject(error);
  }
);

响应拦截器(服务端响应数据后进行拦截)

_axios.interceptors.response.use(
  function(response) {
    // 2xx 范围内走这里
    return response;
  },
  function(error) {
    // 超出 2xx, 比如 4xx, 5xx 走这里
    return Promise.reject(error);
  }
);

条件渲染

<template>
    <div>
        <input type="button" value="获取远程数据" @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>
        <div class="tbody">
            <div class="row" v-if="students.length > 0">显示学生数据</div>
            <div class="row" v-else>暂无学生数据</div>
        </div>
    </div>
</template>
<script>
import axios from '../util/myaxios'
const options = {
    data: function() {
        return {
            students: []
        };
    },
    methods : {
        async sendReq() {
            const resp = await axios.get("/api/students");
            console.log(resp.data.data)
            this.students = resp.data.data;
        }
    }
};
export default options;
</script>
<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 #f0f0f0;
        width: 15%;
        height: 35px;
        text-align: center;
        line-height: 35px;
    }

    .bold .col {
        background-color: #f1f1f1;
    }
</style>

列表渲染

<template>
    <div>
        <!-- <input type="button" value="获取远程数据" @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>
        <div class="tbody">
            <div v-if="students.length > 0">
                <div class="row" v-for="s of students" :key="s.id">
                    <div class="col">{{s.id}}</div>
                    <div class="col">{{s.name}}</div>
                    <div class="col">{{s.sex}}</div>
                    <div class="col">{{s.age}}</div>
                </div>
            </div>
            <div class="row" v-else>暂无学生数据</div>
        </div>
    </div>
</template>
<script>
import axios from '../util/myaxios'
const options = {
    mounted: function(){
        this.sendReq()
    },
    data: function() {
        return {
            students: []
        };
    },
    methods : {
        async sendReq() {
            const resp = await axios.get("/api/students");
            console.log(resp.data.data)
            this.students = resp.data.data;
        }
    }
};
export default options;
</script>
  • v-if 和 v-for 不能用于同一个标签
  • v-for 需要配合特殊的标签属性 key 一起使用,并且 key 属性要绑定到一个能起到唯一标识作用的数据上,本例绑定到了学生编号上
  • options 的 mounted 属性对应一个函数,此函数会在组件挂载后(准备就绪)被调用,可以在它内部发起请求,去获取学生数据

重用组件

按钮组件

<template>
    <div class="button" :class="[type,size]">
        a<slot></slot>b
    </div>
</template>
<script>
const options = {
    props: ["type", "size"]
};
export default options;
</script>
  • 注意,省略了样式部分

使用组件

<template>
    <div>
        <h1>父组件</h1>
        <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
    }
};
export default options;
</script>

相关文章:

  • 艾美捷衣霉素Tunicamycin 化学性质及引用文献
  • 【小样本分割】Self-Support Few-Shot Semantic Segmentation
  • ch01变量和数据结构
  • 五分钟学会一门编程语言?
  • 【Python数据分析 - 11】:DataFrame索引操作(pandas篇)
  • [Vue]数据代理
  • VSCODE 系列(二)常用插件
  • 【zabbix】解决zabbix在web页面显示中文乱码问题
  • ESP32/ESP8266自动下载电路波形,ESP32/ESP8266不能UART流控自动下载的解决方法
  • c语言分层理解(枚举和联合体)
  • 网站死链抓取sitemap递交工具
  • 大意了,一次多线程操作不当导致的线上事故...
  • [Spring boot] Spring boot 实现Excel批量导入数据并将文件保存到本地
  • linux下安装javaJDK和hadoop
  • Java数据结构——代码实现双向链表的方法
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 07.Android之多媒体问题
  • 77. Combinations
  • CentOS从零开始部署Nodejs项目
  • IDEA 插件开发入门教程
  • iOS编译提示和导航提示
  • Java教程_软件开发基础
  • MQ框架的比较
  • Mybatis初体验
  • Redis在Web项目中的应用与实践
  • sessionStorage和localStorage
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • Vue官网教程学习过程中值得记录的一些事情
  • Webpack 4 学习01(基础配置)
  • windows下mongoDB的环境配置
  • 阿里云购买磁盘后挂载
  • 对象引论
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 入手阿里云新服务器的部署NODE
  • 用element的upload组件实现多图片上传和压缩
  • 运行时添加log4j2的appender
  • 智能网联汽车信息安全
  • Mac 上flink的安装与启动
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #stm32驱动外设模块总结w5500模块
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (33)STM32——485实验笔记
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (8)STL算法之替换
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (附源码)ssm码农论坛 毕业设计 231126
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (南京观海微电子)——I3C协议介绍
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (幽默漫画)有个程序员老公,是怎样的体验?