首页 > 其他分享 >Vue2.0+3.0笔记

Vue2.0+3.0笔记

时间:2022-11-25 10:33:20浏览次数:35  
标签:vue value Vue2.0 state Vue 笔记 3.0 组件 store

生命周期 

非单文件组件:全局事件时

 

 脚手架文件结构  

 ├── 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:包版本控制文件

关于不同版本的Vue

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

vue.config.js配置文件

1. 使用vue inspect > output.js可以查看到Vue脚手架的默认配置。 2. 使用vue.config.js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh

ref属性

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

props配置项

1. 功能:让组件接收外部传过来的数据 2. 传递数据:```<Demo name="xxx"/>``` 3. 接收数据:     1. 第一种方式(只接收):```props:['name'] ```     2. 第二种方式(限制类型):```props:{name:String}```     3. 第三种方式(限制类型、限制必要性、指定默认值):       
 ```js
        props:{
         name:{
         type:String, //类型
         required:true, //必要性
         default:'老王' //默认值
         }
        }
        ```
    > 备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

mixin(混入)

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

插件

1. 功能:用于增强Vue npm i vue-resource mian.ts中引入和使用
// 引入Vue
import Vue from 'vue'
// 引入App
import App from './App.vue'
Vue.config.productionTip = false
// 引入插件plugins.js
import plugins from './plugins'
// 关闭Vue的生产提示
Vue.config.productionTip = false

// 引用插件
Vue.use(plugins)
//应用(使用)插件 install(Vue,x,y,z)
Vue.use(plugins,1,2,3)
// 创建vm
new Vue({
  render: h => h(App)
}).$mount('#app')
2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。 3. 定义插件:  plugins.js
```js
    对象.install = function (Vue, options) {
        // 1. 添加全局过滤器
        Vue.filter(....)
   
        // 2. 添加全局指令
        Vue.directive(....)
   
        // 3. 配置全局混入(合)
        Vue.mixin(....)
   
        // 4. 添加实例方法
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
    }
    ```
export default {
  install(Vue,x,y,z){
    console.log(x,y,z)
    //全局过滤器
    Vue.filter('mySlice',function(value){
      return value.slice(0,4)
    })

    //定义全局指令
    Vue.directive('fbind',{
      //指令与元素成功绑定时(一上来)
      bind(element,binding){
        element.value = binding.value
      },
      //指令所在元素被插入页面时
      inserted(element,binding){
        element.focus()
      },
      //指令所在的模板被重新解析时
      update(element,binding){
        element.value = binding.value
      }
    })
    //定义混入
    Vue.mixin({
      data() {
        return {
          x:100,
          y:200
        }
      },
    })

    //给Vue原型上添加一个方法(vm和vc就都能用了)
    Vue.prototype.hello = ()=>{alert('你好啊')}
  }
}
4. 使用插件:```Vue.use()```,mian.ts中
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件vue-resource
import vueResource from 'vue-resource'
//关闭Vue的生产提示
Vue.config.productionTip = false
// 使用插件
Vue.use(vueResource)

//创建vm
new Vue({
  render: h => h(App),
  beforeCreate() {//开启总线
    Vue.prototype.$bus = this
  },
}).$mount('#app')

scoped样式

1. 作用:让样式在局部生效,防止冲突。 2. 写法:```<style scoped>```

总结TodoList案例

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

webStorage

1. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样) 2. 浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。 3. 相关API:  
  1. ```xxxxxStorage.setItem('key', 'value');```
                  该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。

    2. ```xxxxxStorage.getItem('person');```

        ​      该方法接受一个键名作为参数,返回键名对应的值。

    3. ```xxxxxStorage.removeItem('key');```

        ​      该方法接受一个键名作为参数,并把该键名从存储中删除。

    4. ``` xxxxxStorage.clear()```

        ​      该方法会清空存储中的所有数据。
4. 备注:     1. SessionStorage存储的内容会随着浏览器窗口关闭而消失。     2. LocalStorage存储的内容,需要手动清除才会消失。     3. ```xxxxxStorage.getItem(xxx)```如果xxx对应的value获取不到,那么getItem的返回值是null。     4. ```JSON.parse(null)```的结果依然是null。

组件的自定义事件

1. 一种组件间通信的方式,适用于:子组件 ===> 父组件 2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。 3. 绑定自定义事件:     1. 第一种方式,在父组件中:```<Demo @atguigu="test"/>```  或 ```<Demo v-on:atguigu="test"/>```     2. 第二种方式,在父组件中:
        ```js
        <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指向会出问题!

全局事件总线(GlobalEventBus):任意组件事件之间的传递,如爷孙组件

1. 一种组件间通信的方式,适用于任意组件间通信this.$bus.     2. 安装全局事件总线:
   ```js
   new Vue({
      ......
      beforeCreate() {
         Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
      },
       ......
   })
   ```
3. 使用事件总线:    1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。   
      ```js
      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo) // $bus总线.$on绑定事件(‘事件名’,触发调用函数)
     } ```
 2. $emit提供数据:```this.$bus.$emit('xxxx',数据)```
item.vue中需触发事件
methods: {
    //勾选or取消勾选
    handleCheck(id){
      // 通知App组件将对应的todo对象的done值取反
      // 数据在App中,前往App
      // this.checkTodo(id)
      // 总线: 触发事件
      this.$bus.$emit('checkTodo',id)
    },
    // 删除
    handleDelete(id){
      if (confirm('确定删除吗?')){
        // this.deleteTodo(id)
        // 总线: 触发事件
        this.$bus.$emit('deleteTodo',id)
      }
    }
  }
4. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件销毁组件事件绑定注:必须带事件名参数,不然销毁所有组件this.$bus.$off('事件名')
app.vue
// 总线开启:接收item.vue组件传参,使用钩子$on和$off完整写法
  mounted(){
    // $bus总线.$on绑定事件(‘事件名’,触发调用函数)
    this.$bus.$on('checkTodo',this.checkTodo)
    this.$bus.$on('deleteTodo',this.deleteTodo)
  },
  // 总线.$off解绑时间
  beforeDestroy(){
    this.$bus.$off('checkTodo')
    this.$bus.$off('deleteTodo')
  }
总线:场景更适应爷孙深层次组件事件之间的传递。

消息订阅与发布(pubsub)

1.   一种组件间通信的方式,适用于任意组件间通信(需要数据的地方是订阅消息,提供数据的地方是发布消息) 2. 使用步骤:    1. 安装pubsub:```npm i pubsub-js```    2. 引入: ```import pubsub from 'pubsub-js'```,一般组件挂载完后进行订阅,mounted(){}    3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身
      ```js
      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
      }
      ```
   4. 提供数据:```pubsub.publish('xxx',数据)```    5. 最好在beforeDestroy钩子中,用```PubSub.unsubscribe(pid)```去取消订阅注:相对于总线和消息订阅实现功能,Vue推荐使用总线   

nextTick :实际开发中使用较多

1. 语法:```this.$nextTick(回调函数)```
<template>
  <li>
    <label>
      <input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
      <!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props -->
      <!-- <input type="checkbox" v-model="todo.done"/> -->
      <span v-show="!todo.isEdit">{{todo.title}}</span>
      <!--@blur='handleBlur('数据,新数据')’-->
      <input
        type="text"
        v-show="todo.isEdit"
        :value="todo.title"
        @blur="handleBlur(todo,$event)"
        ref="inputTitle"  //使用nextTick
      >
    </label>
    <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
    <button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button>
  </li>
</template>

<script>
// 引入消息订阅pubsub:发布
import pubsub from 'pubsub-js'

export default {
  name:'MyItem',
  //声明接收todo
  props:['todo'],
  methods: {
    //勾选or取消勾选
    handleCheck(id){
      //通知App组件将对应的todo对象的done值取反
      // this.checkTodo(id)
      this.$bus.$emit('checkTodo',id)
    },
    //删除
    handleDelete(id){
      if(confirm('确定删除吗?')){
        //通知App组件将对应的todo对象删除
        // this.deleteTodo(id)
        // this.$bus.$emit('deleteTodo',id)
        // publish发布消息
        pubsub.publish('deleteTodo',id)
      }
    },
    // 编辑状态
    handleEdit(todo){
      // 使用hasOwenProperty('isEdit')判断自身是否有isEdit属性
      if (todo.hasOwnProperty('isEdit')){
        todo.isEdit = true
      }else {
        // console.log('@')
        this.$set(todo,'isEdit',true)
      }
      // nextTick:下一次 DOM 更新结束后执行
      // 当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行
      this.$nextTick(function (){
        this.$refs.inputTitle.focus()
      })
    },
    // 失去焦点回调(真正执行修改逻辑):编辑状态结束
    // 接收@blur='handleBlur('数据,新数据')’
    handleBlur(todo,e){
      todo.isEdit = false
      if(!e.target.value.trim()) return alert('输入不能为空!')
      // 总线:提交新数据,$emit('事件名','数据_id','修改的新数据')
      this.$bus.$emit('upDataTodo',todo.id,e.target.value)
    }
  },
}
</script>
2. 作用:在下一次 DOM 更新结束后执行其指定的回调。 nextTick所指定的回调会在下一次 DOM 更新结束后执行 3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。 定时器虽然也能达到效果,但推荐使用nextTick

Vue封装的过度与动画

1. 作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。 2. 图示:<img src="https://img04.sogoucdn.com/app/a/100520146/5990c1dff7dc7a8fb3b34b4462bd0105" style="width:60%" />   3. 写法:    1. 准备好样式:       - 元素进入的样式:         1. v-enter:进入的起点         2. v-enter-active:进入过程中         3. v-enter-to:进入的终点       - 元素离开的样式:         1. v-leave:离开的起点         2. v-leave-active:离开过程中         3. v-leave-to:离开的终点
   2. 使用```<transition>```包裹要过度的元素,并配置name属性:
      ```vue
      <transition name="hello">
         <h1 v-show="isShow">你好啊!</h1>
      </transition>
      ```

Test.vue完整代码:

<!--使用过渡动画-->
<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <!--过渡标签:transition -->
    <!--过渡标签自定义name='hello':style中 v-变更hello-enter-active-->
    <!--:appear='true'缺省写法 ,直接 appear默认-->
    <!--<transition name="hello" :appear="true">-->
    <transition name="hello" appear>
      <h1 v-show="isShow" >你好啊</h1>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'Test',
  data () {
    return {
      isShow:true
    }
  },
}
</script>

<style scoped>
  h1{
    background-color: orange;
  }
  /*使用过渡标签后自动动画,Vue特定:v-enter-active*/
  /*vue-enter进入-active激活*/
  /*.v-enter-active {
    !*css3动画来:匀速*!
    animation: atguigu 1s linear;
  }*/
  /*<!--过渡标签自定义name='hello':style中 v-变更hello-enter-active-->*/
  .hello-enter-active {
    animation: atguigu 1s linear;
  }
  /*使用过渡标签后自动动画,Vue特定:v-leave-active*/
  /*vue-leave离开-active激活*/
  /*<!--过渡标签自定义name='hello':style中 v-变更hello-leave-active-->*/
  /*.v-leave-active {*/
  .hello-leave-active {
    /*css3动画离开*/
    /*播放动画:atguigu 1秒 reverse翻转*/
    animation: atguigu 1s reverse;
  }

  /*定义动画关键帧*/
  @keyframes atguigu {
    from{
      transform: translateX(-100%);
    }
    to{
      transform: translateY(0px);
    }
  }
</style>
   3. 备注:若有多个元素需要过度,则需要使用:```<transition-group>```,且每个元素都要指定```key```值。

Test2.vue完整代码:

<!--不使用过渡动画-->
<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <!--过渡标签:transition -->
    <!--过渡标签自定义name='hello':style中 v-变更hello-enter-active-->
    <!--:appear='true'缺省写法 ,直接 appear默认-->
    <!--<transition name="hello" :appear="true">-->
    <transition name="hello" appear>
      <h1 v-show="isShow" >你好啊</h1>
    </transition>
    <!--有多个元素需要过度,则需要使用:```<transition-group>```,且每个元素都要指定```key```值-->
    <!--使用场景:如效果取反时-->
    <transition-group name="hello" appear>
      <h1 v-show="!isShow" key="1">你好啊!</h1>
      <h1 v-show="isShow" key="2">尚硅谷</h1>
    </transition-group>
  </div>
</template>

<script>
export default {
  name: 'Test',
  data () {
    return {
      isShow:true
    }
  },
}
</script>

<style scoped>
/*破坏原有h1效果:transition */
h1{
  background-color: orange;
  /*transition: 0.5s linear;*/
}
/*进入的起点,离开的终点*/
.hello-enter,.hello-leave-to {
  transform: translateX(-100%);
}
/*避免破坏h1原有代码:*/
.hello-enter-active,.hello-leave-active {
  transition: 0.5s linear;
}
/*进入的终点、离开的起点*/
.hello-enter-to,.hello-leave {
  transform: translateX(0);
}

</style>

使用animate.css第三方库方法

安装:npm install -y animate.css --save

Test3.vue完整代码

<!--使用animate.css第三方库-->
<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <!--过渡标签:transition -->
    <!--过渡标签自定义name='hello':style中 v-变更hello-enter-active-->
    <!--:appear='true'缺省写法 ,直接 appear默认-->
    <!--<transition name="hello" :appear="true">-->
    <!--<transition name="hello" appear>
      <h1 v-show="isShow" >你好啊</h1>
    </transition>-->

    <!--有多个元素需要过度,则需要使用:```<transition-group>```,且每个元素都要指定```key```值-->
    <!--使用场景:如效果取反时-->
    <!--使用第三方animate.css时,按官网配置name='animate__animated animate__bounce'
    enter-active-class="效果名animate__swing"
    leave-active-class="效果名animate__backOutUp" 三个。
    -->
    <transition-group
      name="animate__animated animate__bounce"
      enter-active-class="animate__swing"
      leave-active-class="animate__backOutUp"
      appear>
      <h1 v-show="!isShow" key="1">你好啊!</h1>
      <h1 v-show="isShow" key="2">尚硅谷</h1>
    </transition-group>
  </div>
</template>

<script>
// 引入第三方animate.css库
import 'animate.css'

export default {
  name: 'Test',
  data () {
    return {
      isShow:true
    }
  },

}
</script>

<style scoped>
/*破坏原有h1效果:transition */
h1{
  background-color: orange;
  /*transition: 0.5s linear;*/
}

/*使用第三库时,以下省略不写*/
/*
!*进入的起点,离开的终点*!
.hello-enter,.hello-leave-to {
  transform: translateX(-100%);
}
!*避免破坏h1原有代码:*!
.hello-enter-active,.hello-leave-active {
  transition: 0.5s linear;
}

!*进入的终点、离开的起点*!
.hello-enter-to,.hello-leave {
  transform: translateX(0);
}
*/

</style>

 

vue脚手架配置代理

Vue中推荐使用ajax库:   Axios库

npm i axios

方法一

​  在vue.config.js中添加如下配置:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave: false, // 关闭语法检查

  // 开启代理服务器:端口5000
  // 弊端1:不能配置多个代理,只能唯一
  // 弊端2:请求本地无时,才走代理服务器
  devServer:{
    proxy:"http://localhost:5000"
  }
})
说明: 1. 优点:配置简单,请求资源时直接发给前端(8080)即可。 2. 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。 3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

方法二

​  编写vue.config.js配置具体代理规则:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave: false, // 关闭语法检查

  // 方式一
  // 开启代理服务器:端口5000
  // 弊端1:不能配置多个代理,只能唯一
  // 弊端2:请求本地无时,才走代理服务器
  /*devServer:{
    proxy:"http://localhost:5000"
  },*/
  // 方式二: 官网devServer.proxy中
  // 更多的代理控制行为
  devServer: {
    proxy: {
      // 代理1:正常写法
      // 注:使用一个 path: options 成对的对象 重点
      // ‘/api’前缀:可自定义
      '/atguigu': {//匹配所有以’/atguigu‘开头的请求路径
        target: 'http://localhost:5000', // 代理目标的基础路径
        pathRewrite: {'^/atguigu':''},// 重写路径:{key'匹配所有^/atguigu : value为'空'}
        ws: true, // 用于支持websocket
        // 用于控制请求头中的host值
        changeOrigin: true // 来自于路径:ture为5000请求服务器端口一致,false默认为8080真实端口
      },
      '/demo': {
        target: 'http://localhost:5001',
        // 重写路径:{key'匹配所有^/atguigu : value为'空'}
        pathRewrite: {'^/demo':''},
        ws: true, // 用于支持websocket
        // 用于控制请求头中的host值
        changeOrigin: true // 来自于路径:false为5000请求服务器端口一致,true为8080真实端口
      },
      // 代理2:精简写法
      '/foo': {
        target: '<other_url>'
      }
    }
  }
})
   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000    changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080,
   changeOrigin默认值为true   对应的App.vue完整代码
<template>
  <div>
    <button @click="getStudents">获取学生信息</button>
    <button @click="getCars">获取汽车信息</button>
  </div>
</template>

<script>
// 引入axios
import axios from 'axios'

export default {
  name:'App',
  methods: {
    getStudents(){
      // 请求get().then()返回值:前提配置好vue.config.js中代理服务器和端口
      // vue.config.js中配置了/atguigu前缀,端口后放前缀
      // 问题:代理转发路径时带有/atguigu报错,需重写代理路径pathRewrite
      axios.get('/atguigu/http://localhost:8080/atguigu/students').then(
        // 成功和失败:获取的是对象data,不是data()方法
        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>
<style>
</style>
说明: 1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。 2. 缺点:配置略微繁琐,请求资源时必须加前缀。  

github_Search案例

1、拆解index.html为Search.vue和List.vue组件

2、style中引入index.css

3、引入第三方库:bootstrap.css

  1、src/assets静态资源创建Css文件夹资源:问题报错 如字体等

// 引入css问题:第三方资源字体或其他无资源时报错
// 问题解决:在公共资源public里建立静态资源Css
import './assets/css/bootstrap.css'

  2、将第三方库移动至public文件夹下,并在index.html中添加 <link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">

 

<!DOCTYPE html>
<html lang="">
  <head>
      <meta charset="utf-8">
      <!--  针对IE浏览器的一个特殊配置,含义是让IE浏览器以最高的渲染级别渲染页面  -->
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <!--  开启移动端的理想视口-->
      <meta name="viewport" content="width=device-width,initial-scale=1.0">
      <!--  配置页签图标-->
      <link rel="icon" href="<%= BASE_URL %>favicon.ico">
      <!--  注:引入第三方样式 -->
      <link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">
      <!--  配置网页标题-->
      <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <!--当浏览器不支持js时noscript中的元素就会被渲染-->
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <!--容器-->
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

 完善案例完整代码:

mian.ts

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false

//创建vm
new Vue({
  render: h => h(App),
  beforeCreate() {//开启总线
    Vue.prototype.$bus = this
  },
}).$mount('#app')

App.vue

<template>
  <div class="container">
    <Search/>
    <List/>
  </div>
</template>

<script>
import Search from '@/components/Search'
import List from '@/components/List'
// 引入css问题:第三方资源字体或其他无资源时报错
// 问题解决:在公共资源public里建立静态资源Css
// import './assets/css/bootstrap.css'

export default {
  name:'App',
  components:{Search,List},
}
</script>
<style>

</style>

components中Search.vue

<template>
  <section class="jumbotron">
    <h3 class="jumbotron-heading">Search Github Users</h3>
    <div>
      <!--获取用户关键词:v-model='keyword'-->
      <input type="text" placeholder="enter the name you search" v-model="keyWord"/>&nbsp;
      <button @click="searchUsers">Search</button>
    </div>
  </section>
</template>

<script>
// 引入axios
import axios from 'axios'

export default {
  name: 'Search',
  data(){
    return{
      keyWord: '',
    }
  },
  methods: {
    searchUsers(){
      //总线:提供数据,请求前更新List的数据
      this.$bus.$emit('updateListData',{isLoading:true,errMsg:'',users:[],isFirst:false})

      // 注意:需要模板解析要使用 ~ `` 符号包裹,q=${this.keyWord}
      axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
          response => {
            console.log('请求成功了')
            // 请求成功后更新List的数据
            this.$bus.$emit('updateListData',{isLoading:false,errMsg:'',users:response.data.items})
          },
          error => {
            // 请求后更新List的数据
            this.$bus.$emit('updateListData',{isLoading:false,errMsg:error.message,users:[]})
          }
      )
    }
  }

}
</script>

<style scoped>

</style>

components中List.vue

<template>
  <div class="row">
    <!-- 展示用户列表 -->
    <!--使用获取的用户数据绑定:user.login\user.html_url\user.avatar_url属性-->
    <div v-show="info.users.length" class="card" v-for="user in info.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>
    <!-- 展示欢迎词 -->
    <h1 v-show="info.isFirst">欢迎使用!</h1>
    <!-- 展示加载中 -->
    <h1 v-show="info.isLoading">加载中....</h1>
    <!-- 展示错误信息 -->
    <h1 v-show="info.errMsg">{{info.errMsg}}</h1>
  </div>
</template>

<script>
export default {
  name: 'List',
  data(){
    return {
      info: {
        isFirst: true,
        isLoading: false,
        errMsg:'',
        users: []
      },
    }
  },
  // 总线:接收获取数据,使用mounted钩子
  mounted () {
    this.$bus.$on('updateListData',(dataObj)=>{
      // info替换成dataObj:达到响应式效果
      // 合并属性:{...this.info,...dataObj}以...dataObj属性为主
      this.info = {...this.info,...dataObj}
    })
  },

}
</script>

<style 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> 

Vue项目中使用2个Ajax库:插件和axios的区别

mian.ts中使用插件

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件vue-resource
import vueResource from 'vue-resource'
//关闭Vue的生产提示
Vue.config.productionTip = false
// 使用插件
Vue.use(vueResource)

//创建vm
new Vue({
  render: h => h(App),
  beforeCreate() {//开启总线
    Vue.prototype.$bus = this
  },
}).$mount('#app')

Search.vue中:this.http.get替换axios.get

 

 

  

 替换后,2者功能完全一致。但是推荐使用axios库方法,插件Vue.use(vueResource)不推荐

插槽

1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件 ===> 子组件。 2. 分类:默认插槽、具名插槽、作用域插槽 3. 使用方式:    1. 默认插槽:       app.vue父组件中:              
<Category>
      <div>html结构1</div>
</Category>
<template>
  <div class="container">
    <!--绑定事件:listData统一事件名,便于接收-->
    <!--出现列表不同样式时:不需统一事件名-->
    <!--<Category title="美食" :listData="foods">-->
    <Category title="美食">
      <img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
    </Category>
    <Category title="游戏">
      <ul>
        <li v-for="(g,index) in games" :key="index">{{ g }}</li>
      </ul>
    </Category>
    <Category title="电影" :listData="films">
      <!--控制播放controls:无法播放问题-->
      <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
    </Category>
  </div>
</template>

<script>
import Category from '@/components/Category'
export default {
  name:'App',
  components:{Category},
  data(){
    return{
      foods:['火锅','烧烤','小龙虾','牛排'],
      games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
      films:['《教父》','《拆弹专家》','《你好,李焕英》','《尚硅谷》']
    }
  }
}
</script>

<style lang="css">
  .container{
    display: flex;
    /*相邻距离:调整主轴*/
    justify-content: space-around;
  }
  video{
    width: 100%;
  }

</style>
      Category.vue子组件中:  
<template>
   <div>
      <!-- 定义插槽 -->
      <slot>插槽默认内容...</slot>
      </div>
</template>            
<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
    <slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
    <!--<ul>
      <li v-for="(item,index) in listData" :key="index">{{ item }}</li>
    </ul>-->
  </div>
</template>

<script>
export default {
  name: 'Category',
  props: ['listData',"title"]

}
</script>

<style scoped>
  .category{
    background-color: skyblue;
    width: 200px;
    height: 300px;
  }
  h3{
    text-align: center;
    background-color: orange;
  }
  img{
    width: 100%;
  }
</style>
   2. 具名插槽: App.vue中:父组件
      ```vue
      父组件中:
              <Category>
                  <template slot="center">
                    <div>html结构1</div>
                  </template>
     
                  <template v-slot:footer>
                     <div>html结构2</div>
                  </template>
              </Category>

完整代码

<template>
  <div class="container">   
    <Category title="美食">
      <!--slot具名插槽-->
      <img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
      <a slot="footer" href="http://www.atguigu.com" >更多美食</a>
    </Category>
    <Category title="游戏">
      <ul slot="center">
        <li v-for="(g,index) in games" :key="index">{{ g }}</li>
      </ul>
      <div class="foot" slot="footer">
        <a href="http://www.atguigu.com">单机游戏</a>
        <a href="http://www.atguigu.com">网络游戏</a>
      </div>
    </Category>
    <Category title="电影" :listData="films">
      <!--控制播放controls:无法播放问题-->
      <video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
      <!--此时template标签中的内容显示在页面上,但是看dom结构没有template标签-->
      <!--template下Vue2.6插槽:v-slot才有效新写法-->
      <template v-slot:footer>
      <!--<template slot="footer">-->
        <div  class="foot">
          <a href="http://www.atguigu.com">经典</a>
          <a href="http://www.atguigu.com">热门</a>
          <a href="http://www.atguigu.com">推荐</a>
        </div>
        <h4>欢迎前来观影</h4>
      </template>
    </Category>
  </div>
</template>

<script>
import Category from '@/components/Category'

export default {
  name:'App',
  components:{Category},
  data(){
    return{
      foods:['火锅','烧烤','小龙虾','牛排'],
      games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
      films:['《教父》','《拆弹专家》','《你好,李焕英》','《尚硅谷》']
    }
  }
}
</script>

<style lang="css">
/*可以合并简写,功能相同*/
  .container,.foot{
    /*弹性布局*/
    display: flex;
    /*相邻距离:调整主轴*/
    justify-content: space-around;
  }
  /*可以合并简写*/
  /*.foot{
    display: flex;
    !*相邻距离:调整主轴*!
    justify-content: space-around;
  }*/
  video{
    width: 100%;
  }
  h4{
    text-align: center;
  }

</style>
      子组件中:
<template>
      <div>
          <!-- 定义插槽 -->
          <slot name="center">插槽默认内容...</slot>
          <slot name="footer">插槽默认内容...</slot>
       </div>
</template>

Category.vue完整代码

<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
    <slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
    <slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
  </div>
</template>

<script>
export default {
  name: 'Category',
  props: ['listData',"title"]

}
</script>

<style scoped>
  .category{
    background-color: skyblue;
    width: 200px;
    height: 300px;
  }
  h3{
    text-align: center;
    background-color: orange;
  }
  img{
    width: 100%;
  }
</style>

   3. 作用域插槽必须使用 <template scope='自定义域名’> 标签       1. 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)       2. 具体编码:     
 ```vue
         父组件中:
                 <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>
app.vue完整代码:
<!--作用域插槽:结构是使用者来决定,数据在组件中-->
<template>
  <div class="container">
    <Category title="游戏">
      <!--作用域插槽:必须使用<template scope="自定义域名"标签接收data对象games-->
      <template scope="atguigu">
        <!--无序列表ul-->
        <ul>
          <li v-for="(g,index) in atguigu.games" :key="index">{{ g }}</li>
        </ul>
      </template>
    </Category>

    <Category title="游戏">
      <!--ES6结构赋值:scope="{games}"优化简写-->
      <template scope="{games}">
        <!--有序列表ol-->
        <ol>
          <!--ES6结构赋值:scope="{games}"优化简写-->
          <!--<li v-for="(g,index) in atguigu.games" :key="index">{{ g }}</li>-->
          <li v-for="(g,index) in games" :key="index">{{ g }}</li>
        </ol>
      </template>
    </Category>

    <Category title="游戏">
      <!--新的写法-->
      <template v-slot="{games}">
      <!--<template scope="{games}">-->
        <h4 v-for="(g,index) in games" :key="index">{{ g }}</h4>
      </template>
    </Category>
  </div>
</template>

<script>
import Category from '@/components/Category'

export default {
  name:'App',
  components:{Category},

}
</script>

<style lang="css">
/*可以合并简写,功能相同*/
  .container,.foot{
    /*弹性布局*/
    display: flex;
    /*相邻距离:调整主轴*/
    justify-content: space-around;
  }
  /*可以合并简写*/
  /*.foot{
    display: flex;
    !*相邻距离:调整主轴*!
    justify-content: space-around;
  }*/
  video{
    width: 100%;
  }
  h4{
    text-align: center;
  }
</style>

Category.vue

<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
    <!--作用域插槽:绑定事件data数据对象games-->
    <!--可以传多个对象:msg-->
    <slot :games="games" msg="hello">我是默认的一些内容</slot>

  </div>
</template>

<script>
export default {
  name: 'Category',
  props: ['listData',"title"],
  data(){
    return{
      games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
    }
  }
}
</script>

<style scoped>
  .category{
    background-color: skyblue;
    width: 200px;
    height: 300px;
  }
  h3{
    text-align: center;
    background-color: orange;
  }
  img{
    width: 100%;
  }
</style>   ```

Vuex (重点掌握

1.概念

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

2.何时使用?

​     多个组件需要共享数据时,Vue.use(vuex) Vue总线时:

 

 Vuex时:

 

 

 3.搭建vuex环境

 

 

 

 

 

 

1. 创建文件:```src/store/index.js```
   ```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
   })

完整代码:

//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)

//准备actions对象——用于响应组件中的动作
const actions = {}
//准备mutations对象——用于操作数据(state)状态
const mutations = {}
//准备stats对象——用于存储数据
const stats = {}

//创建Store({配置对象})
/*const store = new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  stats,

})
暴露导出接口
export default store*/
// 进行简写优化
// 创建并暴露store
export default new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  stats,
})
  2. 在```main.js```中创建vm时传入```store```配置项
   ```js
   ......
   //引入store
   import store from './store'
   ......
   
   //创建vm
   new Vue({
      el:'#app',
      render: h => h(App),
      store
   })
   ```
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import vueResource from 'vue-resource'
//引入store
import store from './store'

//关闭Vue的生产提示
Vue.config.productionTip = false
//使用插件
Vue.use(vueResource)

//创建vm
new Vue({
  store,// 同名触发简写store:store,
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.$bus = this
  }
}).$mount("#app")

4.基本使用

1. 初始化数据、配置```actions```、配置```mutations```,操作文件```store.js```或Store/index.js  
 ```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```,模板中不用加this, 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. <strong>mapState方法:</strong>用于帮助我们映射```state```中的数据为计算属性  
 ```js
   computed: {
       //借助mapState生成计算属性:sum、school、subject(对象写法)
        ...mapState({sum:'sum',school:'school',subject:'subject'}),
           
       //借助mapState生成计算属性:sum、school、subject(数组写法)
       ...mapState(['sum','school','subject']),
   },
   ```
2. <strong>mapGetters方法:</strong>用于帮助我们映射```getters```中的数据为计算属性
 ```js
   computed: {
       //借助mapGetters生成计算属性:bigSum(对象写法)
       ...mapGetters({bigSum:'bigSum'}),
   
       //借助mapGetters生成计算属性:bigSum(数组写法)
       ...mapGetters(['bigSum'])
   },
   ```

完整代码:index.js

//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)

//准备actions对象——用于响应组件中的动作
const actions = {
  // jia:function (){可简写
  /*jia(context,value){
    // console.log('actions中的jia被调用了!',context,value)
    context.commit('JIA',value)
  },
  jian(context,value){
    context.commit('JIAN',value)
  },*/ // 逻辑简写:功能commit直接mutations

  jiaOdd(context,value){
    console.log('actions中的jiaOdd被调用了!')
    // 使用上下文获取this.$store.state.sum判断
    // if (this.$store.state.sum % 2){
    if (context.state.sum % 2){
      context.commit('JIA',value)
    }
  },
  jiaWait(context,value){
    setTimeout(()=>{
      context.commit('JIA',value)
    },500)
  }
}
//准备mutations对象——用于操作数据(state)状态
const mutations = {// 检测数据变化
  JIA(state,value){
    // console.log('mutations中的JIA被调用了!',state,value)
    state.sum += value
  },
  JIAN (context, value) {
    state.sum -= value
  }
}
//准备stats对象——用于存储数据
const state = {
  sum: 0, //当前的和,初始数据
  School: '尚硅谷',
  subject: '前端',
}
// 准备getters:用于将state中的数据进行加工
const getters = {
  bigSum(state){
    return state.sum*10
  }
}

//创建Store({配置对象})
/*const store = new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  stats,

})
暴露导出接口
export default store*/
// 进行简写优化
// 创建并暴露store
export default new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  state,
  getters,
})

Count.vue完整代码:

<template>
  <div>
    <!--优化:可用计算属性来省略$store.state.-->
    <!--<h1>当前求和为:{{ $store.state.sum }}</h1>-->
    <h1>当前求和为:{{ sum }}</h1>
    <h3>当前求和为10倍:{{ bigSum }}</h3>
    <h3>在{{ School }},做{{ subject }}</h3>
    <!--select单选或多选菜单-->
    <!--v-model.number前置转换数值型-->
    <select v-model.number="n" name="" id="">
      <!--v-model.number前置转换数值型::value无需绑定强制数值型-->
      <!--<option :value="1">1</option>-->
      <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="incrementWait">等一等再加</button>
  </div>
</template>

<script>
// 引入 {映射状态} from vuex 生成State代码
import {mapState} from 'vuex'
import {mapGetters} from 'vuex'

export default {
  name: 'Count',
  data(){
    return{
      n: 1, //用户选择的数字
    }
  },
  computed: {
    // 靠程序员自己亲自去写计算属性
    /*sum(){
      return this.$store.state.sum
    },
    School(){
      return this.$store.state.School
    },
    subject(){
      return this.$store.state.subject
    },*/
    // 借助mapState生成计算属性,从state中读取数据。(对象写法):效果同上
    // ...mapState({})-ES6风格:逐一展开mapState中的key:value展示出来,等同
    ...mapState({sum:'sum',School:'School',subject:'subject'}),

    // 再优化:借助mapState生成计算属性,从state中读取数据。(数组写法):效果同上
    // ...mapState([value1,value2,value3]),只要kv对中的value,而且kv名要一致才可简写
    ...mapState(['sum','School','subject']),

    /* ******************************** */

    /*bigSum(){
      return this.$store.getters.bigSum
    },*/
    // 借助mapGetters生成计算属性,从getters中读取数据。(对象写法):效果同上
    // ...mapGetters({})-ES6风格:逐一展开mapGetters中的key:value展示出来,等同
    ...mapGetters({bigSum:'bigSum'}),
    
    //再优化:kv名要一致,(数组写法):效果同上
    ...mapGetters(['bigSum']),
  },
  methods: {
    increment(){
      // this.sum += this.n
      // 使用vuex的$store.dispatch(key,value)
      // this.$store.dispatch('jia',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIA',this.n)
    },
    decrement(){
      // this.sum -= this.n
      // this.$store.dispatch('jian',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIAN',this.n)
    },
    incrementOdd(){
      /*if (this.sum % 2) {
        this.sum += this.n
      }*/
      /*if (this.$store.state.sum % 2){
        this.$store.dispatch('jia',this.n)
      }*/
      this.$store.dispatch('jiaOdd',this.n)
    },
    incrementWait(){
      /*setTimeout(()=>{
        // this.sum += this.n
        this.$store.dispatch('jia',this.n)
      },500)*/
      this.$store.dispatch('jiaWait',this.n)
    },
  },
  mounted () {
    // console.log('Count',this.$store) // 组件挂载直接输出this.$store
    // 使用映射mapstate({key:value}):({sum():this.$store.state.sum})
    const x = mapState({sum:'sum',School:'School',subject:'subject'})
    console.log(x)
  }
}
</script>
<style scoped>
  button{
    margin-left: 5px;
  }
</style>
3. <strong>mapActions方法:</strong>用于帮助我们生成与```actions```对话的方法,即:包含```$store.dispatch(xxx)```的函数 Count.vue
 methods:{
       //靠mapActions生成:incrementOdd、incrementWait(对象形式)
       ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
   
       //靠mapActions生成:incrementOdd、incrementWait(数组形式)
       ...mapActions(['jiaOdd','jiaWait'])
   }
/*incrementOdd(){
      /!*if (this.sum % 2) {
        this.sum += this.n
      }*!/
      /!*if (this.$store.state.sum % 2){
        this.$store.dispatch('jia',this.n)
      }*!/
      this.$store.dispatch('jiaOdd',this.n)
    },
    incrementWait(){
      /!*setTimeout(()=>{
        // this.sum += this.n
        this.$store.dispatch('jia',this.n)
      },500)*!/
      this.$store.dispatch('jiaWait',this.n)
    },*/
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法):效果同上
    // ...mapMutations({})-ES6风格:逐一展开mapMutations中的map:key展示出来,等同
    ...mapActions({ incrementOdd:'jiaOdd',incrementWait:'jiaWait' }),
    // 数组写法:
    ...mapActions(['jiaOdd','jiaWait']),  
   ```
4. <strong>mapMutations方法:</strong>用于帮助我们生成与```mutations```对话的方法,即:包含```$store.commit(xxx)```的函数 Count.vue中   
methods:{
       //靠mapActions生成:increment、decrement(对象形式)
       ...mapMutations({increment:'JIA',decrement:'JIAN'}),
       
       //靠mapMutations生成:JIA、JIAN(对象形式)
       ...mapMutations(['JIA','JIAN']),
   }
   ```
  methods: {
    /*increment(){
      // this.sum += this.n
      // 使用vuex的$store.dispatch(key,value)
      // this.$store.dispatch('jia',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIA',this.n)
    },
    decrement(){
      // this.sum -= this.n
      // this.$store.dispatch('jian',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIAN',this.n)
    },*/
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法):效果同上
    // ...mapMutations({})-ES6风格:逐一展开mapMutations中的map:key展示出来,等同
    ...mapMutations({increment:'JIA',decrement:'JIAN'}),

    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
    // ...mapMutations(['JIA','JIAN']),
> 备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。

完整代码

main.ts

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import vueResource from 'vue-resource'

//引入store
import store from './store'

//关闭Vue的生产提示
Vue.config.productionTip = false

//使用插件
Vue.use(vueResource)

//创建vm
new Vue({
  store, // 同名触发简写store:store,
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.$bus = this
  }
}).$mount("#app")

App.vue

<template>
  <div>
    <Count/>
  </div>
</template>

<script>
import Count from '@/components/Count'

export default {
  name:'App',
  components:{Count},
  mounted () {
    console.log('App',this)
  }
}
</script>

<style lang="css">

</style>

Store/index.js

//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)

//准备actions对象——用于响应组件中的动作
const actions = {
  // jia:function (){可简写
  /*jia(context,value){
    // console.log('actions中的jia被调用了!',context,value)
    context.commit('JIA',value)
  },
  jian(context,value){
    context.commit('JIAN',value)
  },*/ // 逻辑简写:功能commit直接mutations

  jiaOdd(context,value){
    console.log('actions中的jiaOdd被调用了!')
    // 使用上下文获取this.$store.state.sum判断
    // if (this.$store.state.sum % 2){
    if (context.state.sum % 2){
      context.commit('JIA',value)
    }
  },
  jiaWait(context,value){
    setTimeout(()=>{
      context.commit('JIA',value)
    },500)
  }
}
//准备mutations对象——用于操作数据(state)状态
const mutations = {// 检测数据变化
  JIA(state,value){
    // console.log('mutations中的JIA被调用了!',state,value)
    state.sum += value
  },
  JIAN (context, value) {
    state.sum -= value
  }
}
//准备stats对象——用于存储数据
const state = {
  sum: 0, //当前的和,初始数据
  School: '尚硅谷',
  subject: '前端',
}
// 准备getters:用于将state中的数据进行加工
const getters = {
  bigSum(state){
    return state.sum*10
  }
}

//创建Store({配置对象})
/*const store = new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  stats,
})
暴露导出接口
export default store*/
// 进行简写优化
// 创建并暴露store
export default new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  state,
  getters,
})

components/Count.vue

<template>
  <div>
    <!--优化:可用计算属性来省略$store.state.-->
    <!--<h1>当前求和为:{{ $store.state.sum }}</h1>-->
    <h1>当前求和为:{{ sum }}</h1>
    <h3>当前求和为10倍:{{ bigSum }}</h3>
    <h3>在{{ School }},做{{ subject }}</h3>
    <!--select单选或多选菜单-->
    <!--v-model.number前置转换数值型-->
    <select v-model.number="n" name="" id="">
      <!--v-model.number前置转换数值型::value无需绑定强制数值型-->
      <!--<option :value="1">1</option>-->
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
// 引入 {映射状态} from vuex 生成State代码
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
// import {mapGetters} from 'vuex'
// import { mapMutations } from 'vuex'

export default {
  name: 'Count',
  data(){
    return{
      n: 1, //用户选择的数字
    }
  },
  computed: {
    // 借助mapState生成计算属性,从state中读取数据。(对象写法):效果同上
    // ...mapState({})-ES6风格:逐一展开mapState中的key:value展示出来,等同
    ...mapState({sum:'sum',School:'School',subject:'subject'}),

    // 再优化:借助mapState生成计算属性,从state中读取数据。(数组写法):效果同上
    // ...mapState([value1,value2,value3]),只要kv对中的value,而且kv名要一致才可简写
    ...mapState(['sum','School','subject']),

    /* ******************************** */

    // 借助mapGetters生成计算属性,从getters中读取数据。(对象写法):效果同上
    // ...mapGetters({})-ES6风格:逐一展开mapGetters中的key:value展示出来,等同
    ...mapGetters({bigSum:'bigSum'}),

    //再优化:kv名要一致,(数组写法):效果同上
    ...mapGetters(['bigSum']),
  },
  methods: {
    /*increment(){
      // this.sum += this.n
      // 使用vuex的$store.dispatch(key,value)
      // this.$store.dispatch('jia',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIA',this.n)
    },
    decrement(){
      // this.sum -= this.n
      // this.$store.dispatch('jian',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIAN',this.n)
    },*/
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法):效果同上
    // ...mapMutations({})-ES6风格:逐一展开mapMutations中的map:key展示出来,等同
    ...mapMutations({increment:'JIA',decrement:'JIAN'}),

    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
    // ...mapMutations(['JIA','JIAN']),

    /* **************************** */

    /*incrementOdd(){
      /!*if (this.sum % 2) {
        this.sum += this.n
      }*!/
      /!*if (this.$store.state.sum % 2){
        this.$store.dispatch('jia',this.n)
      }*!/
      this.$store.dispatch('jiaOdd',this.n)
    },
    incrementWait(){
      /!*setTimeout(()=>{
        // this.sum += this.n
        this.$store.dispatch('jia',this.n)
      },500)*!/
      this.$store.dispatch('jiaWait',this.n)
    },*/
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法):效果同上
    // ...mapMutations({})-ES6风格:逐一展开mapMutations中的map:key展示出来,等同
    ...mapActions({ incrementOdd:'jiaOdd',incrementWait:'jiaWait' }),
    // 数组写法:
    ...mapActions(['jiaOdd','jiaWait']),

  },
  mounted () {
    // console.log('Count',this.$store) // 组件挂载直接输出this.$store
    // 使用映射mapState({key:value}):({sum():this.$store.state.sum})
    const x = mapState({sum:'sum',School:'School',subject:'subject'})
    console.log(x)
  }
}
</script>

<style scoped>
  button{
    margin-left: 5px;
  }
</style>

 

多组件共享数据

App.vue中新建Person组件

 

 

 Person.vue组件代码:

<template>
  <div>
    <h1>人员列表</h1>
    <h3 style="color:red">Count组件的求和为:{{ sum }}</h3>
    <input type="text" placeholder="请输入名字" v-model="name">
    <button @click="add">添加</button>
    <ul>
      <!--<li v-for="p in $store.state.personalbar" key="p.id">{{ p.name }}</li>-->
      <!--使用computed计算属性:优化$store.state.-->
      <li v-for="p in personList" :key="p.id">{{ p.name }}</li>
    </ul>
  </div>
</template>

<script>
import {nanoid} from 'nanoid'

export default {
  name: 'Person',
  data() {
    return {
      name:''
    }
  },
  computed:{
    personList(){
      return this.$store.state.personList
    },
    sum(){
      return this.$store.state.sum
    },
    // 简写可避免问题:
    // ...mapState(['personList']),
  },
  methods:{
    add(){
      // 将输入的名字包装成对象
      const personObj = {id:nanoid(),name:this.name}
      // console.log(personObj)
      this.$store.commit('ADD_PERSON',personObj)
      // 保持输入框为空
      this.name= ''
    }
  },
}
</script>

<style scoped>

</style>

Count.vue组件代码:

<template>
  <div>
    <!--优化:可用计算属性来省略$store.state.-->
    <!--<h1>当前求和为:{{ $store.state.sum }}</h1>-->
    <h1>当前求和为:{{ sum }}</h1>
    <h3>当前求和为10倍:{{ bigSum }}</h3>
    <h3>在{{ School }},做{{ subject }}</h3>
    <h3 style="color:red">Person组件的总人数是:{{ personList.length }}</h3>
    <!--select单选或多选菜单-->
    <!--v-model.number前置转换数值型-->
    <select v-model.number="n" name="" id="">
      <!--v-model.number前置转换数值型::value无需绑定强制数值型-->
      <!--<option :value="1">1</option>-->
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
// 引入 {映射状态} from vuex 生成State代码
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
// import {mapGetters} from 'vuex'
// import { mapMutations } from 'vuex'

export default {
  name: 'Count',
  data(){
    return{
      n: 1, //用户选择的数字
    }
  },
  computed: {

    // 借助mapState生成计算属性,从state中读取数据。(对象写法):效果同上
    // ...mapState({})-ES6风格:逐一展开mapState中的key:value展示出来,等同
    ...mapState({sum:'sum',School:'School',subject:'subject'}),

    // 再优化:借助mapState生成计算属性,从state中读取数据。(数组写法):效果同上
    // ...mapState([value1,value2,value3]),只要kv对中的value,而且kv名要一致才可简写
    ...mapState(['sum','School','subject',"personList"]),

    /* ******************************** */

    // 借助mapGetters生成计算属性,从getters中读取数据。(对象写法):效果同上
    // ...mapGetters({})-ES6风格:逐一展开mapGetters中的key:value展示出来,等同
    ...mapGetters({bigSum:'bigSum'}),

    //再优化:kv名要一致,(数组写法):效果同上
    ...mapGetters(['bigSum']),
  },
  methods: {
    /*increment(){
      // this.sum += this.n
      // 使用vuex的$store.dispatch(key,value)
      // this.$store.dispatch('jia',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIA',this.n)
    },
    decrement(){
      // this.sum -= this.n
      // this.$store.dispatch('jian',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIAN',this.n)
    },*/
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法):效果同上
    // ...mapMutations({})-ES6风格:逐一展开mapMutations中的map:key展示出来,等同
    ...mapMutations({increment:'JIA',decrement:'JIAN'}),

    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
    // ...mapMutations(['JIA','JIAN']),

    /* **************************** */

    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法):效果同上
    // ...mapMutations({})-ES6风格:逐一展开mapMutations中的map:key展示出来,等同
    ...mapActions({ incrementOdd:'jiaOdd',incrementWait:'jiaWait' }),
    // 数组写法:
    ...mapActions(['jiaOdd','jiaWait']),

  },
  mounted () {
    // console.log('Count',this.$store) // 组件挂载直接输出this.$store
    // 使用映射mapState({key:value}):({sum():this.$store.state.sum})
    const x = mapState({sum:'sum',School:'School',subject:'subject'})
    console.log(x)
  }
}
</script>

<style scoped>
  button{
    margin-left: 5px;
  }
</style>

index.js或Vuex.js核心store代码:

//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)

//准备actions对象——用于响应组件中的动作
const actions = {
  // jia:function (){可简写
  /*jia(context,value){
    // console.log('actions中的jia被调用了!',context,value)
    context.commit('JIA',value)
  },
  jian(context,value){
    context.commit('JIAN',value)
  },*/ // 逻辑简写:功能commit直接mutations

  jiaOdd(context,value){
    console.log('actions中的jiaOdd被调用了!')
    // 使用上下文获取this.$store.state.sum判断
    // if (this.$store.state.sum % 2){
    if (context.state.sum % 2){
      context.commit('JIA',value)
    }
  },
  jiaWait(context,value){
    setTimeout(()=>{
      context.commit('JIA',value)
    },500)
  }
}
//准备mutations对象——用于操作数据(state)状态
const mutations = {// 检测数据变化
  JIA(state,value){
    // console.log('mutations中的JIA被调用了!',state,value)
    state.sum += value
  },
  JIAN (context, value) {
    state.sum -= value
  },
  // 添加人员:无需判断限制,可直接Mutations
  ADD_PERSON (state,value) {
    console.log('mutations中的ADD_PERSON被调用了!')
    // unshift(value):从数组最前面添加元素
    state.personList.unshift(value)
  },
}
//准备stats对象——用于存储数据
const state = {
  sum: 0, //当前的和,初始数据
  School: '尚硅谷',
  subject: '前端',
  personList: [
    {id:'001',name:'模拟'}
  ],
}

// 准备getters:用于将state中的数据进行加工
const getters = {
  bigSum(state){
    return state.sum*10
  }
}

//创建Store({配置对象})
/*const store = new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  stats,

})
暴露导出接口
export default store*/
// 进行简写优化
// 创建并暴露store
export default new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  state,
  getters,
})

7.模块化+命名空间:优化Vuex中store

 

 

 

 

 

 组件中

  

1. 目的:让代码更好维护,让多种数据分类更加明确。 2. 修改```store.js```或者index.js
 ```javascript
   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数据:
   ```js
   //方式一:自己直接读取
   this.$store.state.personAbout.list
   //方式二:借助mapState读取:
   ...mapState('countAbout',['sum','school','subject']),
   ```
4. 开启命名空间后,组件中读取getters数据:
   ```js
   //方式一:自己直接读取
   this.$store.getters['personAbout/firstPersonName']
   //方式二:借助mapGetters读取:
   ...mapGetters('countAbout',['bigSum'])
   ```
5. 开启命名空间后,组件中调用dispatch
   ```js
   //方式一:自己直接dispatch
   this.$store.dispatch('personAbout/addPersonWang',person)
   //方式二:借助mapActions:
   ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
   ```
6. 开启命名空间后,组件中调用commit
   ```js
   //方式一:自己直接commit
   this.$store.commit('personAbout/ADD_PERSON',person)
   //方式二:借助mapMutations:
   ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
   ```

 

main.ts完整代码

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import vueResource from 'vue-resource'

//引入store
import store from './store'

//关闭Vue的生产提示
Vue.config.productionTip = false

//使用插件
Vue.use(vueResource)

//创建vm
new Vue({
  store, // 同名触发简写store:store,
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.$bus = this
  }
}).$mount("#app")

App.vue完整代码

<template>
  <div>
    <Count/>
    <hr>
    <Person/>
  </div>
</template>

<script>
import Count from '@/components/Count'
import Person from '@/components/Person'

export default {
  name:'App',
  components:{Count,Person},
  mounted () {
    console.log('App',this)
  }
}
</script>

<style lang="css">

</style>

Count.vue完整代码:使用vue模块化:import {mapState,mapMutations,mapActions,mapGetters} from 'vuex'

<template>
  <div>
    <!--优化:可用计算属性来省略$store.state.-->
    <!--<h1>当前求和为:{{ $store.state.sum }}</h1>-->
    <h1>当前求和为:{{ sum }}</h1>
    <h3>当前求和为10倍:{{ bigSum }}</h3>
    <h3>在{{ School }},做{{ subject }}</h3>
    <h3 style="color:red">Person组件的总人数是:{{ personList.length }}</h3>
    <!--select单选或多选菜单-->
    <!--v-model.number前置转换数值型-->
    <select v-model.number="n" name="" id="">
      <!--v-model.number前置转换数值型::value无需绑定强制数值型-->
      <!--<option :value="1">1</option>-->
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
// 引入 {映射状态} from vuex 生成State代码
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
// import {mapGetters} from 'vuex'
// import { mapMutations } from 'vuex'

export default {
  name: 'Count',
  data(){
    return{
      n: 1, //用户选择的数字
    }
  },
  computed: {
    /*// 借助mapState生成计算属性,从state中读取数据。(对象写法):效果同上
    // ...mapState({})-ES6风格:逐一展开mapState中的key:value展示出来,等同
    ...mapState({sum:'sum',School:'School',subject:'subject'}),

    // 再优化:借助mapState生成计算属性,从state中读取数据。(数组写法):效果同上
    // ...mapState([value1,value2,value3]),只要kv对中的value,而且kv名要一致才可简写
    ...mapState(['sum','School','subject',"personList"]),*/

    //使用模块化Vuex: Store中的 a,b 模块
    // 模块化Vuex:命名空间必须开启,否则无法使用
    ...mapState('countAbout',['sum','School','subject']),
    ...mapState('personAbout',['personList']),

    /* ******************************** */

    // 借助mapGetters生成计算属性,从getters中读取数据。(对象写法):效果同上
    // ...mapGetters({})-ES6风格:逐一展开mapGetters中的key:value展示出来,等同
    // ...mapGetters({bigSum:'bigSum'}),
    // 模块化Vuex:
    ...mapGetters('countAbout',['bigSum']),

    /*//再优化:kv名要一致,(数组写法):效果同上
    ...mapGetters(['bigSum']),*/

  },
  methods: {
    /*increment(){
      // this.sum += this.n
      // 使用vuex的$store.dispatch(key,value)
      // this.$store.dispatch('jia',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIA',this.n)
    },
    decrement(){
      // this.sum -= this.n
      // this.$store.dispatch('jian',this.n) // 逻辑简写:功能commit直接mutations
      this.$store.commit('JIAN',this.n)
    },*/
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法):效果同上
    // ...mapMutations({})-ES6风格:逐一展开mapMutations中的map:key展示出来,等同
    // ...mapMutations({increment:'JIA',decrement:'JIAN'}),
    // 使用模块化Vuex
    ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),

    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
    // ...mapMutations(['JIA','JIAN']),

    /* **************************** */

    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法):效果同上
    // ...mapMutations({})-ES6风格:逐一展开mapMutations中的map:key展示出来,等同
    // ...mapActions({ incrementOdd:'jiaOdd',incrementWait:'jiaWait' }),
    // 使用Vuex模块化:
    ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

    // 数组写法:
    // ...mapActions(['jiaOdd','jiaWait']),

  },
  mounted () {
    // console.log('Count',this.$store) // 组件挂载直接输出this.$store
    // 使用映射mapState({key:value}):({sum():this.$store.state.sum})
    // const x = mapState({sum:'sum',School:'School',subject:'subject'})
    console.log(this.$store)
  }
}
</script>

<style scoped>
  button{
    margin-left: 5px;
  }
</style>

Person.vue完整代码:使用Vuex模块化:未使用。。。mapState,mapActions,mapMutions,mapGetters

<template>
  <div>
    <h1>人员列表</h1>
    <h3 style="color:red">Count组件的求和为:{{ sum }}</h3>
    <h3>列表中第一个人的名字是:{{firstPersonName}}</h3>
    <input type="text" placeholder="请输入名字" v-model="name">
    <button @click="add">添加</button>
    <button @click="addWang">添加一个姓王的人</button>
    <button @click="addPersonServer">添加一个人,名字随机</button>

    <ul>
      <!--<li v-for="p in $store.state.personalbar" key="p.id">{{ p.name }}</li>-->
      <!--使用computed计算属性:优化$store.state.-->
      <li v-for="p in personList" :key="p.id">{{ p.name }}</li>

    </ul>
  </div>
</template>

<script>
import {nanoid} from 'nanoid'
export default {
  name: 'Person',
  data() {
    return {
      name:''
    }
  },
  computed:{
    personList(){
      return this.$store.state.personAbout.personList
    },
    sum(){
      // return this.$store.state.sum
      // 使用Vuex模块化
      return this.$store.state.countAbout.sum
    },
    // 简写可避免问题:
    // ...mapState(['personList']),

    firstPersonName(){
      return this.$store.getters['personAbout/firstPersonName']
    }
  },
  methods:{
    add(){
      // 将输入的名字包装成对象
      const personObj = {id:nanoid(),name:this.name}
      // console.log(personObj)
      // this.$store.commit('ADD_PERSON',personObj)
      // 模块化vuex: '分类名/ADD_PERSON‘ 提交写法
      this.$store.commit('personAbout/ADD_PERSON',personObj)
      // 保持输入框为空
      this.name= ''
    },
    addWang(){
      const personObj={id:nanoid(),name:this.name}
      this.$store.dispatch('personAbout/addPersonWang',personObj)
      this.name=''
    },
    addPersonServer(){
      this.$store.dispatch('personAbout/addPersonServer')
    }
  },
}
</script>

<style scoped>

</style>

Store中index.js完整代码

//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'

// 引入Vuex模块
import countOptions from './count'
import personOptions from './person'

//应用Vuex插件
Vue.use(Vuex)

// 进行Vuex模块化:优化
// 求和功能相关的配置
// 模块优化:将代码迁移至count.js中
/*const countOptions = {
  namespaced: true, // 命名空间开启:可简写
  actions:{
    jiaOdd(context,value){
      console.log('actions中的jiaOdd被调用了!')
      // 使用上下文获取this.$store.state.sum判断
      // if (this.$store.state.sum % 2){
      if (context.state.sum % 2){
        context.commit('JIA',value)
      }
    },
    jiaWait(context,value){
      setTimeout(()=>{
        context.commit('JIA',value)
      },500)
    }
  },
  mutations:{
    JIA(state,value){
      // console.log('mutations中的JIA被调用了!',state,value)
      state.sum += value
    },
    JIAN (state, value) {
      state.sum -= value
    },
  },
  state:{
    sum: 0, //当前的和,初始数据
    School: '尚硅谷',
    subject: '前端',
  },
  getters:{
    bigSum(state){
      return state.sum*10
    }
  },
}*/

// 人员管理功能相关的配置
// 模块优化:将代码迁移至person.js中
/*const personOptions = {
  namespaced:true, // 命名空间开启:可简写
  actions:{},
  mutations:{
    // 添加人员:无需判断限制,可直接Mutations
    ADD_PERSON (state,value) {
      console.log('mutations中的ADD_PERSON被调用了!')
      // unshift(value):从数组最前面添加元素
      state.personList.unshift(value)
    },
  },
  state:{
    personList: [
      {id:'001',name:'模拟'}
    ],
  },
  getters:{
    bigSum(state){
      return state.sum*10
    }
  },
}*/

// 使用Vuex模块化:优化
//准备actions对象——用于响应组件中的动作
/*const actions = {
  // jia:function (){可简写
  /!*jia(context,value){
    // console.log('actions中的jia被调用了!',context,value)
    context.commit('JIA',value)
  },
  jian(context,value){
    context.commit('JIAN',value)
  },*!/ // 逻辑简写:功能commit直接mutations

  jiaOdd(context,value){
    console.log('actions中的jiaOdd被调用了!')
    // 使用上下文获取this.$store.state.sum判断
    // if (this.$store.state.sum % 2){
    if (context.state.sum % 2){
      context.commit('JIA',value)
    }
  },
  jiaWait(context,value){
    setTimeout(()=>{
      context.commit('JIA',value)
    },500)
  }
}
//准备mutations对象——用于操作数据(state)状态
const mutations = {// 检测数据变化
  JIA(state,value){
    // console.log('mutations中的JIA被调用了!',state,value)
    state.sum += value
  },
  JIAN (context, value) {
    state.sum -= value
  },
  // 添加人员:无需判断限制,可直接Mutations
  ADD_PERSON (state,value) {
    console.log('mutations中的ADD_PERSON被调用了!')
    // unshift(value):从数组最前面添加元素
    state.personList.unshift(value)
  },
}
//准备stats对象——用于存储数据
const state = {
  sum: 0, //当前的和,初始数据
  School: '尚硅谷',
  subject: '前端',
  personList: [
    {id:'001',name:'模拟'}
  ],
}

// 准备getters:用于将state中的数据进行加工
const getters = {
  bigSum(state){
    return state.sum*10
  }
}*/

//创建Store({配置对象})
/*const store = new Vuex.Store({
  actions:actions,// 同名时触发简写,如下
  mutations,
  stats,

})
暴露导出接口
export default store*/
// 进行简写优化
// 创建并暴露store
export default new Vuex.Store({
  /*actions:actions,// 同名时触发简写,如下
  mutations,
  state,
  getters,*/
  // Vuex模块化:命名空间必须开启
  modules:{
    countAbout:countOptions,
    personAbout:personOptions,
  }
})

Count.js完整代码

// 进行Vuex模块化:优化
// 求和功能相关的配置
// 优化:将代码index.js迁移至count.js中
export default {
  namespaced: true, // 命名空间开启:可简写
  actions:{
    jiaOdd(context,value){
      console.log('actions中的jiaOdd被调用了!')
      // 使用上下文获取this.$store.state.sum判断
      // if (this.$store.state.sum % 2){
      if (context.state.sum % 2){
        context.commit('JIA',value)
      }
    },
    jiaWait(context,value){
      setTimeout(()=>{
        context.commit('JIA',value)
      },500)
    }
  },
  mutations:{
    JIA(state,value){
      // console.log('mutations中的JIA被调用了!',state,value)
      state.sum += value
    },
    JIAN (state, value) {
      state.sum -= value
    },
  },
  state:{
    sum: 0, //当前的和,初始数据
    School: '尚硅谷',
    subject: '前端',
  },
  getters:{
    bigSum(state){
      return state.sum*10
    }
  },
}

Person.js完整代码

// 人员管理功能相关的配置
// 模块优化:将代码迁移至person.js中
import axios from 'axios'
import { nanoid } from 'nanoid'
export default {
  namespaced:true, // 命名空间开启:可简写
  actions:{
    addPersonWang(context,value){
      //判断名字value值中含’王‘
      if (value.name.indexOf('王')=== 0){
        context.commit('ADD_PERSON',value)
      }else{
        alert('添加的人必须姓王')
      }
    },
    // 从服务要一个名字:需要引入axios
    addPersonServer (context) {
      // 发起get请求:成功和失败的回调
      axios.get('https://api。uixsj.cn/hitokoto/get?type=social').then(
        Response => {
          context.commit('ADD_PERSON',{id:nanoid(),name:Response.data})
        },
        error => {
          alert(error.message)
        }
      )
    }
  },
  mutations:{
    // 添加人员:无需判断限制,可直接Mutations
    ADD_PERSON (state,value) {
      console.log('mutations中的ADD_PERSON被调用了!')
      // unshift(value):从数组最前面添加元素
      state.personList.unshift(value)
    },
  },
  state:{
    personList: [
      {id:'001',name:'模拟'}
    ],
  },
  getters:{
    bigSum(state){
      return state.sum*10
    }
  },
}

路由:Vue中重点(重点的重点)

 

vue-router的理解:vue 的一个插件库,专门用来实现 SPA 应用 对 SPA 应用的理解:   1. 单页 Web 应用(single page web application,SPA)。   2. 整个应用只有一个完整的页面。   3. 点击页面中的导航链接不会刷新页面,只会做页面的局部更新。   4. 数据需要通过 ajax 请求获取。

 

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

 key 为路径, value 可能是 function 或 component。前端路由component和后端路由function

路由分类   1. 后端路由:     1) 理解:value 是 function, 用于处理客户端提交的请求。     2) 工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数来处理请求, 返回响应数据。   2. 前端路由:     1) 理解:value 是 component,用于展示页面内容。     2) 工作过程:当浏览器的路径改变时, 对应的组件就会显示。

1.基本使用

1. 安装vue-router,命令:
npm i vue-router
2. 应用插件:
Vue.use(VueRouter)
3. 编写router配置项:
   ```js
   //引入VueRouter
   import VueRouter from 'vue-router'
   //引入Luyou 组件
   import About from '../components/About'
   import Home from '../components/Home'
   
   //创建router实例对象,去管理一组一组的路由规则
   const router = new VueRouter({
      routes:[
         {
            path:'/about',
            component:About
         },
         {
            path:'/home',
            component:Home
         }
      ]
   })
   
   //暴露router
   export default router
   ```

router/index.ts完整代码

import Vue from 'vue'   //注:这句必须要有,虽然在main.js里面已经引入过Vue,但是这里不要这句的话,就直接报错了Vue is not defined

// 该文件专门用于创建整个应用的路由器
import VueRouter, { RouteConfig } from 'vue-router'

// 引入组件
import About from '../components/About.vue'
import Home from '@/components/Home.vue'

Vue.use(VueRouter)

// 创建并暴露一个路由器
export default new VueRouter({
  routes:[//注:此处的方法名,记住这里是routes,不是routers,没有r,要是写成routers,控制台不会报错,就是渲染不出组件来,牢记啊!不然会让人崩溃的
    {
      path:'/about',
      component: About,//注:此处容易跟着代码提示一不小心写成components,要注意,控制台报错TypeError: Cannot read property '$createElement' of undefined
    }, // 一组路由KV对
    {
      path: '/Home',
      component: Home,
    }, // 一组路由KV对
  ], // 数组管理一堆route路由
})

/*默认路由数据
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter)

const routes: Array<RouteConfig> = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/!* webpackChunkName: "about" *!/ '../views/AboutView.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router
*/
4. 实现切换(active-class可配置高亮样式)
   App.vue
   <router-link active-class="active" to="/about">About</router-link>
   ```
5. 指定展示位置
   App.vue
   <router-view></router-view>
   ```

2.几个注意点

1. 路由组件通常存放在```pages```文件夹一般组件通常存放在```components```文件夹,一般组件就是自己写组件标签 <Banner/>  2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。 About.vue和Home.vue中   3. 每个组件都有自己的```$route```属性,里面存储着自己的路由信息。 4. 整个应用只有一个router,可以通过组件的```$router```属性获取到。

3.嵌套多级路由(多级路由)

解析静态模板:home-message.html和home.news

将静态模板拆分为Home.vue中的子组件message.vue和news.vue组件

   

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

 index.js中
   routes:[
      {
         path:'/about',
         component:About,
      },
      {
         path:'/home',
         component:Home,
         children:[ //通过children配置子级路由
            {
               path:'news', //此处一定不要写:/news
               component:News
            },
            {
               path:'message',//此处一定不要写:/message
               component:Message
            }
         ]
      }
   ]
   ```

2、路由器中router/index.ts,将拆分的message.vue和news.vue子组件写入一级路由Home

import Vue from 'vue'   //注:这句必须要有,虽然在main.js里面已经引入过Vue,但是这里不要这句的话,就直接报错了Vue is not defined

// 该文件专门用于创建整个应用的路由器
import VueRouter, { RouteConfig } from 'vue-router'

// 引入组件
import About from '@/pages/About.vue'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import Message from '../pages/Message.vue'

Vue.use(VueRouter)

// 创建并暴露一个路由器
export default new VueRouter({
  routes:[//注:此处的方法名,记住这里是routes,不是routers,没有r,要是写成routers,控制台不会报错,就是渲染不出组件来,牢记啊!不然会让人崩溃的
    {// 一级路由
      path:'/about',
      component: About,//注:此处容易跟着代码提示一不小心写成components,要注意,控制台报错TypeError: Cannot read property '$createElement' of undefined
    }, // 一组路由KV对
    {// 一级路由
      path: '/Home',
      component: Home,
      // 子路由使用数组:一级路由下二级路由
      children: [ // 子路由:可能N多个,所以使用数组
        {
          path: 'news', // 子路由:默认有‘/',遍历children时自动增加’/'
          component: News,
        },
        {
          path: 'message',
          component: Message,
        }
      ],
    }, // 一组路由KV对
  ], // 数组管理一堆route路由
})

/*源router内容
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter)

const routes: Array<RouteConfig> = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/!* webpackChunkName: "about" *!/ '../views/AboutView.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router
*/ 
2. 跳转(要写完整路径):
  Home.vue中
   <router-link to="/home/news">News</router-link>
   ```

Home.vue完整代码:

<template>
  <div>
    <h2>Home组件内容</h2>
    <div>
      <ul class="nav nav-tabs">
        <li>
          <!--<a class="list-group-item active" href="./home-news.html">News</a>-->
          <!--将a标签转变成router路由标签:router-link,to='完整跳转路径‘-->
          <!--注:子路由to='完整路径名’-->
          <router-link class="list-group-item" active-class="active"  to="/home/news">News</router-link>
        </li>
        <li>
          <!--<a class="list-group-item " href="./home-message.html">Message</a>-->
          <router-link class="list-group-item" active-class="active" to="/home/message">Message</router-link>
        </li>
      </ul>
      <!--编写路由匹配规则:router/index.vue-->
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Home',
  /*beforeDestroy () {// 周期钩子:销毁
    console.log('Home组件即将被销毁了')
  },
  mounted () {// 挂载完毕
    console.log("Home挂载完毕",this)
  },*/

}
</script>

<style scoped>

</style>

4.路由的query参数

1. 传递参数
Message.vue
   <!-- 跳转并携带query参数,to的字符串写法 -->
   <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
               
   <!-- 跳转并携带query参数,to的对象写法 -->
   <router-link
      :to="{
         path:'/home/message/detail',
         query:{
            id:666,
               title:'你好'
         }
      }"
   >跳转</router-link>
   ```

Message.vue完整代码:

<template>
  <div>
    <ul>
      <!--v-for 必须配 :key-->
      <li v-for="m in messageList" :key="m.id">
        <!--<a href="/message1">{{ m.title }}</a>&nbsp;&nbsp;-->
        <!--使用router路由:to='完整路由'-->
        <!--<router-link to="/home/message/detail">{{ m.title }}</router-link>&nbsp;&nbsp;-->
        <!--query传参:to='完整路由?id=666&title=你好啊!'-->
        <!--<router-link to="/home/message/detail?id=666&title=你好啊!">{{ m.title }}</router-link>&nbsp;&nbsp;-->
        <!--跳转路由并携带query参数,to的字符串写法,
        带有js参数${m.id}的:解析需要绑定:to="``",注意:``-->
        <!--<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp;-->

        <!-- 跳转路由并携带query参数,to的对象写法(推荐) -->
        <router-link :to="{
          // 编写2个属性
          path: '/home/message/detail', // 路由路径
          query: { // query对象传参
            id: m.id,
            title: m.title,
          }
        }">
          {{ m.title }}
        </router-link>
      </li>
    </ul>
    <hr>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'Message',
  data(){
    return{
      messageList:[
        // 可以使用axios从服务器获取数据
        {id:'001',title:'消息001'},
        {id:'002',title:'消息002'},
        {id:'003',title:'消息003'},
      ],
    }
  }
}
</script>

<style scoped>

</style>
2. 三级路由组件Detail.vue中接收参数:
Detail.vue
   $route.query.id
   $route.query.title
   ```

完整代码:

<!--编写路由信息:router/index.ts-->
<!--编写路由信息时:二级路由Message下:三级路由Detail-->
<template>
  <ul>
    <li>消息编号:{{ $route.query.id }}</li>
    <li>消息标题:{{ $route.query.title }}</li>
  </ul>
</template>

<script>

export default {
  name: 'Detail',
  mounted(){
    // console.log(this.$route) // 获取当前路由信息
  }
}
</script>

<style scoped>

</style>

5.命名路由

1. 作用:可以简化路由的跳转。 2. 如何使用    1. 给路由命名:

router/index.ts完整代码

import Vue from 'vue'   //注:这句必须要有,虽然在main.js里面已经引入过Vue,但是这里不要这句的话,就直接报错了Vue is not defined

// 该文件专门用于创建整个应用的路由器
import VueRouter, { RouteConfig } from 'vue-router'

// 引入组件
import About from '@/pages/About.vue'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import Message from '../pages/Message.vue'
import Detail from '@/pages/Detail.vue'

Vue.use(VueRouter)

// 创建并暴露一个路由器
export default new VueRouter({
  routes:[//注:此处的方法名,记住这里是routes,不是routers,没有r,要是写成routers,控制台不会报错,就是渲染不出组件来,牢记啊!不然会让人崩溃的
    {// 一级路由
      name: 'guanyu', // 命名路由:简化跳转编码
      path:'/about',
      component: About,//注:此处容易跟着代码提示一不小心写成components,要注意,控制台报错TypeError: Cannot read property '$createElement' of undefined
    }, // 一组路由KV对
    {// 一级路由
      path: '/Home',
      component: Home,
      // 子组件二级路由数组:一级路由下二级路由
      children: [ // 子路由:可能N多个,所以使用数组
        {
          path: 'news', // 子路由:默认有‘/',遍历children时自动增加’/'
          component: News,
        },
        {
          path: 'message',
          component: Message,
          children:[//三级路由:message子组件的子组件Detail
            {
              name:'xiangqing', // 命名路由:简化跳转编码
              path: 'detail',
              component: Detail,
            },
          ]
        }
      ],
    }, // 一组路由KV对
  ], // 数组管理一堆route路由
})

   2. 简化跳转:message.vue

  完整代码:

<template>
  <div>
    <ul>
      <!--v-for 必须配 :key-->
      <li v-for="m in messageList" :key="m.id">
        <!--<a href="/message1">{{ m.title }}</a>&nbsp;&nbsp;-->
        <!--使用router路由:to='完整路由'-->
        <!--<router-link to="/home/message/detail">{{ m.title }}</router-link>&nbsp;&nbsp;-->
        <!--query传参:to='完整路由?id=666&title=你好啊!'-->
        <!--<router-link to="/home/message/detail?id=666&title=你好啊!">{{ m.title }}</router-link>&nbsp;&nbsp;-->
        <!--跳转路由并携带query参数,to的字符串写法,
        带有js参数${m.id}的:解析需要绑定:to="``",注意:``-->
        <!--<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp;-->

        <!-- 跳转路由并携带query参数,to的对象写法(推荐) -->
        <router-link :to="{
          // 编写2个属性
          // path: '/home/message/detail', // 路由路径
          name: 'xiangqing', // // 命名路由index.ts中:简化path:跳转编码效果同上
          query: { // query对象传参
            id: m.id,
            title: m.title,
          }
        }">
          {{ m.title }}
        </router-link>
      </li>
    </ul>
    <hr>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'Message',
  data(){
    return{
      messageList:[
        // 可以使用axios从服务器获取数据
        {id:'001',title:'消息001'},
        {id:'002',title:'消息002'},
        {id:'003',title:'消息003'},
      ],
    }
  }
}
</script>

<style scoped>

</style>

6.路由的params参数

1. 配置路由,声明接收params参数 router/index.ts中  
import Vue from 'vue'   //注:这句必须要有,虽然在main.js里面已经引入过Vue,但是这里不要这句的话,就直接报错了Vue is not defined

// 该文件专门用于创建整个应用的路由器
import VueRouter, { RouteConfig } from 'vue-router'

// 引入组件
import About from '@/pages/About.vue'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import Message from '../pages/Message.vue'
import Detail from '@/pages/Detail.vue'

Vue.use(VueRouter)

// 创建并暴露一个路由器
export default new VueRouter({
  routes:[//注:此处的方法名,记住这里是routes,不是routers,没有r,要是写成routers,控制台不会报错,就是渲染不出组件来,牢记啊!不然会让人崩溃的
    {// 一级路由
      name: 'guanyu', // 命名路由:简化跳转编码
      path:'/about',
      component: About,//注:此处容易跟着代码提示一不小心写成components,要注意,控制台报错TypeError: Cannot read property '$createElement' of undefined
    }, // 一组路由KV对
    {// 一级路由
      path: '/Home',
      component: Home,
      // 子组件二级路由数组:一级路由下二级路由
      children: [ // 子路由:可能N多个,所以使用数组
        {
          path: 'news', // 子路由:默认有‘/',遍历children时自动增加’/'
          component: News,
        },
        {
          path: 'message',
          component: Message,
          children:[//三级路由:message子组件的子组件Detail
            {
              name:'xiangqing', // 命名路由:简化跳转编码
              // path: 'detail', // query传参
              path: 'detail/:id/:title', // params传参:id/:title占位符
              component: Detail,
            },
          ]
        }
      ],
    }, // 一组路由KV对
  ], // 数组管理一堆route路由
})
2. 传递参数 message.vue中

完整代码

<template>
  <div>
    <ul>
      <!--v-for 必须配 :key-->
      <li v-for="m in messageList" :key="m.id">
        <!--<a href="/message1">{{ m.title }}</a>&nbsp;&nbsp;-->
        <!--使用router路由:to='完整路由'-->
        <!--<router-link to="/home/message/detail">{{ m.title }}</router-link>&nbsp;&nbsp;-->
        <!--query传参:to='完整路由?id=666&title=你好啊!'-->
        <!--<router-link to="/home/message/detail?id=666&title=你好啊!">{{ m.title }}</router-link>&nbsp;&nbsp;-->

        <!--跳转路由并携带query参数,to的字符串写法,
        带有js参数${m.id}的:解析需要绑定:to="``",注意:``-->
        <!--<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp;-->

        <!-- 跳转路由并携带params参数,to的字符串写法 -->
        <!--<router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp;-->

        <!-- 跳转路由并携带query参数或者params参数,to的对象写法(推荐) -->
        <router-link :to="{
          // 编写2个属性
          // path: '/home/message/detail', // 路由路径
          name: 'xiangqing', // 命名路由index.ts中:简化跳转编码效果同上
          // query: { // query对象传参
          params: { // params对象传参,注:必须使用name:命名路由不能使用path:
            id: m.id,
            title: m.title,
          }
        }">
          {{ m.title }}
        </router-link>
      </li>
    </ul>
    <hr>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'Message',
  data(){
    return{
      messageList:[
        // 可以使用axios从服务器获取数据
        {id:'001',title:'消息001'},
        {id:'002',title:'消息002'},
        {id:'003',title:'消息003'},
      ],
    }
  }
}
</script>

<style scoped>

</style>
   > 特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置
3. 接收参数: Detail.vue中
   $route.params.id
   $route.params.title
   ```
<!--编写路由信息:router/index.ts-->
<!--编写路由信息时:二级路由Message下:三级路由Detail-->
<template>
  <ul>
    <!--query方式-->
    <!--<li>消息编号:{{ $route.query.id }}</li>-->
    <!--params方式-->
    <li>消息编号:{{ $route.params.id }}</li>
    <!--<li>消息标题:{{ $route.query.title }}</li>-->
    <li>消息标题:{{ $route.params.title }}</li>
  </ul>
</template>

<script>

export default {
  name: 'Detail',
  mounted(){
    // console.log(this.$route) // 获取当前路由信息
  }
}
</script>

<style scoped>

</style>

7.路由的props配置

​  作用:让路由组件更方便的收到参数

 

 index.vue中

 {
          path: 'message',// 子路由:可能N多个,所以使用数组
          component: Message,
          children:[//三级路由:message子组件的子组件Detail
            {
              name:'xiangqing', // 命名路由:简化跳转编码
              // path: 'detail', // query传参
              path: 'detail/:id/:title', // params传参:id/:title占位符
              component: Detail,

              //props的第一种写法,值为对象,对象中的所有key-value都会以props的形式传给当前Detail组件
              // props: {a:1,b:'hello'}, //数据写死,不常用

              //props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
              // props:true, //但是不接收query传参

              //props的第三种写法: 值为函数
              props($route){
                return{id:$route.params.id,title:$route.params.title} //靠返回值,注意传参是query还是params,Message.vue属性中
              }
            },
          ]
}

Message.vue中

 

 Detail.vue中

 

8.```<router-link>```的replace属性

1. 作用:控制路由跳转时操作浏览器历史记录的模式 2. 浏览器的历史记录有两种写入方式:分别为```push```和```replace```,```push```是追加历史记录,```replace```是替换当前记录。路由跳转时候默认为```push```

 

 

3. 如何开启```replace```模式:```<router-link replace .......>News</router-link>```

 9.编程式路由导航

1. 作用:不借助```<router-link> ```实现路由跳转,让路由跳转更加灵活 2. Message.vue具体编码:

组件路由:Message.vue 完整代码:

<template>
  <div>
    <ul>
      <!--v-for 必须配 :key-->
      <li v-for="m in messageList" :key="m.id">
        <!--<a href="/message1">{{ m.title }}</a>&nbsp;&nbsp;-->
        <!--使用router路由:to='完整路由'-->
        <!--<router-link to="/home/message/detail">{{ m.title }}</router-link>&nbsp;&nbsp;-->
        <!--query传参:to='完整路由?id=666&title=你好啊!'-->
        <!--<router-link to="/home/message/detail?id=666&title=你好啊!">{{ m.title }}</router-link>&nbsp;&nbsp;-->

        <!--跳转路由并携带query参数,to的字符串写法,
        带有js参数${m.id}的:解析需要绑定:to="``",注意:``-->
        <!--<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp;-->

        <!-- 跳转路由并携带params参数,to的字符串写法 -->
        <!--<router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp;-->

        <!-- 跳转路由并携带query参数或者params参数,to的对象写法(推荐) -->
        <router-link :to="{
          // 编写2个属性
          // path: '/home/message/detail', // 路由路径
          name: 'xiangqing', // 命名路由index.ts中:简化跳转编码效果同上
          // query: { // query对象传参,使用props第三种写法
          params: { // params对象传参,注:必须使用name:命名路由不能使用path:
            id: m.id,
            title: m.title,
          }
        }">
          {{ m.title }}
        </router-link>
        <!--编程式路由导航-->
        <!--pushShow(m):将v-for中的m当参数传入-->
        <button @click="pushShow(m)">push查看</button>
        <button @click="replaceShow(m)">replace查看</button>
      </li>
    </ul>
    <hr>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'Message',
  data(){
    return{
      messageList:[
        // 可以使用axios从服务器获取数据
        {id:'001',title:'消息001'},
        {id:'002',title:'消息002'},
        {id:'003',title:'消息003'},
      ],
    }
  },
  methods:{
    pushShow(m){// pushShow(m):将v-for中的m当参数传入
      // console.log('输出了路由器',this.$router)
      // 编程式路由导航
      this.$router.push({// 将router-link to中内容写入
        // 编写2个属性
        // path: '/home/message/detail', // 路由路径
        name: 'xiangqing', // 命名路由index.ts中:简化跳转编码效果同上
        // query: { // query对象传参,使用props第三种写法
        params: { // params对象传参,注:必须使用name:命名路由不能使用path:
          id: m.id,
          title: m.title,
        }
      })
    },
    replaceShow(m){
      // console.log('输出了路由器',this.$router)
      // 编程式路由导航
      this.$router.replace({// 将router-link to中内容写入
        name: 'xiangqing',
        params: { // params对象传参,注:必须使用name:命名路由不能使用path:
          id: m.id,
          title: m.title,
        }
      })
    }
  }
}
</script>

<style scoped>

</style>

一般路由:Banner.vue

<template>
  <div class="col-xs-offset-2 col-xs-8">
    <div class="page-header">
      <h2>Vue Router Demo</h2>
      <button @click="back">后退</button>
      <button @click="forward">前进</button>
      <button @click="test">测试一下go</button>
    </div>
  </div>
</template>

<script>

export default {
  name: 'Banner',
  methods:{
    back(){
      this.$router.back()
    },
    forward(){
      this.$router.forward()
    },
    test(){// 控制浏览器前进后退步数,3或者-3
      this.$router.go(2)
      // this.$router.go(-3)
    }
  }
}
</script>

<style scoped>

</style>

 

10.缓存路由组件

1. 作用:让不展示的News.vue路由组件保持挂载,不被销毁。数据进行缓存
2.Home.vue路由组件具体编码:注:news.vue属于Home.vue组件内容

 

Home.vue完整代码:   

<template>
  <div>
    <h2>Home组件内容</h2>
    <div>
      <ul class="nav nav-tabs">
        <li>
          <!--<a class="list-group-item active" href="./home-news.html">News</a>-->
          <!--将a标签转变成router路由标签:router-link,to='完整跳转路径‘-->
          <!--注:子路由to='完整路径名’-->
          <router-link class="list-group-item" active-class="active"  to="/home/news">News</router-link>
        </li>
        <li>
          <!--<a class="list-group-item " href="./home-message.html">Message</a>-->
          <router-link class="list-group-item" active-class="active" to="/home/message">Message</router-link>
        </li>
      </ul>
      <!--缓存路由组件:保持活跃标签:include包含组件=‘组件名’-->
      <keep-alive include="News">
        <!--编写路由匹配规则:router/index.vue-->
        <router-view></router-view>
      </keep-alive>

    </div>
  </div>
</template>

<script>
export default {
  name: 'Home',
  /*beforeDestroy () {// 周期钩子:销毁
    console.log('Home组件即将被销毁了')
  },
  mounted () {// 挂载完毕
    console.log("Home挂载完毕",this)
  },*/

}
</script>

<style scoped>

</style>

11.两个新的生命周期钩子

1. 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。 2. 具体名字:    1. ```activated```路由组件被激活时触发。    2. ```deactivated```路由组件失活时触发。 News.vue完整代码
<template>
  <ul>
    <li :style="{opacity}">欢迎学习Vue</li>
    <li>news001 <input type="text"></li>
    <li>news002 <input type="text"></li>
    <li>news003 <input type="text"></li>
  </ul>
</template>

<script>
export default {
  name: 'News',
  data(){
    return {
      opacity: 1
    }
  },
  /*beforeDestroy () {// 生命钩子周期:配合组件缓存
    console.log('News组件即将被销毁了!')
    clearInterval(this.timer) // 销毁定时器
  },
  mounted () { // 定时器
    this.timer =setInterval(()=>{
      console.log('@')
      this.opacity -= 0.01
      if(this.opacity <= 0) this.opacity =1
    },16)
  } // 与beforDestroy钩子成对出现*/
  activated () { //生命钩子 激活:组件中使用更灵活
    this.timer =setInterval(()=>{
      console.log('@')
      this.opacity -= 0.01
      if(this.opacity <= 0) this.opacity =1
    },16)
  },
  deactivated () { //生命钩子 失活 与activated成对出现
    clearInterval(this.timer) // 销毁定时器
  }

}
</script>

<style scoped>

</style>

3、回顾还有个生命周期钩子:nextTick

 // nextTick:下一次 DOM 更新结束后执行
      // 当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行
      this.$nextTick(function (){
        this.$refs.inputTitle.focus()
      })

12.路由守卫(重点):开发常用

1. 作用:对路由进行权限控制 2. 分类:全局守卫、独享守卫、组件内守卫 3. 全局守卫:

router/index.ts完整代码

import Vue from 'vue'   //注:这句必须要有,虽然在main.js里面已经引入过Vue,但是这里不要这句的话,就直接报错了Vue is not defined

// 该文件专门用于创建整个应用的路由器
import VueRouter, { RouteConfig } from 'vue-router'

// 引入组件
import About from '@/pages/About.vue'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import Message from '../pages/Message.vue'
import Detail from '@/pages/Detail.vue'

Vue.use(VueRouter)

// 创建并暴露一个路由器
// export default new VueRouter({
// 使用路由守卫时:先创建
const router = new VueRouter({
  routes:[//注:此处的方法名,记住这里是routes,不是routers,没有r,要是写成routers,控制台不会报错,就是渲染不出组件来,牢记啊!不然会让人崩溃的
    {// 一级路由
      name: 'guanyu', // 命名路由:简化跳转编码
      path:'/about',
      component: About,//注:此处容易跟着代码提示一不小心写成components,要注意,控制台报错TypeError: Cannot read property '$createElement' of undefined
      meta:{// 路由元信息:程序员自定义
        // isAuth:true, // 是否条件访问授权:是
        title:'关于',
      },
    }, // 一组路由KV对
    {// 一级路由
      name: 'zhuye',
      path: '/Home',
      component: Home,
      meta:{// 路由元信息:程序员自定义
        // isAuth:true, // 是否条件访问授权:是
        title:'主页',
      },
      // 子组件二级路由数组:一级路由下二级路由
      children: [ // 子路由:可能N多个,所以使用数组
        {
          name:'xinwen',
          path: 'news', // 子路由:默认有‘/',遍历children时自动增加’/'
          component: News,
          meta:{// 路由元信息:程序员自定义
            isAuth:true, // 是否授权:是
            title:'新闻',
          },
        },
        {
          name:'xiaoxi',
          path: 'message',
          component: Message,
          meta:{// 路由元信息:程序员自定义
            isAuth:false, // 是否授权:是
            title: '消息',
          },
          // 可能N多个,所以使用数组
          children:[//三级路由:message子组件的子组件Detail
            {
              name:'xiangqing', // 命名路由:简化跳转编码
              // path: 'detail', // query传参
              path: 'detail/:id/:title', // params传参:id/:title占位符
              component: Detail,
              meta: {
                title: '详情',
              },

              //props的第一种写法,值为对象,对象中的所有key-value都会以props的形式传给当前Detail组件
              // props: {a:1,b:'hello'}, //数据写死,不常用

              //props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
              // props:true, //但是不接收query传参

              //props的第三种写法: 值为函数
              props($route){
                return{id:$route.params.id,title:$route.params.title} //靠返回值,注意传参是query还是params
              }
            },
          ]
        }
      ],
    }, // 一组路由KV对
  ], // 数组管理一堆route路由
})

// 使用路由器守卫时;beforeEach,before什么之前Each每一次(个)路由之前
// 全局 前置 路由守卫————初始化的时候被调用、每次路由切换之前被调用
// 参数:to去哪,form来自,next放行
router.beforeEach((to, from, next) =>{
  console.log('前置路由守卫',to,from)

  // document.title = to.meta.title || '通达系统' //此处有bug,受限访问的title不受限,解决放在放行之前

  // if (to.path === '/home/news' || to.path === '/home/message'){
  // if (to.name === 'xinwen' || to.name === 'atguigu'){
  // 路由元信息:鉴权
  if (to.meta.isAuth){// 判断是否需要鉴权
    /*
    表单提交验证
    localStorage.getItem(key):获取指定key本地存储的值;   //  获取指定key 本地存储数据的值。
    localStorage.setItem(key,value):将value存储到key字段; // 获取指定value 存储到key 字段
    localStorage.removeItem(key):删除指定key本地存储的值;  // 删除指定key 本地存储的值*/
    if (localStorage.getItem('school')==='atguigu'){
      /*//此处有bug,受限访问的title不受限,解决放在放行之前,但是写2遍繁琐,直接后置路由守卫优化
      document.title = to.meta.title || '通达系统' */
      next()
    }else {
      alert('学校名不对,无权查看!')
    }
  }else {
    /*//此处有bug,受限访问的title不受限,解决放在放行之前,但是写2遍繁琐,直接后置路由守卫优化
    document.title = to.meta.title || '通达系统' */
    next()
  }
})

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

// 暴露路由器
export default router

 

  4. 独享守卫:
    {// 一级路由
      name: 'zhuye',
      path: '/Home',
      component: Home,
      meta:{// 路由元信息:程序员自定义
        // isAuth:true, // 是否条件访问授权:是
        title:'主页',
      },
      // 子组件二级路由数组:一级路由下二级路由
      children: [ // 子路由:可能N多个,所以使用数组
        {
          name:'xinwen',
          path: 'news', // 子路由:默认有‘/',遍历children时自动增加’/'
          component: News,
          meta:{// 路由元信息:程序员自定义
            isAuth:true, // 是否授权:是
            title:'新闻',
          },
          // 独享(局部)路由守卫:进入之前enter
          // 重点:独享(局部)路由守卫没有后置路由守卫!但是可以匹配全局后置路由守卫
          beforeEnter:(to, from, next)=>{
            // 逻辑与全局 前置 路由守卫一致
            console.log('独享局部路由守卫',to,from)

            // document.title = to.meta.title || '通达系统' //此处有bug,受限访问的title不受限,解决放在放行之前

            // if (to.path === '/home/news' || to.path === '/home/message'){
            // if (to.name === 'xinwen' || to.name === 'atguigu'){
            // 路由元信息:鉴权
            if (to.meta.isAuth){// 判断是否需要鉴权
              /*
              表单提交验证
              localStorage.getItem(key):获取指定key本地存储的值;   //  获取指定key 本地存储数据的值。
              localStorage.setItem(key,value):将value存储到key字段; // 获取指定value 存储到key 字段
              localStorage.removeItem(key):删除指定key本地存储的值;  // 删除指定key 本地存储的值*/
              if (localStorage.getItem('school')==='atguigu'){
                //此处有bug,受限访问的title不受限,解决放在放行之前,但是写2遍繁琐,直接后置路由守卫优化
                document.title = to.meta.title || '通达系统'
                  next()
              }else {
                alert('学校名不对,无权查看!')
              }
            }else {
              //此处有bug,受限访问的title不受限,解决放在放行之前,但是写2遍繁琐,直接后置路由守卫优化
              document.title = to.meta.title || '通达系统'
                next()
            }
          }
        },

5. 组件内守卫:

 

  

13.路由器的两种工作模式

1. 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。 2. hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。 3. hash模式:    1. 地址中永远带着#号,不美观 。    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。    3. 兼容性较好。 4. history模式:    1. 地址干净,美观 。    2. 兼容性和hash模式相比略差。    3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。 5.打包   1、服务器运行 : npm run serve  启动   2、打包生成: npm run build    项目打包

   3、npm run build    项目打包后出现dist文件夹

 

   4、部署:将dist内容上传服务器进行部署

 

       

标签:vue,value,Vue2.0,state,Vue,笔记,3.0,组件,store
From: https://www.cnblogs.com/yayuya/p/16836716.html

相关文章

  • 重构:改善既有代码的设计 读书笔记
    第1章重构,第一个示例1.1起点1.2对此起始程序的评价1.3重构的第一步1.4分解statement函数1.5进展:大量嵌套函数1.6拆分计算阶段与格式化阶段1.7进展:分离......
  • Html笔记
    html笔记html是什么HTML英文全称是HyperTextMarkupLanguage,中文译为“超文本标记语言”,专门用来设计和编辑网页。1.超文本也即超越纯文本,这意味着HTML文档不仅......
  • Clickhouse 安装使用笔记(随记 未整理)
     安装创建SHA256密码echo-n123456|openssldgst-sha256(stdin)=8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92 尝试用Navicat......
  • centos7部署heartbeat3.0
    1.概述本篇介绍在centos7.9上快速部署heartbeat3.0.6,以便在后续学习工作中使用heartbeat作为高可用软件实施其他服务的高可用部署。centos7.9源码编译按转heartbeat,大致......
  • 驱动开发学习笔记---字符设备
    字符设备是按照字节流进行读写操作的设备,读写数据是分先后顺序的。常见的点灯、按键、IIC、SPI和LCD等都是字符设备。字符设备驱动开发步骤:总体思路:------定义并初......
  • springboot笔记
    微服务阶段javase:OOPmysql:持久化html+css+js+jquery+框架:视图,框架不熟练,css不好;Javaweb:独立开发MVC三层架构的网站了:原始ssm:框架:简化了我们的开发流程,配置也开始较......
  • C++学习笔记——static
    //#include<iostream>//usingnamespacestd;////classTen//{//private://staticintc;//当静态成员函数在私有成员下定义,类外不可对其进行访问......
  • C++学习笔记——友元函数
    //#include<iostream>//usingnamespacestd;////classStu//{//protected://private://intage;//voidfun()//{//age=12;//......
  • C++学习笔记——构造函数
    //#include<iostream>//usingnamespacestd;////classStu//{//public://intage;//floatf;////构造函数,可由系统自动调用//Stu()//......
  • C++学习笔记——析构函数
    //#include<iostream>//usingnamespacestd;////classFive//{//public://intn;//Five()//定义一个构造函数//{//cout<<"调用......