vue2笔记(尚硅谷)

总结:

通信:

注:组件中的数据共有三种形式:data、props、computed;

1、父传子 props、(插槽)
2、 子传父 自定义事件、vuex
3、组件之间 全局事件总线、 vuex
vuex全能
(当然 $refs $attrs也有用的情景)

Vue脚手架

Vue脚手架隐藏了所有webpack相关的配置,若想查看具体的webpakc配置

请执行:vue inspect > output.js


├──node_modules

├──public

│├──favicon.ico:页签图标

│└──index.html:主页面

├──src

│├──assets:存放静态资源

││└──logo.png

││──component:存放组件

││└──HelloWorld.vue

││──App.vue:汇总所有组件

││──main.js:入口文件

├──.gitignore:git版本管制忽略的配置

├──babel.config.js:babel的配置文件

├──package.json:应用包配置文件

├──README.md:应用描述文件

├──package-lock.json:包版本控制文件 

ref属性

1、被用来给元素或子组件注册引用信息(id的替代者)
2、应用在html标签上获取到时真实dom元素,应用在组件标签上是组件实例对象
3、使用方式:

  打标识:<h1 ref="xxx">...</h1>或者<School ref="xxx" />
  获取:this.$refs.xxx

配置props

功能:让组件接收外部传过来的数据

(1)传递数据: <Demo name="xxx" />
(2)接收数据:

 		第一种(只接收)
          props:['name']
        第二种方式(限制类型)
          props:{
            name:String
          }
 第三种方式(限制类型、限制必要性、指定默认值)
   props:{
              name:{
                type:String, //类型
                required:true,  //必要性
                default:'老王'  // 默认值
              }
          }
  备注:props是只读的,vue底层会监测你对props的修改,如果你进行了修改,就会发出警告。
    若业务需求确实需要修改,那么请 复制props的内容到data中一份,然后去修改data中的数据。

minxin(混入)

功能:把多个组件共用的配置提取成一个混入对象
使用方式:
第一步:定义混合,例如:

  {
        data(){
          ...
        },
        methods:{...},
        ...
      }
  }

第二步:使用混合,例如:
(1)全局混入:Vue.mixin(xxx)
(2)局部混入:mixins:[‘xxx’]

插件

功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件传递者传递的数据。
定义插件:


    对象:install=function(Vue,options){
        // 全局过滤器
       Vue.filter(){
        ...
    })
    
    // 自定义全局指令
    Vue.directive('xxx',{
        ...
    }) ,
    // 全局混入
    Vue.mixin({
      ...
    }),
    //添加实例方法
    Vue.prototype.$myMothod=function(){...}
    Vue.prototype.$myProterty=xxx
	}
使用 :Vue.use() 

scoped

作用域,所有的样式最终会汇总到一起,如果使用了相同的class或者id,就会产生冲突(按照引用的顺序进行覆盖), scoped 限制了使用范围

总结TodoList案例

1.组件化编码流程:
(1)拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。

(2)实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

①一个组件在用:放在组件自身即可。

②一些组件在用:放在他们共同的父组件上(状态提升)

(3)实现交互:从绑定事件开始。

2.props适用于:

    (1)父组件 ==> 子组件 通信

    (2)子组件 ==> 父组件 通信 (要求父先给子一个函数)

3.使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

4.props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

本地存储 webstorage

存储内容大小一般支持5MB左右(不同浏览器可能还不一样)

浏览器端通过Window.sessionStorage和Window.localStorage属性来实现本地存储机制

相关API:


	xxxStorage.setItem('key', 'value'):该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值
	xxxStorage.getItem('key'):该方法接受一个键名作为参数,返回键名对应的值
	xxxStorage.removeItem('key'):该方法接受一个键名作为参数,并把该键名从存储中删除
	xxxStorage.clear():该方法会清空存储中的所有数据

备注:


	SessionStorage存储的内容会随着浏览器窗口关闭而消失
	LocalStorage存储的内容,需要手动清除才会消失
	xxxStorage.getItem(xxx)如果 xxx 对应的 value 获取不到,那么getItem()的返回值是null
	JSON.parse(null)的结果依然是null

组件的自定义事件:

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

A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)

绑定自定义事件:

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

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

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

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

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

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

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

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

全局事件总线

1、一种组件间的通信方式
2、安装全局事件总线

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

3、使用事件总线:
3.1、接收数据:A组件想接收数据,则在A组件给$bus绑定自定义事件,- 事件的回调在A组件自身 -

    methods(){
      demo(data){
        ...
      }
    }
    ...
      mounted(){
      this.$bus.$on('xxx',tihs.demo) //this.demo为回调函数,如果在钩子这里写必须写成箭头函数
    },
    beforeDestory(){
    this.$bus.$off('xxx')
    }

3.2、提供数据: this.$bus.$emit('xxx',数据)

4、最好在beforeDestory 钩子中,用$off去解绑 当前组件用到的事件

消息的订阅与发布 pubsub

1、一种组件间的通信方式,**适用于 任意组件通信 **
2、引入:npm i pubsub-js
3、接收数据:A组件想接收数据,则A 订阅消息 ,订阅的回调发生在A身上

另外,值得一提的是 因为pubsub-js是第三方库,vue不会帮我们管理,所以this的指向,要么用箭头函数完成回调,要么在methods里创建一个方法(比如demo)使用this.demo;
   methods(){
      demo(data){...}
    },
    mounted(){
      this.pid=pubsub.subscribe('xxx',this.demo) //订阅消息
    }

4、提供数据:pubsub.publish('xxx',数据)

5、最好在beforeDestory钩子中,用pubsub.unsubscribe(pid)去 取消订阅

nextTick

1、语法:this.$nextTick(回调函数)
2、作用:在下一次更新结束之后执行指定回调
3、什么时候用:当改变数据后,- 要基于更新后的dom进行某些操作时 -,要在nextTick所指定的回调函数中执行

vue中的ajax

vue脚手架配置代理服务器:

方法一:在vue.config.js中添加如下配置:
  devServer:{
      proxy:"http://localhost:5000"
    }

说明:

1、优点:配置简单,请求资源时直接发给前端即可

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

3、工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

方法二:
 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

说明:

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

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

插槽:

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

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

使用方式:

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>

作用域插槽:

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

具体编码:

父组件中:
		<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

什么是vuex

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

什么时候用vuex?

多个组件依赖于同一状态
来自不同组件的行为需要变更同一状态

搭建vuex环境

下载 Vuex:npm i vuex (需要注意版本匹配 vue2匹配vuex3 vue3 匹配vuex4)

vuex的基本使用

  //引入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,
    })

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

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

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

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

mapState方法:用于帮助我们映射state中的数据

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

mapGetters方法:用于帮助我们映射getters中的数据



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

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

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

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

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

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

 methods:{
    //靠mapActions生成:increment、decrement(对象形式)
    ...mapMutations({increment:'JIA',decrement:'JIAN'}),
    
    //靠mapMutations生成:JIA、JIAN(对象形式)
    ...mapMutations(['JIA','JIAN']),
  }
备注:mapActions与mapMutations使用时,若需要传递参数,则需要在模板中绑定事件时传递好参数,否则参数是事件对象

模块化+命名空间

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、安装vue-router,命令 npm i vue-router
2、应用插件:Vue.use(VueRouter)
3、编写router配置项


    //引入VueRouter
    import VueRouter from 'vue-router'
    //引入Luyout 组件
    import About from '../components/About'
    import Home from '../components/Home'

    //创建router实例对象,去管理一组一组的路由规则
     export default new VueRouter({
      routes:[
        {
          path:'/about',
          component:About
        },
        {
          path:'/home',
          component:Home
        }
      ]
    })

4、实现切换(active-class 可配置高亮样式)

    <router-link active-class="active" to="/about">About</router-link>

5、指定展示位:

    <router-view></router-view>

6、几个注意点
1、路由组件通常存放在pages文件夹,一般组件存放在components文件夹
2、通过切换,‘隐藏’了的路由组件,默认是被销毁的,需要的时候再去挂载;
3、每个组件只有一个$router属性,里面存储自己对路由信息;
4、整个应用只有一个routers,可以通过组件的$router属性获取

多级路由

1、配置路由规则,使用 children 配置项:

routes:[
		{
			path:'/about', //一级路由
			component:About,
           
		},
		{
			path:'/home',
			component:Home,
             children:[
                {
                    path:'news',
                    component:News,
                },
                {
                    path:'message',
                    component:Message, //二级路由
                }
            ]
		}
	]

2、跳转(要写完整路径):

<template>
  <div>
    <h2>Home组件内容</h2>
    <div>
      <ul class="nav nav-tabs">
        <li>
          <router-link
            class="list-group-item"
            active-class="active"
            to="/home/news"
            >News</router-link
          >
        </li>
        <li>
          <router-link
            class="list-group-item"
            active-class="active"
            to="/home/message"
            >Message</router-link
          >
        </li>
      </ul>
      <router-view></router-view>
    </div>
  </div>
</template>

路由守卫

全局路由守卫

to : 要跳转到?(即将进入的目标 路由对象)
from :从哪里?(当前导航正要离开的路由)
next :放行

//全局前置路由守卫————初始化的时候、每次路由切换之前被调用
router.beforeEach((to,from,next) => {
    console.log('前置路由守卫',to,from)
    if(to.meta.isAuth){
        if(localStorage.getItem('school')==='atguigu'){
            next()
        }else{
            alert('学校名不对,无权限查看!')
        }
    }else{
        next()
    }
})

//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
	console.log('后置路由守卫',to,from)
	document.title = to.meta.title || '硅谷系统'
})

独享路由守卫

 {
            name:'zhuye',
            path:'/home',
            component:Home,
            meta:{title:'主页'},
            children:[
                {
                    name:'xinwen',
                    path:'news',
                    component:News,
                    meta:{title:'新闻'},
                    //独享守卫,特定路由**切换之后**被调用
                    beforeEnter(to,from,next){
                        console.log('独享路由守卫',to,from)
                        if(localStorage.getItem('school') === 'atguigu'){
                            next()
                        }else{
                            alert('暂无权限查看')
                        }
                    }
                },

组件内路由守卫

<template>
    <h2>我是About组件的内容</h2>
</template>

<script>
    export default {
        name:'About',
        //通过路由规则,离开该组件时被调用
        beforeRouteEnter (to, from, next) {
            console.log('About--beforeRouteEnter',to,from)
            if(localStorage.getItem('school')==='atguigu'){
                next()
            }else{
                alert('学校名不对,无权限查看!')
            }
        },
        //通过路由规则,离开该组件时被调用
        beforeRouteLeave (to, from, next) {
            console.log('About--beforeRouteLeave',to,from)
            next()
        }
    }
</script>

路由的两种模式

1、对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值

2、hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器

3、hash模式:

地址中永远带着#号,不美观
若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
兼容性较好

4、history模式:

地址干净,美观
兼容性和hash模式相比略差
应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题

组件库

Vant
Cube UI
Mint UI
Element UI
IView UI

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值