11、12周所学

ref属性

1. 被用来给元素或子组件注册引用信息(id的替代者)

2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)

3. 使用方式:

    1. 打标识:<h1 ref="xxx">.....</h1> 或 <School ref="xxx"></School>

    2. 获取:this.$refs.xxx

<template>  
  <div>
    <h1 v-text="msg" ref="title"></h1>
    <button @click="showDOM" ref="btn">点我输出上方的DOM元素</button>
    <School ref="sch"></School>
  </div>
</template>

<script>
//引入school组件
  import School from './components/School.vue'

  export default {
    name:'ApP',
    components:{School},
    data() {
      return {
        msg:'欢迎学习vue!!'
      }
    },
    methods:{
      showDOM(){
        console.log(this.$refs.title)//真实DOM元素
        console.log(this.$refs.btn)//真实DOM元素
        console.log(this.$refs.sch)//School组件的实例对象(vc)
      }
    }
  }
</script>

<style>

 组件化开发

1.主要作用:提高开发效率;便于代码的管理和维护;提高代码复用率,减少代码冗余

组件化开发案例:todoList案例

props配置项

1. 功能:让组件接收外部传过来的数据 
2. 传递数据:<Demo name="xxx"/>

可在name前面加上v-bind指令,简写为<Demo :name="xxx"/>,这样xxx就成了JS表达式,而不只是字符串,可传各种数据类型和变量,如函数、对象、数字型等。

3. 接收数据:

  1. 第一种方式(只接收):props:['name']
  2. 第二种方式(限制类型):props:{name:String}
  3. 第三种方式(限制类型、限制必要性、指定默认值):

props:{
            name:{
            type:String, //类型
            required:true, //必要性
            default:'老王' //默认值
            }
        }


    > 备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

style的scoped属性

1.作用:让样式只在本组件生效,防止冲突。一般不推荐App组件使用
2.写法:<style scoped>

配置代理服务器

1.原因:vue里面几行代码就能写好一个代理服务器,便于处理服务器跨域问题

跨域:违背了同源策略,即协议名、主机名、端口号一致

如,由于前端所处位置为http://localhost:8080,而服务器位置为http://localhost:5000,不能向服务器发起请求,最好的解决方案是配置一个代理服务器。

2.开始配置:在脚手架的vue.config.js文件里面编写如下代码(方式1)

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

​

再用ajax向后端请求即可,如以下案例:

<template>
	<div>
		<button @click="getStudents">获取学生信息</button>
		<button @click="getCars">获取汽车信息</button>
	</div>
</template>

<script>
	import axios from 'axios'
	export default {
		name:'App',
		methods: {
			getStudents(){
				axios.get('http://localhost:8080').then(
					response => {
						console.log('请求成功了',response.data)
					},
					error => {
						console.log('请求失败了',error.message)
					}
				)
			},
			getCars(){
				axios.get('http://localhost:8080/demo/cars').then(
					response => {
						console.log('请求成功了',response.data)
					},
					error => {
						console.log('请求失败了',error.message)
					}
				)
			}
		},
	}
</script>

 优点:配置简单,请求资源时直接发给前端(端口号为8080)即可。

 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。

工作方式:若按照上述配置代理,当请求了前端存在的资源时,如axios.get('http://localhost:8080/favicon.ico'),那么会获取到脚手架里public文件相应的资源,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

在脚手架的vue.config.js文件里面编写如下代码(方式2)

​
module.exports = {
	devServer: {
      proxy: {
      '/api1': {// 匹配所有以 '/api1'开头的请求路径
        target: 'http://localhost:5000',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}
      },
      '/api2': {// 匹配所有以 '/api2'开头的请求路径
        target: 'http://localhost:5001',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
   changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
   changeOrigin默认值为true
*/

​

1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。

2. 缺点:配置略微繁琐,请求资源时必须加前缀。

组件自定义事件

1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

3. 绑定自定义事件:

    1. 第一种方式,在父组件中:<Demo @atguigu="test"/>  或<Demo v-on:atguigu="test"/>

    2. 第二种方式,在父组件中:

<Demo ref="demo"/>
        ......
        mounted(){
           this.$refs.xxx.$on('atguigu',this.test)
        }

    3. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

4. 触发自定义事件:this.$emit('atguigu',数据)

5. 解绑自定义事件:this.$off('atguigu')

6. 组件上也可以绑定原生DOM事件,需要使用native修饰符。

7. 注意:通过this.$refs.xxx.$on('atguigu',回调) 绑定自定义事件时,回调要么配置在methods中要么用箭头函数,否则this指向会出问题!

全局事件总线

1. 一种组件间通信的方式,适用于任意组件间通信

2. 安装全局事件总线:

 new Vue({
    ......
    beforeCreate() {
      Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
    },
       ......
   })

3. 使用事件总线:

   1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身

 methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }

   2. 提供数据:this.$bus.$emit('xxxx',数据)

4. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

$nextTick

1. 语法:this.$nextTick(回调函数)

2. 作用:在下一次 DOM 更新结束后执行其指定的回调。

3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。如todoList案例中,每个item在点击“编辑”按钮时候出现输入框,并让它立即获取焦点,若直接写回调,则不行,原因是vue在走完每一句代码后再解析模板,将虚拟dom转为真实dom,所以执行这一句回调的时候输入框并没有出现,所以没有作用。推荐的写法是

handleEdit(todo){
				if(todo.hasOwnProperty('isEdit')){
					todo.isEdit = true
				}else{
					// console.log('@')
					this.$set(todo,'isEdit',true)
				}
				this.$nextTick(function(){
					this.$refs.inputTitle.focus()
				})
			},

这意味着在点击编辑按钮后,先不走含有$nextTick里的回调,等真实dom出现在页面后再执行里面的回调

插槽

1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件。

2. 分类:默认插槽、具名插槽、作用域插槽

3. 使用方式:

   1. 默认插槽:


<!--父组件中:-->
              <Category>
                 <div>html结构1</div>
              </Category>
      <!--子组件中:-->
              <template>
                  <div>
                     <!-- 定义插槽 -->
                     <slot>插槽默认内容...</slot>
                  </div>
              </template>

   2. 具名插槽:


<!--父组件中:-->
              <Category>
                  <template slot="center">
                    <div>html结构1</div>
                  </template>
                  <template v-slot:footer>
                     <div>html结构2</div>
                  </template>
              </Category>
      <!--子组件中:-->
              <template>
                  <div>
                     <!-- 定义插槽 -->
                     <slot name="center">插槽默认内容...</slot>
                     <slot name="footer">插槽默认内容...</slot>
                  </div>
              </template>

   3. 作用域插槽:

      1. 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)

      2. 具体编码:


<!--父组件中:-->
            <Category>
              <template scope="scopeData">
                <!-- 生成的是ul列表 -->
                <ul>
                  <li v-for="g in scopeData.games" :key="g">{{g}}</li>
                </ul>
              </template>
            </Category>
            <Category>
              <template slot-scope="scopeData">
                <!-- 生成的是h4标题 -->
                <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
              </template>
            </Category>
         <!--子组件中:-->
                 <template>
                     <div>
                         <slot :games="games"></slot>
                     </div>
                 </template>
                 <script>
                     export default {
                         name:'Category',
                         props:['title'],
                         //数据在子组件自身
                         data() {
                             return {
                                 games:['红色警戒','穿越火线','劲舞团','超级玛丽']
                             }
                         },
                     }
                 </script>

Vuex

1.概念

​   在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

 2.何时使用?

​   多个组件需要共享数据时

 3.搭建vuex环境

1. 创建文件:src/store/index.js


 //引入Vue核心库
   import Vue from 'vue'
   //引入Vuex
   import Vuex from 'vuex'
   //应用Vuex插件
   Vue.use(Vuex)
   //准备actions对象——响应组件中用户的动作
   const actions = {}
   //准备mutations对象——修改state中的数据
   const mutations = {}
   //准备state对象——保存具体的数据
   const state = {}
   //创建并暴露store
   export default new Vuex.Store({
    actions,
    mutations,
    state
   })

2. 在main.js中创建vm时传入store配置项


//引入store
   import store from './store'
   //创建vm
   new Vue({
    el:'#app',
    render: h => h(App),
    store
   })

  4.基本使用

1. 初始化数据、配置actions、配置mutations,操作文件store.js


//引入Vue核心库
   import Vue from 'vue'
   //引入Vuex
   import Vuex from 'vuex'
   //引用Vuex
   Vue.use(Vuex)
   const actions = {
       //响应组件中加的动作
    jia(context,value){
      // console.log('actions中的jia被调用了',miniStore,value)
      context.commit('JIA',value)
    },
   }
   const mutations = {
       //执行加
    JIA(state,value){
      // console.log('mutations中的JIA被调用了',state,value)
      state.sum += value
    }
   }
   //初始化数据
   const state = {
      sum:0
   }
   //创建并暴露store
   export default new Vuex.Store({
    actions,
    mutations,
    state,
   })

​

2. 组件中读取vuex中的数据:$store.state.sum

3. 组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据) 或 $store.commit('mutations中的方法名',数据)

   >  备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

 5.getters的使用

1. 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。

2. 在store.js追加getters配置


const getters = {
    bigSum(state){
      return state.sum * 10
    }
   }
   //创建并暴露store
   export default new Vuex.Store({
    ......
    getters
   })

3. 组件中读取数据:$store.getters.bigSum

 6.四个map方法的使用

1.mapState方法:用于帮助我们映射state中的数据为计算属性


computed: {
       //借助mapState生成计算属性:sum、school、subject(对象写法)
        ...mapState({sum:'sum',school:'school',subject:'subject'}),
       //借助mapState生成计算属性:sum、school、subject(数组写法)
       ...mapState(['sum','school','subject']),
   },

2. mapGetters方法:用于帮助我们映射```getters```中的数据为计算属性


 computed: {
       //借助mapGetters生成计算属性:bigSum(对象写法)
       ...mapGetters({bigSum:'bigSum'}),
       //借助mapGetters生成计算属性:bigSum(数组写法)
       ...mapGetters(['bigSum'])
   },

3.mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数

 methods:{
       //靠mapActions生成:incrementOdd、incrementWait(对象形式)
       ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
       //靠mapActions生成:incrementOdd、incrementWait(数组形式)
       ...mapActions(['jiaOdd','jiaWait'])
   }

4. mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数

methods:{
       //靠mapActions生成:increment、decrement(对象形式)
       ...mapMutations({increment:'JIA',decrement:'JIAN'}),
       //靠mapMutations生成:JIA、JIAN(对象形式)
       ...mapMutations(['JIA','JIAN']),
   }

> 备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。

 7.模块化+命名空间

1. 目的:让代码更好维护,让多种数据分类更加明确。

2. 修改store.js

 const countAbout = {
     namespaced:true,//开启命名空间
     state:{x:1},
     mutations: { ... },
     actions: { ... },
     getters: {
       bigSum(state){
          return state.sum * 10
       }
     }
   }
   const personAbout = {
     namespaced:true,//开启命名空间
     state:{ ... },
     mutations: { ... },
     actions: { ... }
   }
   const store = new Vuex.Store({
     modules: {
       countAbout,
       personAbout
     }
   })

3. 开启命名空间后,组件中读取state数据:

 //方式一:自己直接读取
   this.$store.state.personAbout.list
   //方式二:借助mapState读取:
   ...mapState('countAbout',['sum','school','subject']),

4. 开启命名空间后,组件中读取getters数据:

 //方式一:自己直接读取
   this.$store.getters['personAbout/firstPersonName']
   //方式二:借助mapGetters读取:
   ...mapGetters('countAbout',['bigSum'])

5. 开启命名空间后,组件中调用dispatch

 //方式一:自己直接dispatch
   this.$store.dispatch('personAbout/addPersonWang',person)
   //方式二:借助mapActions:
   ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

6. 开启命名空间后,组件中调用commit

 //方式一:自己直接commit
   this.$store.commit('personAbout/ADD_PERSON',person)
   //方式二:借助mapMutations:
   ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值