vue3
创建
使用Vue CLI创建
// 安装
$ npm install -g @vue/gli
$ vue --version
// 创建
$ vue create [名字]
Vue Router
使用fetch获取数据
在单独组件的vue中使用
// fetch返回Promise对象
// 默认执行get请求
fetch('http://localhost:3000/banner').then((res)=>{
// json()将响应的body,解析json的promise
// console.log(ews.json());
return res.json()
}).then((res)=>{
console.log(res);
// 这里通过变量可以获取res的值,从而之后渲染到界面上
this.bannersList=res.banners
})
在状态集中管理中使用
store/index.js
import {reactive} from 'vue'
const store={
store: reactive({// 定义状态
msg: "hello world",
bannersList: []
}),
updateMsg: function() {
this.state.msg='你好'
},
updateBannersList(value) {
this.state.bannersList=value
},
}
export default store
Home.vue中
// fetch返回Promise对象
fetch('http://localhost:3000/banner').then((res)=>{
// json()将响应的body,解析json的promise
// console.log(ews.json());
return res.json()
}).then((res)=>{
console.log(res);
// 这里改变了
this.store.updateBannersList(res.bannersList)
})
使用axios获取数据
文档地址1:http://www.axios-js.com/zh-cn/docs/
文档地址2(官方):https://www.axios-http.cn/docs/intro
概念
axios是基于Promise的http库
axios与ajax关系:暂时理解为axios是ajax的子集
安装
$ npm install axios
使用
引入axios
// 引入
import axios from 'axios'
axios.get('http://localhost:3000/banner').then((res)=>{
console.log(res);
})
支持并发请求及携带参数,具体见文档
vite通过proxy解决跨域问题
【引例】使用axios获取“猫眼电影”的数据
打开“猫眼电影”,右键检查,找到Network中对应请求,找到Headers中General的Request URL,用于axios中。
以下情况因为浏览器同源策略的保护机制,出现跨域请求问题。
Home.vue
import axios from 'axios'
axios.get('https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E4%B8%8A%E6%B5%B7&ci=10&channelId=4').then((res)=>{
console.log(res);
})
【解决方案】使用proxy
创建中转服务器(proxy),代理请求发送给服务端(返回数据的那个,如“猫眼电影”)
Home.vue
import axios from 'axios'
axios.get('/path/api/mmdb/movie/v3/list/hot.json?ct=%E4%B8%8A%E6%B5%B7&ci=10&channelId=4').then((res)=>{
console.log(res);
})
vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {// 中转服务器
proxy: {// 通过代理实现跨域
'/path': { // 简单来说,这个的目的在于【提醒】看到/path就要去代理,对应上方Home.vue中的/path,代理的是下方target的内容
target: 'https://i.maoyan.com', // 需要替换的服务端地址
changeOrigin: true, // 开启代理
rewrite: path=>path.replace(/^\/path, '')// 因为/path只为题型作用,/path为多余的,所以需要重写路径
}
}
}
})
Vuex
文档地址(官方):https://vuex.vuejs.org/zh/
概念
可以理解为一个状态(其实就是数据)管理模式,简单来说就是作为一个仓库集中管理使得各个视图可以使用状态。
一般在大型项目中使用。
安装
- 一开始Vue CLI创建时选择;
$ npm install vuex@next --save
基本使用——Store
(以Vue CLI创建后的文件为基础)
新建src/store/index.js
import { createApp } from 'vue'
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
state () {// 存放单一状态(基本数据)
return {
count: 0
}
}
})
export default store
main.js
// 将 store 实例作为插件安装
import store from './store'
app.use(store)
HomeView.vue
<h2>{{$store.state.count}}</h2>
选项式情况下,JavaScript中要加this
改变store中的状态——Mutation
不建议直接更改store中的数据。
建议利用mutation改变,大概意思是可以跟踪到什么操作改变了什么数据。
index.js
import { createApp } from 'vue'
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
state () {// 存放单一状态(基本数据)
return {
count: 0
}
},
// 新增内容
mutations: {// 通过store.commit方法对应函数触发状态变更
increment (state,value) {// state表示上面state返回的对象,value表示传过来的参数
state.count+=value
}
}
})
export default store
main.js
// 将 store 实例作为插件安装
import store from './store'
app.use(store)
HomeView.vue
<button @click="addCount(5)">count++</button>
methods: {
addCount(num){
this.$store.commit('increment',num)// 使用store.commit方法改变state状态
}
}
也可以提交payload。
可以以对象的形式进行提交。
Mutation必须是同步函数,异步函数放在Action处理。
从State中派生状态——Getter
getter可以理解为store的计算属性。
index.js
import { createApp } from 'vue'
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
state () {// 存放单一状态(基本数据)
return {
count: 0,
msg: 'helloworld'
}
},
getters () {
reverMsg: function(state) {
return state.msg.split('').reverse.join('')
},
reverMsgLength: function(state, getters) {// getters表示当前store中的getters对象
return getters.reverMsg.length
}
}
})
export default store
HomeView.vue
<h2>{{$store.getters.reversMsg}}</h2>
<h2>{{$store.getters.reversMsgLength}}</h2>
异步操作——Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态;
- Action 可以包含任意异步操作,mutation必须是同步操作。
解决跨域问题方法
以”猫眼电影“为例。
Warning:以下有跨域问题。
store/index.js
const store = createStore({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
getHot: function() {// 需要通过dispatch触发
fetch('https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E4%B8%8A%E6%B5%B7&ci=10&channelId=4').then((res)=>{
console.log(res)
})
}
}
})
HomeView.vue
mounted() {
this.$sttore.dispatch('getHot')
}
【解决方案】
vue.config.js
注意:rewrite写法有所不同!
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
proxy: {
'/path': {
target: 'https://i.maoyan.com',
changeOrigin: true,
//注意!有所不同!
pathRewrite: {
'^/path': ''
}
}
}
})
store/index.js
getHot: function() {// 需要通过dispatch触发
fetch('/path/api/mmdb/movie/v3/list/hot.json?ct=%E4%B8%8A%E6%B5%B7&ci=10&channelId=4').then((res)=>{
console.log(res.json())
})
}
要接收请求数据
store/index.js
mutations: {
updateHotList: function(state, value) {
state.hotList=value
}
},
actions: {
getHot: function(context) { // context与store实例具有相同的属性和方法的对象
axios.get('/path/api/mmdb/movie/v3/list/hot.json?ct=%E4%B8%8A%E6%B5%B7&ci=10&channelId=4').then(res=>{
context.commit('updateHotList', res.data.data.hot)
console.log(context.store.hotList)
})
}
实现传参
HomeView.vue
mounted() {
this.$store.dispatch('getHot', 'hhh')
}
store/index.js
actions: {
getHot: function(context, payload) { // context与store实例具有相同的属性和方法的对象
axios.get('/path/api/mmdb/movie/v3/list/hot.json?ct=%E4%B8%8A%E6%B5%B7&ci=10&channelId=4').then(res=>{
context.commit('updateHotList', res.data.data.hot)
console.log(context.store.hotList)
console.log(payload)// 打印出hhh
})
}
模块化——Module
模块化处理
store/index.js
const moduleA = {
state: () => ({
userName: "用户张三"
}),
mutations: { ... },
actions: { ... },
getters: {
userNameAge: function(state) {// state是局部状态
return state.userName+',今年18岁'
}
}
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,// 也可以直接写moduleA(moduleA: moduleA)
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
获取数据方式
注意:state比较特殊!
getters、mutations、actions通过
s
t
o
r
e
直接获取,
s
t
a
t
e
通过
store直接获取,state通过
store直接获取,state通过store.state.模块名.状态名获取。
HomeView.vue
<h2>{{$store.getters.userName}}</h2>
<h2>{{$store.state.a.userName}}</h2>
获取根节点实例state的状态
store/index.js
const moduleA = {
state: () => ({
userName: "用户张三"
}),
mutations: { ... },
actions: { ... },
getters: {
userNameAge: function(state, getters, rootState) {// state是局部状态
console.log(getters)// 获取store实例中的getters对象
console.log(rootState)// 获取根节点实例state的状态
return state.userName+',今年18岁'
}
}
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,// 也可以直接写moduleA(moduleA: moduleA)
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
store结构优化
新建store/userua
新建store/user/index.js
store/user/index.js
const user = {
state: () => ({
userName: "用户张三"
}),
mutations: { ... },
actions: { ... },
getters: {
userNameAge: function(state, getters, rootState) {// state是局部状态
console.log(getters)// 获取store实例中的getters对象
console.log(rootState)// 获取根节点实例state的状态
return state.userName+',今年18岁'
}
}
}
export default user// 在别的地方引入
命名空间
store/user/index.js
const user = {
namespaced: true,
state: () => ({
userName: "用户张三"
}),
mutations: { ... },
actions: { ... },
getters: {
userNameAge: function(state, getters, rootState) {
console.log(getters)
console.log(rootState)
return state.userName+',今年18岁'
}
}
}
export default user
HomeView.vue
<h2>{{$store.getters[]'a/userNameAge'}}</h2>
methods中也要对应改变(actions、mutations……)。
this.$store.commit('a/updateUserName')
如果要用辅助函数
...mapMutations('a', ['updataUserName'])
辅助函数
文档跳转
HomeView.vue
import {MapState} from 'vuex'
export default {
// 省略
computed: mapState({
// 方式一
count: state => state.count
// 方式二
count: "count"
})
}
// 方式三
computed: mapState(['count','msg'])
<h2>{{ count }}</h2>
缺点在于如果原本需要有computed,就出现不能同时有两个computed的情况。此时采用对象展开运算符的方法。
computed:
addNum: function() {
return this.num*10
},
...mapState(['count','msg'])
getters、actions、mutations用法均一致,只需最开始引入。