学习Vue第四章/学习第五章VueX

第四章Vue中的ajax

1.在Vue.cli上面去配置代理服务器解决同源问题(一)

同源问题:
浏览器向服务器拿取数据的话,如果不是与浏览器使用的
协议 主机名 端口 一致的话 那么数据就会被浏览器拦截不会展现到页面

配置代理服务器,与浏览器同源 ,由代理服务器去请求数据,再返回给浏览器(因为服务器与服务器之间是没有同源问题的)

使用axios发送ajax请求

需要先启动两台服务器 通过 node js文件名启动
1.安装axios
npm i axios
2.引入axios
import axios from “axios”
3.使用axios发送ajax请求

<template>
    <div>
        <button @click="send">点我发送请求获取数据</button>
    </div>

</template>
<script>
    // 引入axios来发送ajax请求
    import axios from "axios"
    export default {
        name:'app',
        methods:{
            send(){
                // 通过直接请求代理服务器的方式 去解决同源问题
                axios.get("http://localhost:8080/students").then(
                    // .get(路径).then(需要写两个回调函数,一个成功回调response  一个是error)
                    response=>{
                        console.log("我收到数据了",response.data)  // response.data拿到返回数据
                    },
                    error=>{
                        console.log("错误信息是",error)
                    }
                )
            }
        }
    }
</script>

<style>
    /* 在App写的样式全局可用  那你就不要写scoped */
</style>

4.在vue.config.js中配置代理服务器

module.exports = {
    pages: {
      index: {
        // page 的入口
        entry: 'src/main.js'

      },
// 自定义配置文件
    },
    lintOnSave:true,  // 关闭语法检查
    devServer:{
      // 配置 vue.cli的代理服务器 这样配置只可以代理到一台服务器上
      proxy: 'http://localhost:5000'   // 代理服务器的目的地
    }
  }

直接访问 http://localhost:5000会出现
报错:
已拦截跨源请求:同源策略禁止读取位于 http://localhost:5000/ 的远程资源。(原因:CORS 头缺少 ‘Access-Control-Allow-Origin’)。状态码:404

这种方式 只有代理服务器上么有的资源,才会访问到目标服务器(public中的有就直接返回了)而且只能配置一个代理

2.配置代理方式2 可以配置多个代理目的服务器,和拦截具体的请求

发请求是直接给vue.cli代理服务器发 他的端口也是8080

            send2(){
                // 通过直接请求代理服务器的方式 去解决同源问题
                axios.get("http://localhost:8080/demo/cars").then(
                    // .get(路径).then(需要写两个回调函数,一个成功回调response  一个是error)
                    response=>{
                        console.log("我收到数据了",response.data)  // response.data拿到返回数据
                    },
                    error=>{
                        console.log("错误信息是",error)
                    }
                )
            }

vue.config.js 这个配置

    devServer:{
      proxy:{
        '/api':{  //拦截请求前缀(端口号后面),走代理  真实请求他会删除/api的 
          target: 'http://localhost:5000',  // 代理的目的服务器
          ws: true,    // 用于支持 websocket 
          changeOrigin: true,  // 用于控制 请求头中的host的值  为正说谎  为假不说谎
          pathRewrite:{'^/api':''}  // 重写路径值  ^/api  代表匹配所有的 前缀为api的值 替换为空
        },
        'demo':{
          target: 'http://localhost:5001',
          ws: true, // 开启对websocket的支持
          changeOrigin: true, // 开启对 请求投中的host的值的控制
          pathRewrite:{"^/demo":''}

        }
      }
    }

3.github案例

在这里插入图片描述

1.首先是组件的抽取,静态页面的形成

1.bootstrap.css的引入 可以在App中引入 (在src下创建 assets静态文件夹)
但是这种引入的话会有严格的报错

所以把文件放在public下的css中 在index.html中引入

		<!-- 引入第三方样式  <%= BASE_URL %> 就是public-->
		<link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">

2.创建Search.vue 和 List.vue

<template>
      <div class="row">
        <div class="card">
            <a href="https://github.com/xxxxxx" target="_blank">
            <img src="https://cn.vuejs.org/images/logo.svg" style='width: 100px'/>
            </a>
            <p class="card-text">xxxxxx</p>
        </div>

        </div>
</template>

<script>
    export default{
        name: 'List',
    }
</script>
<style>
</style>
<template>
        <section class="jumbotron">
        <h3 class="jumbotron-heading">Search Github Users</h3>
        <div>
            <input type="text" placeholder="enter the name you search"/>&nbsp;<button>Search</button>
        </div>
        </section>
</template>

<script>
    export default {
        name: 'Search'
    }
</script>
<style>
</style>

App.vue

<template>
    <div id="app">
    <div class="container">
        <Search></Search>
        <List></List>
    </div>
</div>
</template>
<script>
import List from "./components/List.vue"
import Search from "./components/Search.vue"

    export default {
        name:'app',
        components:{
            List,
            Search
        }

    }
</script>
<style>
    /* 在App写的样式全局可用  那你就不要写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>

main.js

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

Vue.config.productionTip=false

// import {m} from './mixin'
// Vue.mixin(m) 
// 引入整个应用都用的混合   全局混合


new Vue({
    el:'#app',
    render: h =>h(App)
})
2.数据列表展示 ``使用飘号 加上${}来解析表达式

1.访问https://api.github.com/search/users?q=xxx github会返回用户列表的

2.给搜索框绑定上单击事件 点击搜索 收集keyword参数 发送ajax请求利用axios

3.把用户数据给到list组件展示 通过全局事件总线
list:

        <div class="card" v-for="user in users" :key="user.login">
            <a :href="user.html_url" target="_blank">
            <img :src="user.avatar_url" style='width: 100px'/>
            </a>
            <p class="card-text">{{ user.login }}</p>
        </div>

        mounted(){
            // 需要users数据就要挂载事件
            this.$bus.$on('sendUsers',(users)=>{
                console.log('收到数据了',users)
                this.users = users
            })
        },
        beforeDestroy(){
            // 在销毁之前解锁事件
            this.$bus.$off('sendUsers')
        }

search

        methods:{
            searchkeyword(){
                // ``使用飘号  加上${}来解析表达式
                axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(
                    response=>{
                        console.log('数据数',response.data.items)
                        // 把数据传递到list中显示
                        this.$bus.$emit('sendUsers',response.data.items)
                    },
                    error=>{
                        console.log('错误错误',error)
                    }
                )
            }
        }
3.完善案例 数据的完善 this.info = {…this.info,…objdata}
 // 这个是合并对象的一种写法   后面的对象去合并前面的对象
            this.info = {...this.info,...objdata}

1新增几个属性来控制页面

        <h1 v-show="ifFirse">欢迎访问</h1>
        <h1 v-show="ifLoading"> 加载中请稍后 </h1>
        <h1 v-show="errMessage">{{ errMessage }}</h1>

                ifFirse:true,  // 是不是刚开始  刚开始就要显示  欢迎来到页面
                ifLoading:false,  //是否加载中,
                errMessage:'',   // 有无错误信息

2.以对象的形式传递参数

            this.$bus.$on('changdata',(objdata)=>{
                // 这个是合并对象的一种写法
                this.info = {...this.info,...objdata}
            })

            searchkeyword(){
                // ``使用飘号  加上${}来解析表达式
                // 发送请求前是一个加载状态
                this.$bus.$emit('changdata',{ifFirse:false,ifLoading:true,errMessage:'',users:[]})
                axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(
                    response=>{
                        console.log('数据数',response.data.items)
                        // 把数据传递到list中显示
                        // this.$bus.$emit('sendUsers',response.data.items)     
                        //  请求成功加载完成
                        this.$bus.$emit('changdata',{ifLoading:false,errMessage:'',users:response.data.items})
                    },
                    error=>{
                        console.log('错误错误',error)
                        // 请求失败  给出错误信息
                        this.$bus.$emit('changdata',{ifLoading:false,errMessage:error.message,users:[]})
                    }
                )
            }

4.vue-resource发送Ajax请求

1.下载
npm i vue-resource
2.引入使用

import vueResource from 'vue-resource'

Vue.config.productionTip=false
// 使用这个插件
Vue.use(vueResource)

3.在Vue上会多出来一个$http 利用它发送请求

   this.$http.get(`https://api.github.com/search/users?q=${this.keyword}`).then(
                    response=>{
                        console.log('数据数',response.data.items)
                        // 把数据传递到list中显示
                        // this.$bus.$emit('sendUsers',response.data.items)     
                        //  请求成功加载完成
                        this.$bus.$emit('changdata',{ifLoading:false,errMessage:'',users:response.data.items})
                    },
                    error=>{
                        console.log('错误错误',error)
                        // 请求失败  给出错误信息
                        this.$bus.$emit('changdata',{ifLoading:false,errMessage:error.message,users:[]})
                    }
                )

5.默认插槽的使用

多个标签都是会往一个插槽中放的《slot》

1.在组件的template要用到查槽的地方加入
<slot组件没有插入的话那么就显示默认值</slot

    <div class="category">
        <h1>{{title}}分类</h1>
        <!-- <ul v-for="(data,index) in listData" :key="index">
            <li>{{ data }}</li>
        </ul> -->
        <!-- 默认插槽等待被人插入 -->
        <slot>组件没有插入的话那么就显示默认值</slot>
    </div>

2.在组件使用的地方的里面加位置

        <Category title="电影">
        video controls 是可以播放的
            <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
        </Category>

6.具名插槽的使用

1.在使用slot插槽站位的时候使用 name属性表示名字

        <!-- 具名插槽等待被人插入  使用name属性指定名字 -->
        <slot name="center">组件没有插入的话那么就显示默认值1</slot>
        <slot name="footer">组件没有插入的话那么就显示默认值2</slot>

2.在插入的使用使用 slot="name"的方式 指定放入哪个插槽中

        <Category title="电影">
            <video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>

            <template v-slot:footer>
                <a href="www.baidu.con">更多美食</a>
            <h1> 欢迎观影</h1>
            </template>
        </Category>

3.使用template的话可以使用新语法 template 在解析完成后可以去掉

 <template v-slot:footer>

7.作用域插槽 slot-scope 但必须用template包裹住 他也可以有name

理解:
作用域插槽,是父组件想要用到子组件的数据,数据在子组件自身,但是父组件想要子组件的数据生成不一样的结构,

子组件中:
        <!-- 作用域插槽等待被人插入  父组件想要用到我的数据,但是结构不一样  通过标签反向传递数据-->
        <slot :foods="foods">组件没有插入的话那么就显示默认值1</slot>

父组件用slot-scope="属性名" 得到一个对象 对象中包含所有参数,这样来用数据指定不同的结构
        <!-- 作用域插槽,根据数据 指定不同的结构 -->
          <template slot="xx" slot-scope="foods">
         <ul>
            <li v-for="(food,index) in foods.foods" :key="index">
                {{ food }}
            </li>
        </ul>
        </template>
        </Category>

        <Category title="美食">
            <template slot-scope="foods">
                <ol>
                    <li v-for="food in foods.foods" :key="food">
                        {{ food }}
                    </li>
                </ol>
            </template>
        </Category>

第五章VueX 共享操作数据

1.什么是VueX

Vuex它是集中式管理状态(数据)的一个Vue插件,对Vue中多个组件的共享状态进行集中式管理(读/写),也是一个通讯方式,且适合任意组件通讯

什么时候用:共享
1.多个组件依赖于同一个状态时
2.不同的组件的行为操作同一个状态时

2.纯Vue求和案例

<template>
    <div class="category">
        <h1>当前的数字是{{ sum }}</h1>
        <select v-model="n">
            <option :value="1">1</option>
            <option :value="2">2</option>
            <option :value="3">3</option>
        </select>

        <button @click="increment"> + </button>
        <button @click="decrement"> - </button>
        <button @click="incrementOdd">点我奇数加</button>
        <button @click="incrementawite">点我等等再加</button>
    </div>
</template>

<script>
    export default{
        name:'Count',
        data(){
            return{
                sum:0,  // 求和的初始值
                n:1,  // select的初始值
            }
        },
        methods:{
            increment(){
                this.sum += this.n
            },
            decrement(){
                this.sum -= this.n
            },
            incrementOdd(){
                if(this.sum % 2 !== 0){
                    this.sum += this.n
                }
            },
            incrementawite(){
                setTimeout(()=>{
                    this.sum += this.n
                },500)
            }
        }
    }
</script>

<style scoped>

button{
    margin-left: 5px;
}

</style>

3.VueX的工作原理

在这里插入图片描述

4.搭建Vuex环境 配置index.js中配置Store对象,new Vue的使用引入

注意 在创建Store对象的时候,必须要use(Vuex)

1.首先安装Vuex
npm i vuex@3
2.引入Vuex并且使用,那么在创建Vue的时候就可以有Store配置项

// 引入暴露的store
import Store from './store/index'

new Vue({
    el:'#app',
    store:Store,
    render: h =>h(App),  // 会覆盖 index上面的 <div id="app"></div>
    beforeCreate(){
        // 在原型对象上绑定 全局事件总线的傀儡
        Vue.prototype.$bus = this
    },
    mounted(){
        console.log('',this)
    }
})

3.在src下创建store文件夹 创建index.js文件,在这个里面配置Store
创建三个对象 actions mutations state
在使用Vuex提供的.Store函数去创建对象

// 在这里要创建store对象  并且暴露

// 引入Vuex这个插件  并且使用  那么在Vue上就可以配置 store这个属性
import Vue from 'vue'
import Vuex from 'vuex'
//  must call Vue.use(Vuex) before creating a store instance.
Vue.use(Vuex)
// 它是定义行为的集合
const actions = {}
// 它是操作数据
const mutations = {}
// 它是存储数据
const state = {}

// 使用Vuex来创建store
  export default  new Vuex.Store({
        actions,
        mutations,
        state
    })
使用Vuex集中管理数据插件来实现就和

1.在index.js的state中定义共享数据
2.在组件中通过$store.dispatch(“行为名”,操作数)来发起操作
3.在actions中 定义一个行为方法(context上下文,value操作数) 在里面写逻辑
写完通过context.commit(“突变名”,value操作数)提交给 mutations
如果没有逻辑可以写 那么可以直接由组件 commit到 mutations

4.在mutations中定义 突变方法(state管理数据,value) 去直接操作数据

页面通过$store.state.数据访问

index.js

// 在这里要创建store对象  并且暴露

// 引入Vuex这个插件  并且使用  那么在Vue上就可以配置 store这个属性
import Vue from 'vue'
import Vuex from 'vuex'
//  must call Vue.use(Vuex) before creating a store instance.
Vue.use(Vuex)
// 它是定义行为的集合
const actions = {
    jia:function(context,value){
// context中有 commit和dispatch  
        //console.log(context,value)
        // 在action中我们写逻辑  然后提交给 mutations操作具体数据  一般action中方法为小写  mutations中为大写
        context.commit('JIA',value);
    },
    jian(context,value){
        context.commit('JIAN',value)
    },
    jianOdd(context,value){
        // 上下文中也是有数据  的  state
        if(context.state.sum % 2 !== 0){
            context.commit("JIANODD",value)
        }
    },
    jiawait(context,value){
        setTimeout(()=>{
            context.commit("JIAWAIT",value)
        },500)
    }
}
// 它是操作数据
const mutations = {
    JIA(state,value){
        // 第一个参数就是 state 里面包含所有管理的数据  第二个参数是 操作数
        // console.log("@",a,b)
        state.sum+=value
    },
    JIAN(state,value){
        state.sum -= value
    },
    JIANODD(state,value){
        state.sum+=value
    },
    JIAWAIT(state,value){
        state.sum+=value
    }
}
// 它是存储数据
const state = {
    sum:0
}

// 使用Vuex来创建store
  export default  new Vuex.Store({
        actions,
        mutations,
        state
    })

组件中:

        methods:{
            increment(){
                // 在这里 我们需要 使用dispatch  发送一个 方法名和操作数
                // actions中方法没哟业务逻辑,直接commit到mutations
                 this.$store.commit('JIA',this.n)
            },
            decrement(){
                this.$store.dispatch('jian',this.n)
            },
            incrementOdd(){
                // 把操作数传递过去  让action完成逻辑操作
                this.$store.dispatch('jianOdd',this.n)
            },
            incrementawite(){
                this.$store.dispatch('jiawait',this.n)
            }
        }

5.Vuex的开发工具的使用

1.Vuex开发工具会监测 mutations中的方法的执行
2.actions中主要是写业务逻辑的
在context可以再次调用 dispatch去处理别的业务逻辑
在context中也可以拿到 state数据
3.组件中如果没有业务逻辑的处理的话可以直接 commit

6.Vuex的另一个属性getters

getters这个数据是 如果你要对state中的数据进行加工那么你可以用getters

配置新的getters对象

const getters = {
    // 在这里配置一个getters  在把它放入Store中  就会有了
    bigSum(state){
        // 可以从tate中拿到数据进行加工  他的返回值就是 bigSum的值
       return state.sum*10
    }
}

// 使用Vuex来创建store
  export default  new Vuex.Store({
        actions,
        mutations,
        state,
        getters
    })

使用
        <h1>他的十倍是{{ $store.getters.bigSum }}</h1>

7.VueX中帮忙映射数据为计算属性的函数mapState、mapGetters

1.    // 导入映射函数
    import { mapState,mapGetters } from 'vuex'

  2.在computed中使用       // Vue提供的函数...mapState  ...mapGetters  可以帮助我们把这些中的数据映射成为计算属性
        // sum:'sum'第一个是计算属性的名字  第二个是在state中数据的名字  两个相同的话可以写成数组的形式
            ...mapState({sum:'sum',name:'name',school:'school'}),
        ...mapGetters(['bigSum'])

8.Vuex帮忙映射数据为方法 mapMutations,mapActions

    // 导入映射函数
    import { mapState,mapGetters,mapMutations,mapActions } from 'vuex'


    <button @click="increment(n)"> + </button>

methods:{
            // increment(){
            //     // 在这里 我们需要 使用dispatch  发送一个 方法名和操作数
            //     this.$store.commit('JIA',this.n)
            // },
                // 可以通过 mapMutations来生成方法 他会在方法中commit  传递参数需要在模板中写方法的时候写
                //  对象的key是 方法名  Value 是 mutations的名字  对象和数组的写法
                ...mapMutations({increment:'JIA'}),


                // mapActions可以帮我们生成方法 ,他会在方法中电泳dispatch

            // decrement(){
            //     this.$store.dispatch('jian',this.n)
            // },
                ...mapActions({decrement:'jian'}),
                }

9.组件之间的共享数据利用Vuex

读取的话可以直接用计算属性读取 可以利用mapstate生成

    computed:{
        persons(){
            return this.$store.state.persons
        },
        sum(){
            return this.$store.state.sum
        }
    },

要是想写的话就要通过访问 actions 或者 mutations

    methods:{
         add(){
            // 在这个方法中,要联系共享数据管理  因为没有逻辑  直接操作 mutations
            const person = {id:nanoid(),name:this.keyname}
            this.$store.commit("ADD_PERSON",person)
            this.keyname = ''
        }
    }

10.VueX组件的模块化

1.在index.js中对不同组件的 Vuex分模块

// 模块化module 管理 每一个组件的共享数据
const countAbout = {
    // 模块化管理要开启命名空间
    namespaced:true,
    actions{},
    mutations{},
    state{},
    getters{}
}

2.在创建Store的时候要使用modules来告诉 这个是一个模块

// 使用Vuex来创建store
  export default  new Vuex.Store({
    // 模块化注册管理
    modules:{
    模块名
        countAbout:countAbout,
        listPerson:listPerson
    }
    })

3.如果是使用…mapxxx映射函数来写的,那么都只要在第一个参数上写上模块名就好了

方法
...mapMutations('countAbout',{increment:'JIA'}),
计算属性
...mapState('countAbout',{sum:'sum',name:'name',school:'school'}),

4.如果是自己手动写,那么只有state中的数据是对象存储,其他都是通过
“模块名/方法”来存储

    computed:{
        persons(){
            return this.$store.state.listPerson.persons
        },
        sum(){
            return this.$store.state.countAbout.sum
        }
    },

    methods:{
         add(){
            // 在这个方法中,要联系共享数据管理  因为没有逻辑  直接操作 mutations
            const person = {id:nanoid(),name:this.keyname}
            this.$store.commit("listPerson/ADD_PERSON",person)
            this.keyname = ''
        }
    }

5.getters这个类似于计算属性的也是通过 [ ]的形式拿到对象的属性值

        FristName(){
            return this.$store.getters['listPerson/FristName']
        }

6.还可以把对各个组件的配置给分开到store文件夹中写js文件 只要默认暴露对象就好了 在index.js中引入

// 引入共享资源文件
import countAbout from './count'
import listPerson from './listPerson'
注意 state的数据存在store的原型上以对象的方式存储

actions中处理逻辑

actions
       aroundName(context){
        // 在actions中处理业务逻辑  发送请求
        axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(
            response => {
                context.commit('ADD_PERSON',{id:2,name:response.data})
            },
            error => {
                alert(error.message)
            }
        )
       }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值