The third stop of front-end learning - Vue2 basics

Table of contents

1. Environment preparation

1.1 Install scaffolding

1.2 Create a project 

1.3 install vue devtools

1.4 Running the project

2 Vue components 

2.1 Text Interpolation 

2.2 Attribute binding v-bind

2.3 Event binding v-on

 2.4 Calculated attribute computed

2.5 The principle of Vue's underlying display interface 

 3. Axios

4. List rendering v-for and conditional rendering v-if


1. Environment preparation

1.1 Install scaffolding

npm install -g @vue/cli
  • The -g parameter means global installation, so that you can use vue scripts to create projects in any directory

1.2 Create a project 

Go to the directory where you want to create the server, open the command window, and execute the command

vue ui

This means to use the graphical interface wizard to create a vue project, and jump out of this interface after running

  Select manual configuration items

 Add vue router and vuex

 Select version, create project

This will automatically generate the vue project in the folder~ 

1.3 install vue devtools

This is a browser plug-in that can debug vue projects, very easy to use

 If you can't access the Google Play Store, you can try the following methods.

1. Go to a plug-in download website first to download the plug-in

After successful download and decompression, there will be a .crx suffix file as shown below.

2. Open Google Chrome, click the three dots in the upper right corner, more tools - extensions 

Go to the following page and turn on the developer mode in the upper right corner. 

Then drag the downloaded .crx suffix file into this browser page. 

1.4 Running the project

Enter the project directory, prowershell window, execute the command

npm run serve

If an error is reported, try to run prowershell as an administrator, then enter the project directory, and execute the above command.

modify port

If the front-end server occupies the back-end port 8080 by default, it can be modified

Open the vue.config.js file to add

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

add agent

In order to avoid cross-domain problems caused by fetch and xhr requests when the front-end and back-end servers are jointly debugged , a proxy needs to be configured

Open the vue.config.js file to add

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
    
  // ...
    
  devServer: {
    port: 7070,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  }
    
})

 Vue's project structure

  • assets - static resources

  • components - Reusable components

  • router - router

  • store - data sharing

  • views - the view components

will be added later

  • api - Interact with the background, send fetch and xhr requests, and receive responses

  • plugins - plugins

2 Vue components 

Vue's component files end with .vue, and each component consists of three parts

<template></template>

<script></script>

<style></style>
  • template template part, which generates html code

  • The script code section controls the data source and behavior of the template

  • style The style part, generally don't care about it

The entry component is App.vue

First delete the original code, let's take a Hello, World example

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

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

explain

  • export default export component object for main.js import

  • This object has a data method that returns an object that provides data to the template

  • { {}}In Vue, it is called an interpolation expression , which is used to bind the object properties returned by the data method . The meaning of binding is that when the data changes, the page display will change synchronously

2.1 Text Interpolation 

<template>
    <div>
        <h1>{
   
   { name }}</h1>
        <h1>{
   
   { age > 60 ? '老年' : '青年' }}</h1>
    </div>
</template>
<script>
const options = {
    data: function () {
        return { name: '张三', age: 70 };
    }
};
export default options;
</script>
  • { {}}Only one property can be bound here, multiple properties need to be { {}}bound separately

  • There can only be one root element in the template

  • Simple expression calculations can be performed within interpolation

2.2 Attribute binding v-bind

Vue can bind components and time. The following code

<template>
    <div>
        <!-- 属性绑定 v-bind -->
        <div><input type="text" v-bind:value="name"/></div>
        <div><input type="date" v-bind:value="birthday"/></div>
        <!-- v-bind简写 v-bind可以省略 -->
        <div><input type="text" :value="age"/></div>
    </div>
    
</template>
<script>
    const options = {
        data:function(){
            return {name: '张三',birthday: '1995-01-01',age: 18}
        }
    }
    export default options;
</script>
  • Shorthand: you can omit v-bind and only keep the colon

2.3 Event binding v-on

<!-- 事件绑定 -->
<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>
  • Shorthand: You can replace v-on: with @

  • This in the methods method represents the data object returned by the data function

 2.4 Calculated attribute computed

<!-- 计算属性 -->
<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;
  • Ordinary method calls must add (), there is no caching function

  • When the calculated attribute is used, it is used as an attribute without adding (), and it has a cache function:

    • After a calculation, the result will be cached. When the calculation is performed next time, as long as the data has not changed, the calculation will not be recalculated, and the cached result will be returned directly.

2.5 The principle of Vue's underlying display interface 

Here is an example of our App.vue. Because it comes with the vue project after it is created

First, import App.vue into the main.js file 

 

Then execute the render in new Vue in main.js 

So, what is this #app file? In fact, it has been created by default for us in the vue project 

As shown in the picture:

This is how vue renders components to the page~ 

 3. Axios

 The bottom layer of axios is to use XMLHttpRequest (xhr) to send requests and receive responses. Compared with the fetch api mentioned earlier, xhr has more powerful functions, but because it is an older api, it does not support Promise. Axios implements xhr for xhr Encapsulate, make it support Promise, and provide a unified interception function for requests and responses

Install

npm install axios -S

import

import axios from 'axios'
  • Axios exports an object by default, and the import here imports the object it exports by default

method

ask Remark
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 - options object, e.g. query parameters, request headers...

  • data - request body data, most commonly in json format

  • Get and head requests cannot carry the request body, which should be caused by browser restrictions (xhr and fetch api have restrictions)

  • options and delete requests can carry the request body through the data in config

Code demonstration (this includes sending get and post requests, sending request headers, sending with query parameters, sending data with a request body in urlencode format, sending data with a request body in multipart format, and sending data with a request body in json format) 

Code: Prompt, here I have configured cross-domain issues, /stu represents localhost:8080,

Front-end code:

<template>
<!-- axios -->
    <div>
        {
   
   {data}}
        <input type="button" value="点击获取数据" @click="sendAsync">
    </div>
    
</template>

<script>
/* 导入axios */
import axios from '../util/myaxios'
    const options = {
        data:function(){
            return { data:''}
        },
        methods: {
            async sendAsync(){
                // 发送 get请求
                // const resp = await axios.get('stu/a1');

                //发送 post请求,需要携带一个参数对象,这里为空对象
                // const resp = await axios.post('stu/a2',{});

                //发送请求头,除了请求地址,参数,还有config对象
                // const resp = await axios.post('stu/a3',{},{
                //     headers:{
                //         Authorization: 'authorization'
                //     }
                // });

                //发送请求时携带查询参数, url?name=xxx&age=xxx
                /* 第一种方法,拼接字符串 */
                // const name = encodeURIComponent('&&&');
                // const age = 18;
                // const resp = await axios.post(`stu/a4?name=${name}&age=${age}`);
                /* 只是这种方法对于特殊字符串,需要重新编码 ,例如&&&*/

                /* 
                    第二种方法,就是在config对象中设置param对象 
                    这种方法会自动对特殊字符进行重新编码
                */
                // const resp = await axios.post('stu/a4',{},{
                //     params:{
                //         name: '&&&',
                //         age: 18
                //     }
                // });

                //用请求体发送数据,格式为urlencoded
                // const param = new URLSearchParams();
                // param.append('name','张三');
                // param.append('age','18');
                // const resp = await axios.post('stu/a4',param);

                //用请求体发送数据,格式为 multipart
                // const param = new FormData();
                // param.append('name','李四');
                // param.append('age','19');
                // const resp = await axios.post('stu/a4',param);


                // //用请求体发送数据,格式为json,需在后端加上@RequestBody注解
                // const resp = await axios.post('stu/a5',{
                //     name: '张三',
                //     age: 18
                // });

               
                this.data = resp.data
                console.log(resp)
            },
            sendSync(){
                axios.get('stu/student')
                .then(resp =>{
                    console.log(resp)
                    this.data = resp.data
                })
            }
        }
    }
    export default options;
</script>

rear end:

For convenience, the code is written in the Controller layer

package com.hua.controller;

import com.hua.domain.A5;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;

/**
 * @Author 华子
 * @Date 2023/1/8 15:51
 * @Version 1.0
 */
@Controller
@RequestMapping("stu")
public class AxiosController {

    @GetMapping("/a1")
    @ResponseBody
    public String a1(){
        return "get request";
    }

    @PostMapping("/a2")
    @ResponseBody
    public String a2(){
        return "post request";
    }

    @PostMapping("/a3")
    @ResponseBody
    public String a3(@RequestHeader("Authorization") String authorization){
        System.out.println("Authorization:"+authorization);
        return "post request";
    }

    @PostMapping("/a4")
    @ResponseBody
    public String a4(String name, Integer age){
        System.out.println("name:"+name+",age:"+age);
        return "post request";
    }

    @PostMapping("/a5")
    @ResponseBody
    public String a5(@RequestBody A5 a5){
        System.out.println("name:"+a5.getName()+",age:"+a5.getAge());
        return "post request";
    }

    @PostMapping("/a6Set")
    @ResponseBody
    public String a6Set(HttpSession session){
        System.out.println("==========a6Set==============");
        System.out.println(session.getId());
        session.setAttribute("name","张三");
        return "post request";
    }

    @PostMapping("/a6Get")
    @ResponseBody
    public String a6Get(HttpSession session){
        System.out.println("==========a6Get==============");
        System.out.println(session.getId());
        System.out.println(session.getAttribute("name"));
        return "post request";
    }

}

Axios can be configured by default

create instance

const _axios = axios.create(config);
  • The axios object can be used directly, but the default settings are used

  • Objects created with axios.create can override the default settings, see the description below for config

Common config items are  

name meaning
baseURL will be automatically added in front of the url
headers request header, the type is a simple object
params The request parameters following the URL, of type Simple Object or URLSearchParams
data Request body, types include simple object, FormData, URLSearchParams, File, etc.
withCredentials Whether to carry credentials such as cookies when crossing domains, the default is false
responseType Response type, default is json

example

const _axios = axios.create({
    baseURL: 'http://localhost:8080',
    withCredentials: true
});
await _axios.post('/api/a6set')
await _axios.post('/api/a6get')
  • In the production environment, it is hoped that the xhr request will not go through the proxy, and can be modified uniformly with baseURL

  • If you want to carry cookies in cross-domain requests, you need to configure withCredentials: true, and the server must also configure allowCredentials = true, otherwise the browser will report an error when obtaining the cookie returned by cross-domain

Here is a default written axios configuration~

myaxios.js file (there are interceptors inside, including request and response interceptors)

import axios from 'axios'
const _axios = axios.create({
    // baseURL: 'http://localhost:8080',
    withCredentials: true
});

// 9. 拦截器
_axios.interceptors.request.use(
    function (config) {
        // 比如在这里添加统一的 headers
        config.headers = {
            Authorization: 'aaa.bbb.ccc'
        }
        return config;
    },
    function (error) {
        return Promise.reject(error);
    }
);

_axios.interceptors.response.use(
    function (response) {
        // 2xx 范围内走这里
        return response;
    },
    function (error) {
        if (error.response?.status === 400) {
            console.log('请求参数不正确');
            return Promise.resolve(400);
        } else if (error.response?.status === 401) {
            console.log('跳转至登录页面');
            return Promise.resolve(401);
        } else if (error.response?.status === 404) {
            console.log('资源未找到');
            return Promise.resolve(404);
        }
        // 超出 2xx, 比如 4xx, 5xx 走这里
        return Promise.reject(error);
    }
);

export default _axios;

We can write this by importing axios

4. List rendering v-for and conditional rendering v-if

Here is an example to show

Take the student data from the back end and display it to the front end

<template>
    <div>
        <!-- <input type="button" value="点击获取数据" @click="sendAsync"> -->
        <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"> 
            <!-- 条件渲染v-if:如果读取到学生数据不为空,就展示 -->
            <div v-if="students.length > 0">
                <!-- 列表渲染v-for,循环得到的学生数据并展示 -->
                <div class="row" v-for="student of students" :keys="student.id">
                    <div class="col">{
   
   {student.id}}</div>
                    <div class="col">{
   
   {student.name}}</div>
                    <div class="col">{
   
   {student.sex}}</div>
                    <div class="col">{
   
   {student.age}}</div>
                </div>  
            </div>
            <!-- 如果为空 -->
            <div class="row" v-else>暂无学生数据</div>
        </div>
    </div>
</template>
<script>
    import axios from  '../util/myaxios'
    const options = {
        mounted: function(){
            this.sendAsync();
        },
        data: function(){
            return {
                students: []
            }
        },
        methods:{
            async sendAsync(){
               const resp = await axios.get('stu/student');
               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>

Reuse components :

The main syntax is to define a common component in the components folder, that is, a subcomponent

Then import it into the parent component

<script>
    import MyButton from  '../components/MyButton.vue'
    const options = {
       components:{
           MyButton
       }
    }
    export default options;
</script>

Label it in the parent component.

<template>
<!-- 可重用组件 -->
    <div>
       <h1>父组件</h1>
       <div>
           <h2>子组件</h2>
           <my-button>1</my-button>
       </div>
    </div>
</template>

 Specific code:

Subcomponent MyButtons:

<template>
    <div class="button" :class="[type,size]">
        <slot></slot><!-- 加入插槽,可以在父组件中添加按钮名称 -->
    </div>
</template>
<script>
const options = {
    props:["type","size"]
};
export default options;
</script>
<style scoped>
.button {
    display: inline-block;
    text-align: center;
    border-radius: 30px;
    margin: 5px;
    font: bold 12px/25px Arial, sans-serif;
    padding: 0 2px;
    text-shadow: 1px 1px 1px rgba(255, 255, 255, .22);
    box-shadow: 1px 1px 1px rgba(0, 0, 0, .29), inset 1px 1px 1px rgba(255, 255, 255, .44);
    transition: all 0.15s ease;
}

.button:hover {
    box-shadow: 1px 1px 1px rgba(0, 0, 0, .29), inset 1px 1px 2px rgba(0, 0, 0, .5);
}

.button:active {
    box-shadow: inset 1px 1px 2px rgba(0, 0, 0, .8);
}

.primary {
    background-color: #1d6ef9;
    color: #b5e3f1;
}

.danger {
    background-color: rgb(196, 50, 50);
    color: white;
}

.success {
    background-color: #a5cd4e;
    ;
    color: #3e5706;
}

.small {
    width: 40px;
    height: 20px;
    font-size: 10px;
    line-height: 20px;
}

.middle {
    width: 50px;
    height: 25px;
    font-size: 14px;
    line-height: 25px;
}

.large {
    width: 60px;
    height: 30px;
    font-size: 18px;
    line-height: 30px;
}
</style>

parent component:

<template>
<!-- 可重用组件 -->
    <div>
       <h1>父组件</h1>
       <div>
           <h2>子组件</h2>
           <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>
    </div>
</template>
<script>
    import MyButton from  '../components/MyButton.vue'
    const options = {
       components:{
           MyButton
       }
    }
    export default options;
</script>

<style scoped>
.button {
    display: inline-block;
    text-align: center;
    border-radius: 30px;
    margin: 5px;
    font: bold 12px/25px Arial, sans-serif;
    padding: 0 2px;
    text-shadow: 1px 1px 1px rgba(255, 255, 255, .22);
    box-shadow: 1px 1px 1px rgba(0, 0, 0, .29), inset 1px 1px 1px rgba(255, 255, 255, .44);
    transition: all 0.15s ease;
}

.button:hover {
    box-shadow: 1px 1px 1px rgba(0, 0, 0, .29), inset 1px 1px 2px rgba(0, 0, 0, .5);
}

.button:active {
    box-shadow: inset 1px 1px 2px rgba(0, 0, 0, .8);
}

.primary {
    background-color: #1d6ef9;
    color: #b5e3f1;
}

.danger {
    background-color: rgb(196, 50, 50);
    color: white;
}

.success {
    background-color: #a5cd4e;
    ;
    color: #3e5706;
}

.small {
    width: 40px;
    height: 20px;
    font-size: 10px;
    line-height: 20px;
}

.middle {
    width: 50px;
    height: 25px;
    font-size: 14px;
    line-height: 25px;
}

.large {
    width: 60px;
    height: 30px;
    font-size: 18px;
    line-height: 30px;
}
</style>

Guess you like

Origin blog.csdn.net/qq_59212867/article/details/128603373
Recommended