【Vue2】基础知识二

脚手架文件结构

|—— node_modules
|—— public
|   |—— favicon.ico: 页签图标
|   |—— index.html: 主页面
|—— src
|   |—— assets: 存放静态资源
|   |      |—— logo.png
|   |—— components: 存放组件
|   |      |—— HelloWorld.vue
|   |—— App.vue: 汇总所有文件
|   |—— main.js: 入口文件
|
|—— .gitignore:git版本管理忽略的配置
|—— babel.config.js:babel的配置文件
|—— package-lock.json:包版本控制文件
|—— package.json:应用包配置文件
|—— README.md:应用描述文件
|—— vue.config.js:自定义控制脚手架配置
 

关于不同版本的Vue:

    1.vue.js与vue.runtime.xxx.js的区别
       1.vue.js是完整版的vue,包含:核心功能+模板解析器
       2.vue.runtime.xxx.js 是运行版的Vue,只包含:核心功能:没有模板解析器
    因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
    render函数接收到的createElement函数去指定具体内容。
 

vue.config.js配置文件

>    使用vue inspect > output.js可以查看到Vue脚手架的默认配置。
>    使用vue.config.js可以对脚手架进行个性化定制,详情见vue官网 > vue 生态cli >配置参数
 

ref属性

  1.被用来给元素或子组件注册引用信息(id的替代者)
  2.应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
  3.使用方式:
      打标识:<h1 ref="xxx">...</h1> 或 <School ref="xxx"></School>
      获取:   this.$refs.xxx
 

配置项props

    功能:让组件接收外部传过来的值
      (1)传递数据:
          <Demo name="xxx"/>
      (2)接收数据 (接受数据三种写法)
          第一种方法(只接收):
          props:['name']
          第二种方法(限制类型):
          props:{
            name:String
          }
          第三种方法(限制类型、限制必要性、指定默认值):
            props:{
              name:{
                  type:String,//类型
                  required:true,//必要性
                  default:'老王'//默认值
              }
            }
      备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,
      若业务需求确实需要修改,name请复制props的内容到data中一份,然后去修改data中的数据。(data里重新return ,储存一个新变量名储存值,然后后用methods或computed计算一下)
 

mixin(混入) 基础模块暴露,代码复用

    功能:可以把多个组件共用的配置提取成一个混入对象
    使用方式:
        第一步定义混合,例如:
          {
            data()(...),
            methods:(...)
            ......
          }
        第二步使用混入,例如:
            (1)全局混入:Vue.mixin(xxx)
            (2)局部混入:mixins:['xxx']
 

插件(使用方法类似express里的中间件)

    功能:用于增强Vue
    本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
   
    定义插件:对象.install = function(Vue,options){
       // 全局过滤器
        Vue.filter('mySlice',function (value) {})
        // 定义全局指令
        Vue.directive('fbind', {})
        // 配置全局混入
        Vue.mixin({})
        // 给vue原型上添加方法(vm和vc都能用了)
        Vue.prototype.$myMethod = () =>{alert('你好啊')}
        Vue.prototype.$myProperty = xxx
    }

    使用插件:
    Vue.use(plugins)
 

scope样式

    作用:让样式在局部生效,防止冲突。
    写法:<style scoped>  <style lang="less">
 

总结TodoList案例

    1.组件化编码流程:
      (1). 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
      (2). 实现动态组件:考虑好数据的存放位置,数据是一个组件再用,还是一些组件再用;
             1)一个组件在用:放在组件自身即可。
             2)一些组件在用:放在他们共同的父组件上(状态提升)。
      (3). 实现交互,从绑定事件开始。
    2.props适用于:
      (1)父组件==> 子组件  通信
      (2)子组件==> 父组件 通信(要求父先给一个函数)
    3.使用v-model要切记:v-model绑定的值不能是props传过来的值,因为props是只读不可修改的。
    4.props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。
 

webSrorage

    1.存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
    2.浏览器通过 Window.sessionStorageWindow.localStorage 属性来实现本地存储机制。
    3.相关API:
      1.local/sessionStorage.setItem('key', 'value')
      2.local/sessionStorage.getItem('key', 'value')
      3.local/sessionStorage.removeItem('key')
      4.local/sessionStorage.clear()
    4.备注:
      1.sessionStorage 存储的内容会随着浏览器窗口关闭而消失
      2.LocalStorage存储的内容,需要手动清除才会消失
      3.local/sessionStorage.getItem(xxx)如果对应的value获取不到,那么对应的返回值是null
      4.JSONP.parse(null)的结果依然是null
 

组件的自定义事件★

  1.一种组件间通信的方式,适用于: 子组件==>父组件
  2.使用场景:A是父组件,B是子组件,B想给A传数据,name就要在A中给B绑定自定义事件(事件的回调在A中)
  3.绑定自定义事件(自定义时间名称必须用小写或者用 x-x 连接):
        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', data)
        5.解绑自定义事件:this.$off('atguigu')
        6.组件上也可以绑定原生DOM事件,需要使用native修饰符。★
        7.注意:通过this.$refs.xxx.$on('atguigu', options)绑定自定时事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出现问题。
 

全局事件总线(GlobalEventBus)

  1.一种组件间通信方式,适用于任意组件间通信。
  2.安装全局事件总线:
      new Vue({
        ......
        beforeCreate(){
            Vue.prototype.$bus = this           //安装全局事件总线,$bus就是当前应用的vm
                            在vm create时给vue原型对象安装一个傀儡$bus(傀儡vm实例对象)
        }
        .....
      })
  3.使用事件总线:
    1).接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身
        methods(){
          demo(data){......}
        }
        .....
        mounted(){
          this.$bus.$on('事件名', this.demo)           //或者直接把this.demo写成成回调函数形式
        }
     2).提供数据:this.$bus.$emit('事件名', data)
  4.最好在beforeDestroy钩子中,用$off 去解绑当前组件所用到的事件。
 

消息订阅与发布(全局事件总线的封装库)(react常用)

  1.一种组件间通信的方式,适用于任意组件间通信。
  2.使用步骤:
    1.安装pubsub: npm i pubsub-js
    2.引入: import pubsub from 'pubsub-js'
    3.订阅方接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身
        method(){
          demo(data){.....}
        }
        .....
        mounted(){
          this.pid = pubsub.subscribe('xxx', this.demo)//订阅消息
        }
     4.发布方提供数据:pubsub.publish('xxx', data)
     5.最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid) 去取消订阅
 

nextTick

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

插槽

    1.作用:让父组件向子组件指定位置插入html结构,也是一种组件间通信的方式,使用于父组件 ===> 子组件(props反向配置)
    2.分类:默认插槽、具名插槽、作用域插槽
    3.使用方式
          1.默认插槽
            父组件
                  <Category>
                    <div>html结构</div>
                  </Category>
            子组件
                  <template>
                    <div>
                      <!-- 定义插槽 -->
                        <slot>插槽默认内容</slot>
                    </div>
                  </template>
           2.具名插槽
             父组件
                  <Category slot="center">
                      <div>html结构1</div>
                  </Category>
                  <Category v-slot:footer>
                      <div>html结构2</div>
                  </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, index) in scopeData.games" :key="index">{{g}}</li>
        </ul>
      </template>
  </Category>

  <Category>
      <template slot-scope="scopeData">
        <!-- 生成h4标题 -->
        <h4 v-for="(g, index) in scopeData.games" :key="index">{{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
<!-- !该文件用于创建Vuex中最为核心的store -->
<!-- !引入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
  })
创建文件 src/store/index.js
      2.main.js中创建vm时传入store配置项
  import Vue from "vue";
  import App from './App.vue';
  Vue.config.productionTip = false;
  <!-- !引入store -->
  import store from './store/index'

  new Vue({
      el:"#app",
      render:(h)=> h(App),
      store,
      beforeCreate() {
          Vue.prototype.$bus = this
      },
  })
main.js中创建vm时传入store配置项
      3.基本使用,配置actions、配置mutations、操作文件store.js
1.  
<!-- !该文件用于创建Vuex中最为核心的store -->
<!-- !引入vue -->
import Vue from 'vue'
<!-- !引入Vuex -->
import Vuex from 'vuex'
<!-- !使用vuex插件 -->
Vue.use(Vuex)
<!-- !准备actions,用于响应组件中的动作 -->
const actions ={
    jia(context, value) {
        console.log('actions中的jia被调用');
        context.commit('JIA', value)
    }
}
<!-- !准备mutations,用于操作数据(state) -->
const mutations ={
    JIA(state, value){
        console.log('mutations中的JIA被调用');
        state.sum += value
    }
}
<!-- !准备state,用于存储数据 -->
const state ={
    sum:0 //当前的和
}

<!-- !创建并暴露store -->
export default new Vuex.Store({
    actions,
    mutations,
    state
})
<!-- !模板里不用写this,js脚本里写应该加this -->
2.组件中读取vuex中的数据:$store.state.sum
3.组件中修改vuex中的数据:$store.dispatch('actions中的方法名', 数据)
或直接 $store.commite('mutations中的方法名', 数据)
若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit
基本使用,配置actions、配置mutations、操作文件store.js
    4.getters的使用
      1.概念:当state中的数据需要经过加工再使用时,可以使用getters加工
      2.在store.js中追加getters配置
      3.组件中读取数据,$store.getters.bigSum
<!-- !准备getters,用于将state中的数据进行加工 -->
const getters ={
    bigSum(state){
        return state.sum*10
    }
}
<!-- !创建并暴露store -->
export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
})
getters的使用
      6.四个map方法的使用
        1.mapState:用于帮助我们映射state中的数据为计算属性
<!-- !借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法) -->
computed:{
...mapMutations(['JIA', 'JIAN']),
}
<!-- !借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法) -->
computed:{
...mapMutations({increase:'JIA', decrease:'JIAN'}),
}
 
        2.mapGetters方法:用于帮助我们映射getters中的数据为计算属性
<!-- !借助mapStae生成计算属性,从state中读取数据。(对象写法) -->
computed:{
...mapGetters({bigSum:'bigsum'})
}
<!-- !借助mapState生成计算属性,从state中读取数据。(数组写法) -->
computed:{
...mapGetters(['bigSum'])
}

        3.mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数
<!-- !借助mapMutations生成对应的方法,方法中会调用diapatch去联系actions(数组写法) -->
methods:{
...mapActions(['jiaOdd', 'jiaWait']),
}
<!-- !借助mapMutations生成对应的方法,方法中会调用diapatch去联系actions(对象写法) -->
methods:{
...mapActions({increaseOdd:'jiaOdd', increaseWait:'jiaWait'})
}
四个map方法的使用
      7.模块化+命名空间
        1.目的:让代码更好维护,让多种数据分类更加明确。
        2.修改store.js(inde.js)
<!-- !求和相关的配置 -->
const countAbout = {
    <!-- *开启命名空间,以区分不同组件 -->
    namespaced:true,
    state: { x:1 },
    actions: { ... },
    mutations: { ... },
    getters: {
        bigSum(state) {
            return state.sum * 10
        }
    }
}
<!-- !人员管理相关的配置 -->
const personAbout = {
    <!-- *开启命名空间,以区分不同组件 -->
    namespaced:true,
    state: { x:1 },
    actions: { ... },
    mutations: { ... },
}
<!-- !创建并(暴露)store -->
const store =  new Vuex.Store({
    modules:{
        countAbout:countOptions,
        personAbout:personOptions
    }
})
模块化+命名空间
        3.开启命名空间后,组件中读取state数据(这里直接去案例里看具体写法)Count.vue里用了map方式,Person.vue用了纯自己写的
      方式一、自己直接读取
      return this.$store.state.personAbout.personList
      方式二、借助mapState读取
      ...mapState('countAbout', ['sum', 'school', 'subject']),
        4.开启命名空间后,组件中读取getters数据
      方式一、组件直接读取
      return this.$store.getters['personAbout/firstPersonName']
      方式二、借助mapGetters读取
      ...mapGetters('countAbout', ['bigSum'])
       5.开启命名空间后,组件中调用dispatch数据
      方式一、组件直接读取
      this.$store.dispatch('personAbout/addPersonWang', personObj)
      方式二、借助mapGetters读取
      ...mapActions('countAbout', {increaseOdd:'jiaOdd', increaseWait:'jiaWait'})
        6.开启命名空间后,组件中调用commit
      方式一、组件直接读取
      this.$store.commit('personAbout/ADD_PERSON', personObj)
      方式二、借助mapGetters读取
      ...mapMutations('countAbout', {increase:'JIA', decrease:'JIAN'}),
 

路由

    1.理解:一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router进行管理)
    2.前端路由:key是路径,value是组件。

    一、基本使用
      1.安装vue-router,命令:npm i vue-router
      2.应用插件:Vue.use(VueRouter)
      3.编写router配置项
  <!-- !该文件专门用于创建整个应用的路由器 -->
  import VueRouter from "vue-router";
  <!-- !引入路由组件 -->
  import About from '../components/About'
  import Home from '../components/Home'

  <!-- !创建并暴露一个路由器,去管理一组一组的路由规则 -->
  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>
 
    二、几个注意点
        1.路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
        2.通过切换,‘隐藏’了的路由组件,默认是被销毁掉的,需要的时候再去挂载
        3.每个组件都有组件的$route睡醒,里面存储着组件的路由消息。
        4.整个应用只有一个router,可以通过组件的$router属性获取到
 
    三、多级路由(嵌套路由)
      1.配置路由规则,使用children配置项
<!-- !创建并暴露一个路由器 -->
export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home,
            children:[  //通过childrend配置子级路由
                {
                    path:'news',    //二级路由不能加路径/
                    component:News,
                },
                {
                    path:'message', //二级路由不能加路径/
                    component:Message,
                },
            ]
        },
    ]
})
多级路由(嵌套路由)
      2.跳转(要写完整路径)
      <router-link to="/home/message">Message</router-link>
 
    四、路由的query参数
         1.传递参数
  <!-- !跳转路由并携带query参数,to的字符串写法 -->
  <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link>&nbsp;&nbsp;
  <!-- !跳转路由并携带query参数,to的对象写法 -->
  <router-link :to="{
      path:'/home/message/detail',
      query:{
          id:m.id,
          title:m.title
      }
  }">
      {{m.title}}</router-link>
传递参数
         2.接收参数
      $route.query.id
      $route.query.title
 
    五、命名路由
         1.作用:可以简化路由的跳转
         2.如何使用
            1.给路由命名:
  {
    path:'/demo',
    component:Demo,
    children:[
        {
            path:'test', //二级路由不能加路径/
            component:Test,
            children:[
                {
                    name:'hello',
                    path:'welcome', //二级路由不能加路径/
                    component:Hello,
                }
            ]
        },
    ]
  },
给路由命名
            2.简化跳转
  <!-- !简化前,需要写完整路径 -->
  <router-link to="/demo/test/welcome">跳转</router-link>
  <!-- !简化后,直接通过名字跳转 -->
  <router-link :to="{name:'hello'}">跳转</router-link>

  <!-- !简化写法配合传递参数 -->
  <router-link :to="{
      name:'hello',
      <!-- //path:'/home/message/detail', -->
      query:{
          id:m.id,
          title:m.title
      }
  }">
  跳转</router-link>
简化跳转
    六、路由的params参数
        1.配置路由,声明并接收params参数
  {
    path:'/demo',
    component:Demo,
    children:[
        {
            path:'test', //二级路由不能加路径/
            component:Test,
            children:[
                {
                    name:'hello',
                    path:'/demo/:id/:title', //使用占位符声明并接收params参数
                    component:Hello,
                }
            ]
        },
    ]
  },
路由的params参数
        2.传递参数
        路由使用params参数时,若使用to的对象写法,则不能使用path配置项(/aa/bb),必须使用name配置
  <!-- !跳转并携带params参数,to的字符串写法 -->
  <router-link to="/demo/test/welcome/666/你好">跳转</router-link>
  <!-- !跳转并携带params参数,to 的对象写法 -->
  <router-link :to="{
      name:'hello', //路由使用params参数时,若使用to的对象写法,则不能使用path配置项(/aa/bb),必须使用name配置
      query:{
          id:m.id,
          title:m.title
      }
  }">
  跳转</router-link>
传递参数
        3.接收参数
       $route.params.id
          $route.params.title
    七、路由的props配置
          作用:让路由组件更方便的收到参数
{
  path:'message', 
  component:Message,
  children:[
      {
          name:'xiangqing',
          path:'detail',  //二级路由不能加路径
          component:Detail,

          <!-- !props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件 -->
          props:{a:1,b:'hello'}
           <!-- !props的第二种写法,值为对象,若布尔值为真,就会把路由组件收到的所有params参数,以props的形式传给Detail组件 -->
          props:true
           <!-- !props的第三种写法,值为函数,此写法最强大,此处可以解构赋值并连续解构赋值 -->
          props({$route}){
              return {
                  id:$route.query.id,
                  title:$route.query.title
              }
          }
      }
  ]
},
路由的props配置
   八、<router-link>的replace属性
          1.作用:控制路由器跳转时操作浏览器历史记录的模式
          2.浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前的记录,路由跳转时候默认为push
          3.如何开启replace模式<router-link replace ...>News</router-link>

  九、编程时路由导航
          1.作用:不借助<router-link>实现路由跳转,让路由跳转更加灵活
          2.具体编码
  <!-- !$router的两个API -->
  this.$router.push({
        name:'xiangqing',   //使用params参数不允许使用path配置项
        query:{
            id:m.id,
            title:m.title
        }
  })

  this.$router.replace({
        name:'xiangqing',   //使用params参数不允许使用path配置项
        query:{
            id:m.id,
            title:m.title
        }
  })

  <!-- !$router的另外三个API -->
  前进
  back(){
      this.$router.back()
  },
  后退
  forward(){
      this.$router.forward()

  },
  可前进也可后退
  test(){
      this.$router.go(+3)
  }
$router的两个API

 

posted @ 2022-03-09 11:23  wanglei1900  阅读(51)  评论(0编辑  收藏  举报