Ajax in Vue (26th)

1 Vue scaffolding configuration proxy

To organize the way to send the request:
1.xhr
2.jQuery encapsulates xhr (professional encapsulation of DOM operations is not suitable in Vue)
3.axios encapsulates xhr (recommended)
4.fetch (window built-in method)

In this case, the axios library needs to be downloaded: npm install axios

But sometimes cross-domain occurs (the protocol host name and port number are the same so that it will not cross-domain)

How to solve cross-domain problems:
1.cors (the server will give you a special response header after receiving it (back-end processing))
2.jsonp (with the help of script tag request, only get request can be solved)
3. Proxy server
In the development process, we cleverly use the vue scaffolding to open the proxy server to solve the cross-domain problem

Target server http://localhost:5000/students
vue.config.js:

module.exports = {
    pages: {
        index: {
            entry: 'src/main.js',
        },
    },
    lintOnSave:false,
    // Enable proxy server (method 1)
    // devServer: {
    //     proxy:'http://localhost:5000'
    // }

    //Enable proxy server (method 2)
	devServer: {
        proxy: {
            '/atguigu': {
                target: 'http://localhost:5000',
                pathRewrite:{'^/atguigu':''},  //Match all paths starting with atguigu and turn it into an empty string for the server to find
                // ws: true, // used to support websocket, the default value is true
                // changeOrigin: true //Used to control the host value in the request header, the default value is true
            },
            '/demo': {
                target: 'http://localhost:5001',
                pathRewrite:{'^/demo':''},
                // ws: true, // used to support websocket, the default value is true
                // changeOrigin: true //Used to control the host value in the request header, the default value is true
            }
        }
    }
}

Then configure your code
src/App.vue

<template>
    <div id="root">
        <button @click="getStudents">Get student information</button><br/>
        <button @click="getCars">Get car info</button>
    </div>
</template>

<script>
    import axios from 'axios'
    
    export default {
        name:'App',
        methods: {
			getStudents(){
				axios.get('http://localhost:8080/atguigu/students').then(
					response => {
						console.log('request succeeded',response.data)
					},
					error => {
						console.log('request failed',error.message)
					}
				)
			},
            getCars(){
				axios.get('http://localhost:8080/demo/cars').then(
					response => {
						console.log('request succeeded',response.data)
					},
					error => {
						console.log('request failed',error.message)
					}
				)
			}
        }
    }
</script>

Summarize:

vue scaffolding configuration proxy server:

Method 1: Add the following configuration to vue.config.js

devServer:{
    proxy:"http://localhost:5000"
}

illustrate:

1. Advantages: Simple configuration, just send it directly to the front end when requesting resources
2. Disadvantages: You cannot configure multiple proxies, and you cannot flexibly control whether requests go through proxies
3. Working method: If the proxy is configured according to the above, when a resource that does not exist in the front end is requested, the request will be forwarded to the server (preferably matching front-end resources)

Method 2: Add the following configuration to vue.config.js

devServer: {
    proxy: {
      	'/api1': { // matches all request paths starting with '/api1'
        	target: 'http://localhost:5000', // base path of proxy target
        	changeOrigin: true,
        	pathRewrite: {'^/api1': ''}
      	},
      	'/api2': { // matches all request paths starting with '/api2'
        	target: 'http://localhost:5001', // base path of proxy target
        	changeOrigin: true,
        	pathRewrite: {'^/api2': ''}
      	}
    }
}

// When changeOrigin is set to true, the host in the request header received by the server is: localhost:5000
// When changeOrigin is set to false, the host in the request header received by the server is: localhost:8080

illustrate:

1. Advantages: You can configure multiple proxies, and you can flexibly control whether the request goes through the proxy
2. Disadvantages: The configuration is slightly cumbersome, and a prefix must be added when requesting resources

2 GitHub user search case

public/index.html

<!DOCTYPE html>
<html lang="">
    <head>
        <meta charset="UTF-8">
        <!-- against IE The special configuration of the browser, the meaning is to let IE The browser renders the page at the highest rendering level -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <!-- The ideal port to open the mobile terminal -->
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <!-- Configure Tab Icons -->
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        <!-- introduce bootstrap style -->
        <link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">   //Introduce bootstarp here
        <!-- Configure page title -->
        <title><%= htmlWebpackPlugin.options.title %></title>
    </head>
    <body>
        <!-- container -->
        <div id="app"></div>
    </body>
</html>

src/main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
    el:"#app",
    render: h => h(App),
    beforeCreate(){
        Vue.prototype.$bus = this
    }
})

src/App.vue

<template>
	<div class="container">
		<Search/>
		<List/>
	</div>
</template>

<script>
	import Search from './components/Search.vue'
	import List from './components/List.vue'

    export default {
        name:'App',
		components:{Search,List},
	}
</script>

src/components/Search.vue

<template>
    <section class="jumbotron">
		<h3 class="jumbotron-heading">Search Github Users</h3>
		<div>
            <input type="text" placeholder="enter the name you search" v-model="keyWord"/>&nbsp;
            <button @click="getUsers">Search</button>
		</div>
    </section>
</template>

<script>
    import axios from 'axios'
    export default {
        name:'Search',
        data() {
            return {
                keyWord:''
            }
        },
        methods: {
            getUsers(){
                //Update List data before request
				this.$bus.$emit('updateListData',{isLoading:true,errMsg:'',users:[],isFirst:false})
				axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
					response => {
						console.log('request succeeded')
						//Update the data of the List after the request is successful
						this.$bus.$emit('updateListData',{isLoading:false,errMsg:'',users:response.data.items})
					},
					error => {
						//Update List's data after request
						this.$bus.$emit('updateListData',{isLoading:false,errMsg:error.message,users:[]})
					}
				)
            }
        }
    }
</script>

src/components/List.vue

<template>
    <div class="row">
        <!-- Show user list -->
        <div class="card" v-show="info.users.length" v-for="user in info.users" :key="user.id">
            <a :href="user.html_url" target="_blank">
                <img :src="user.avatar_url" style='width: 100px'/>
            </a>
            <h4 class="card-title">{{user.login}}</h4>
        </div>
        <!-- show welcome -->
        <h1 v-show="info.isFirst">welcome!</h1>
        <!-- show loading -->
        <h1 v-show="info.isLoading">Loading...</h1>
        <!-- Show error messages -->
        <h1 v-show="info.errMsg">{{errMsg}}</h1>
    </div>
</template>

<script>
    export default {
        name:'List',
        data() {
            return {
                info:{
                    isFirst:true,
                    isLoading:false,
                    errMsg:'',
                    users:[]
                }
            }
        },
        mounted(){
            this.$bus.$on('updateListData',(dataObj)=>{
                //Dynamically merge properties of two objects
                this.info = {...this.info,...dataObj}
            })
        },
        beforeDestroy(){
            this.$bus.$off('updateListData')
        }
    }
</script>

<style scoped>
    .album {
		min-height: 50rem; /* Can be removed; just added for demo purposes */
		padding-top: 3rem;
		padding-bottom: 3rem;
		background-color: #f7f7f7;
	}

	.card {
		float: left;
		width: 33.333%;
		padding: .75rem;
		margin-bottom: 2rem;
		border: 1px solid #efefef;
		text-align: center;
	}

	.card > img {
		margin-bottom: .75rem;
		border-radius: 100px;
	}

	.card-text {
		font-size: 85%;
	}
</style>

3 vue-resource

Download vue-resource library: npm i vue-resource

src/main.js

import Vue from 'vue'
import App from './App.vue'
import vueResource from 'vue-resource'

Vue.config.productionTip = false
Vue.use(vueResource)

new Vue({
    el:"#app",
    render: h => h(App),
    beforeCreate(){
        Vue.prototype.$bus = this
    }
})

src/components/Search.vue

<template>
    <section class="jumbotron">
		<h3 class="jumbotron-heading">Search Github Users</h3>
		<div>
            <input type="text" placeholder="enter the name you search" v-model="keyWord"/>&nbsp;
            <button @click="getUsers">Search</button>
		</div>
    </section>
</template>

<script>
    export default {
        name:'Search',
        data() {
            return {
                keyWord:''
            }
        },
        methods: {
            getUsers(){
                //Update List data before request
				this.$bus.$emit('updateListData',{isLoading:true,errMsg:'',users:[],isFirst:false})
				this.$http.get(`https://api.github.com/search/users?q=${this.keyWord}`).then( //replace axios with $http on this line
					response => {
						console.log('request succeeded')
						//Update the data of the List after the request is successful
						this.$bus.$emit('updateListData',{isLoading:false,errMsg:'',users:response.data.items})
					},
					error => {
						//Update List's data after request
						this.$bus.$emit('updateListData',{isLoading:false,errMsg:error.message,users:[]})
					}
				)
            }
        }
    }
</script>

Summarize:

Two Ajax libraries commonly used in vue projects:

1.axios: A general-purpose Ajax request library, officially recommended, with high efficiency
2.vue-resource: vue plug-in library, vue 1.x is widely used, and the official is no longer maintained

4 slot slot

4.1 Default slot

src/App.vue

<template>
	<div class="container">
		<Category title="Food" >
			<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
		</Category>

		<Category title="game" >
			<ul>
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
		</Category>

		<Category title="Movie">
			<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
		</Category>
	</div>
</template>

<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category},
		data() {
			return {
				games:['Plants vs. Zombies','red alert','Hollow Knight','kingdom']
			}
		},
	}
</script>

<style scoped>
	.container{
		display: flex;   //Flexbox model to achieve uniform distribution of a row
		justify-content: space-around;
	}
</style>

src/components/Category.vue

<template>
	<div class="category">
		<h3>{{title}}Classification</h3>
		<!-- Define a slot (dig a hole and wait for the user of the component to fill it) -->
		<slot>i'm some default value, when the user doesn't pass a concrete struct, i get</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title']
	}
</script>

<style scoped>
	.category{
		background-color: skyblue;
		width: 200px;
		height: 300px;
	}
	h3{
		text-align: center;
		background-color: orange;
	}
	video{
		width: 100%;
	}
	img{
		width: 100%;
	}
</style>

Effect:

4.2 Named Slots

src/App.vue

<template>
	<div class="container">
		<Category title="Food" >
			<img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
			<a slot="footer" href="http://www.atguigu.com">More Food</a>
		</Category>

		<Category title="game" >
			<ul slot="center">
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
			<div class="foot" slot="footer">
				<a href="http://www.atguigu.com">Single player game</a>
				<a href="http://www.atguigu.com">Online Games</a>
			</div>
		</Category>

		<Category title="Movie">
			<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
			<template v-slot:footer>
				<div class="foot">
					<a href="http://www.atguigu.com">Classic</a>
					<a href="http://www.atguigu.com">Popular</a>
					<a href="http://www.atguigu.com">Recommended</a>
				</div>
				<h4>Welcome to watch the movie</h4>
			</template>
		</Category>
	</div>
</template>

<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category},
		data() {
			return {
				games:['Plants vs. Zombies','red alert','Hollow Knight','kingdom']
			}
		},
	}
</script>

<style>
	.container,.foot{
		display: flex;
		justify-content: space-around;
	}
	h4{
		text-align: center;
	}
</style>

src/components/Category.vue

<template>
	<div class="category">
		<h3>{{title}}Classification</h3>
		<!-- Define a slot (dig a hole and wait for the user of the component to fill it) -->
		<slot name="center">i'm some default value, when the consumer doesn't pass a concrete struct, i get 1</slot>
        <slot name="footer">i'm some default value, when the consumer doesn't pass a concrete struct, i get 2</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title']
	}
</script>

<style scoped>
	.category{
		background-color: skyblue;
		width: 200px;
		height: 300px;
	}
	h3{
		text-align: center;
		background-color: orange;
	}
	video{
		width: 100%;
	}
	img{
		width: 100%;
	}
</style>

4.3 Scoped slots

src/App.vue

<template>
	<div class="container">

		<Category title="game">
			<template scope="atguigu">
				<ul>
					<li v-for="(g,index) in atguigu.games" :key="index">{{g}}</li>
				</ul>
			</template>
		</Category>

		<Category title="game">
			<template scope="{games}">
				<ol>
					<li style="color:red" v-for="(g,index) in games" :key="index">{{g}}</li>
				</ol>
			</template>
		</Category>

		<Category title="game">
			<template slot-scope="{games}">
				<h4 v-for="(g,index) in games" :key="index">{{g}}</h4>
			</template>
		</Category>

	</div>
</template>

<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category},
	}
</script>

<style scoped>
	.container,.foot{
		display: flex;
		justify-content: space-around;
	}
	h4{
		text-align: center;
	}
</style>

src/components/Category.vue

<template>
	<div class="category">
		<h3>{{title}}Classification</h3>
		<slot :games="games" msg="hello">I am default some content</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title'],
		data() {
			return {
				games:['red alert','cross fire','Audition','Super Mary'],
			}
		},
	}
</script>

<style scoped>
	.category{
		background-color: skyblue;
		width: 200px;
		height: 300px;
	}
	h3{
		text-align: center;
		background-color: orange;
	}
	video{
		width: 100%;
	}
	img{
		width: 100%;
	}
</style>

Effect:

Summarize:

Slot:

1. Function: Allow the parent component to insert the html structure into the specified position of the child component, which is also a way of communication between components, suitable for parent components to pass child components

2. Classification: default slot, named slot, scoped slot

3. How to use:
1. Default slot

In the parent component:
        <Category>
           	<div>html Structure 1</div>
        </Category>
In child component:
        <template>
            <div>
               	<slot>Slot default content...</slot>
            </div>
        </template>

2. Named Slots

In the parent component:
        <Category>
            <template slot="center">
             	 <div>html Structure 1</div>
            </template>

            <template v-slot:footer>
               	<div>html Structure 2</div>
            </template>
        </Category>
In child component:
        <template>
            <div>
               	<slot name="center">Slot default content...</slot>
                <slot name="footer">Slot default content...</slot>
            </div>
        </template>

3. Scope slots:

1. Understanding: The data is in the component itself, but the user of the component needs to decide according to the structure of data generation. (The games data is in the Category component, but the structure traversed by the data is determined by the App component)
2. Specific code:

In the parent component:
		<Category>
			<template scope="scopeData">    //Receive must be written in the template tag, the name can be arbitrarily
				<!-- generated is ul list -->
				<ul>
					<li v-for="g in scopeData.games" :key="g">{{g}}</li>
				</ul>
			</template>
		</Category>

		<Category>
			<template slot-scope="scopeData">
				<!-- generated is h4 title -->
				<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
			</template>
		</Category>
In child component:
        <template>
            <div>
                <slot :games="games"></slot>
            </div>
        </template>
		
        <script>
            export default {
                name:'Category',
                props:['title'],
                //The data is in the child component itself
                data() {
                    return {
                        games:['red alert','cross fire','Audition','Super Mary']
                    }
                },
            }
        </script>

Tags: Javascript Vue.js Ajax

Posted by linus on Wed, 19 Oct 2022 10:51:42 +1030