Vue高级部分(一)

使用vue脚手架

初始化脚手架

说明

Vue脚手架是Vue官方提供的标准化开发工具(开发平台)。

目前,最新的版本是5.x。

文档:https://cli.vuejs.org/zh/

具体步骤

安装vue脚手架(仅第一次执行):

npm install -g @vue/cli

通过脚手架创建项目

vue create xxx
Vue高级部分(一)

进入项目:

cd xxx

启动项目:

npm run serve

vue脚手架项目结构

|-- README.md # 应用描述说明
|-- babel.config.js  # bable的配置文件
|-- package.json # 应用包配置文件
|-- .gitignore # git版本管理忽略的配置
|-- public 
|   |-- favicon.ico
|   `-- index.html # 主页面文件
|-- src 
|   |-- App.vue 
|   |-- assets
|   |   `-- logo.png
|   |-- components 
|   |   `-- HelloWorld.vue #示例的vue文件
|   `-- main.js # 应用入口js
`-- yarn.lock

应用示例

示例:

目录结构:

.
|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- School.vue
|   |   `-- Student.vue
|   `-- main.js
`-- yarn.lock

components/School.vue

<template>
  <div class="demo">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <button @click="showName">点我提示学校名称</button>
  </div>
</template>

<script>
export default {
  name'School',
  data () {
    return {
      name'江苏师范大学',
      address'江苏省徐州市泉山区'
    };
  },
  methods: {
    showName () {
      console.log(this.name);
    }
  }
};
</script>

<style scoped>

.demo {
  background-color: pink;
}
</style>

components/Student.vue

<template>
  <div>
    <h2>学生姓名:{{ name }}</h2>
    <h2>学校年龄:{{ age }}</h2>
  </div>
</template>

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18
    };
  }
};
</script>

App.vue

<template>
  <div>
    <img alt="logo" src="@/assets/logo.png">
    <School/>
    <Student/>
  </div>
</template>

<script>
import School from '@/components/School';
import Student from '@/components/Student';

export default {
  name'App',
  components: {
    School,
    Student
  }
};
</script>

main.js

/*
 * 该文件是整个项目的入口文件
 */

// 引入Vue
import Vue from 'vue';
// 引入App组件,该组件是所有组件的父组件
import App from './App';
// 关闭Vue的生产提示
Vue.config.productionTip = false;

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


// 创建Vue实例对象(vm)
new Vue({
  el'#app',
  // 将组件添加到容器中
  renderh => h(App),
  /*
    render (createElement) {
      console.log('render', createElement);
      return createElement(App);
    }
  */

});

ref和props

ref

作用:

  • 被用来给元素或子组件注册引用的信息(id的替代者)。
  • 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象。

打标识:

<h1 ref="xxx"></h1>
<School ref="xxx"/>

读取方式:

this.$refs.xxxx

示例:

<template>
  <div>
    <!--  通过ref属性来标识自己   -->
    <h1 ref="title" v-text="msg"></h1>
    <!--  通过ref属性来标识自己   -->
    <button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
    <!--  通过ref属性来标识自己   -->
    <School ref="sch"/>
  </div>
</template>

<script>

import School from './components/School';

export default {
  name'App',
  data () {
    return {
      msg'欢迎学习vue'
    };
  },
  methods: {
    showDOM () {
      console.log(this.$refs.title);
      console.log(this.$refs.btn);
      console.log(this.$refs.sch);
    }
  },
  components: {
    School
  }
};
</script>

props

作用:让组件接收外部传过来的数据。

传递数据:

<Demo name="xxx"/>

接收数据:

<script>
// 简单接受
export default {
  // 简单声明接收
  // props: ['name', 'sex', 'age']
};
</script>
<script>
export default {
  // 限制类型
  props: {
    nameString,
    sexString,
    ageNumber
  }
};
</script>
<script>
export default {
  // 限制类型、限制必要性、指定默认值
  props: {
    name: {
      typeString// name的类型是字符串
      requiredtrue // name是必要的
    },
    age: {
      typeNumber,
      default99 // 默认值
    },
    sex: {
      typeString,
      requiredtrue
    }
  }
};
</script>

注意:props是只读的,Vue底层会检测对props的修改,如果进行了修改,就会发出警告。

示例:

App.vue

<template>
  <div>
    <Student :age="18" name="张三" sex="女"/>
    <hr>
    <Student :age="19" name="李四" sex="男"/>
  </div>
</template>

<script>

import Student from './components/Student';

export default {
  name'App',
  components: {
    Student
  }
};
</script>

Student.vue

<template>
  <div>
    <h1>{{ msg }}</h1>
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生性别:{{ sex }}</h2>
    <h2>学生年龄:{{ age }}</h2>
  </div>
</template>

<script>
export default {
  name'Student',
  data () {
    console.log(this);
    return {
      msg'学生信息',
    };
  },
  // 简单声明接收
  // props: ['name', 'sex', 'age']
  // 接收的同时对数据进行类型限制
  /*props: {
    name: String,
    sex: String,
    age: Number
  }*/

  // 接收的同时对数据:进行类型显示+默认值的指定+必要性的限制
  props: {
    name: {
      typeString// name的类型是字符串
      requiredtrue // name是必要的
    },
    age: {
      typeNumber,
      default99 // 默认值
    },
    sex: {
      typeString,
      requiredtrue
    }
  }
};
</script>

mixin混入

概述

功能:可以将多个组件公用的配置提取成一个换入对象。

使用方式:

  • ① 定义混入,如下所示:
export default {
  methods: {
    showName () {
      alert(this.name);
    }
  }
};
  • ② 使用混入,如下所示:
<script>
// 局部混入    
// 引入一个混合
import minix from '../mixin';

export default {
  mixins: [minix]
};
</script>
import Vue from 'vue';
import App from './App.vue';
import mixin from './mixin';

Vue.config.productionTip = false;
// 全局混入
Vue.mixin(mixin);

new Vue({
  el'#app',
  renderh => h(App),
});

应用示例

示例:

项目结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- School.vue
|   |   `-- Student.vue
|   |-- main.js
|   `-- mixin.js
|-- vue.config.js
`-- yarn.lock

mixin.js

export default {
  methods: {
    showName () {
      alert(this.name);
    }
  }
};

main.js

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

Vue.config.productionTip = false;
// 全局混入
Vue.mixin(mixin);

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

<template>
  <div>
    <School/>
    <Student/>
  </div>
</template>

<script>
import Student from './components/Student';
import School from './components/School';

export default {
  name'App',
  components: {
    Student,
    School
  }
};
</script>

School.vue

<template>
  <div>
    <h2 @click="showName">学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
  </div>
</template>

<script>
//引入一个混合
import minix from '../mixin';

export default {
  name'School',
  data () {
    return {
      name'江苏师范大学',
      address'江苏省徐州市泉山区'
    };
  },
  mixins: [minix]
};
</script>

<style scoped>

</style>

Student.vue

<template>
  <div>
    <h2 @click="showName">学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
  </div>
</template>

<script>
//引入一个混合
import minix from '../mixin';

export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18
    };
  },
  mixins: [minix]
};
</script>

<style scoped>

</style>

插件

概述

Vue插件是一个包含Install方法的对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

通过install方法给Vue或Vue实例添加方法、定义全局指令等。

定义插件:

export default {
  install (Vue) {
    // 全局过滤器
    Vue.filter(...);
    // 全局指令
    Vue.directive(...);
    // 配置全局混入
    Vue.mixin(...);
    // 添加实例方法
    Vue.prototype.$mymethod = function(){...}
    // 添加实例属性
    Vue.prototype.$myprototype = xxx
  }
};

使用插件:

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

new Vue({
  el'#app',
  renderh => h(App),
});

应用示例

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- School.vue
|   |   `-- Student.vue
|   |-- main.js
|   `-- plugins.js
|-- vue.config.js
`-- yarn.lock

plugins.js

export default {
  install (Vue) {
    console.log('@@@install', Vue);
    //全局过滤器
    Vue.filter('capitalize'function (value{
      if (!value) {
        return '';
      }
      value = value.toString();
      return value.charAt(0).toUpperCase() + value.slice(1);
    });
    //全局指令
    Vue.directive('fbind', {
      //指令和元素成功绑定时
      bind (element, binding) {
        console.log('bind'this); //注意此处的this是Window
        element.value = binding.value;
      },
      //指令所在元素被插入页面时
      inserted (element, binding) {
        console.log('inserted'this, binding); //注意此处的this是Window
        element.focus();
      },
      //指令所在的模板被重新解析时
      update (element, binding) {
        console.log('update'this); //注意此处的this是Window
        element.value = binding.value;
      }
    });
  }
};

main.js

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

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

<template>
  <div>
    <School/>
    <Student/>
  </div>
</template>

<script>
import Student from './components/Student';
import School from './components/School';

export default {
  name'App',
  components: {
    Student,
    School
  }
};
</script>

School.vue

<template>
  <div>
    <h2>学校名称:{{ name | capitalize }}</h2>
    <h2>学校地址:{{ address }}</h2>
  </div>
</template>

<script>
//引入一个混合

export default {
  name'School',
  data () {
    return {
      name'江苏师大',
      address'江苏省徐州市泉山区'
    };
  },

};
</script>

Student.vue

<template>
  <div>
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
  </div>
</template>

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18
    };
  },
};
</script>

scoped样式

概述

样式在局部生效,防止冲突。

写法:

<style lang="less" scoped>
.demo {
  background-color: pink;
}
</style>

应用示例

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- School.vue
|   |   `-- Student.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

注意:当前vue脚手架使用的webpack版本是4.46.0,所以使用less需要安装对应的版本。

① 安装less-loader:yarn add less-loader@7.3.0。

② 安装less:yarn add less@4.1.1。

●main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

<template>
  <div>
    <School/>
    <Student/>
  </div>
</template>

<script>

import Student from './components/Student';
import School from './components/School';

export default {
  name'App',
  components: {
    Student,
    School
  }
};
</script>

<style lang="less">
.demo {
  background-color: pink;
}
</style>

Student.vue

<template>
  <div class="demo">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
  </div>
</template>

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18
    };
  }
};
</script>

<style scoped>
.demo {
  background-color: orange;
}
</style>

School.vue

<template>
  <div class="demo">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
  </div>
</template>

<script>
export default {
  name'School',
  data () {
    return {
      name'江苏师范大学',
      address'江苏省徐州市泉山区'
    };
  }
};
</script>

<style scoped>
.demo {
  background-color: skyblue;
}
</style>

Vue中的组件自定义事件

绑定事件监听

使用v-on指令绑定自定义事件监听:

<template>
    <!-- 使用v-on指令绑定自定义事件demo,绑定的函数是demo函数 -->
    <Header v-on:demo="demo"></Header>
</template>

使用ref绑定自定义事件监听:

<template>
 <Header ref="demo"></Header>
</template>

<script>
export default {
    name:'header',
    mounted(){
        //绑定自定义事件
        this.$refs.demo.$on('demo',this.demo)
    },
    methods:{
        demo(){

        }
    }
}    
</script>

触发事件

在绑定自定义事件监听的组件实例对象上使用this.$emit触发事件:

<script>
export default {
  name'Student',
  methods: {
    sendStudentName () {
      console.log(this);
      //触发Student组件实例身上的demo事件
      this.$emit('demo''xxx');
    }
  }
};
</script>

解绑事件监听

在绑定自定义事件监听的组件实例对象上使用this.$off解绑事件监听:

解绑单个事件监听:

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18,
      num0
    };
  },
  methods: {
    unbind () {
      //解绑Student组件实例身上的demo事件
      this.$off('demo'); //解绑一个自定义事件
    }
  }
};
</script>

解绑多个事件监听:

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18,
      num0
    };
  },
  methods: {
    unbind () {
      //解绑Student组件实例身上的demo事件
      this.$off(['demo''demo1']); //解绑多个自定义事件
    }
  }
};
</script>

解绑所有的自定义事件:

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18,
      num0
    };
  },
  methods: {
    unbind () {
      //解绑Student组件实例身上的demo事件
      this.$off();//解绑所有的自定义事件
    }
  }
};
</script>

应用示例

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- School.vue
|   |   `-- Student.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

<template>
  <div class="app">
    <h1>{{ msg }}</h1>
    <!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
    <School :getSchoolName="getSchoolName"/>

    <!-- 通过父组件给子组件绑定一个自定义事件:子给父传递数据(第一种写法,使用@或v-on) -->
    <!-- <Student v-on:demo="getStudentName"/> -->

    <!-- 通过父组件给子组件绑定一个自定义事件:子给父传递数据(第二种写法,使用ref) -->
    <Student ref="student"/>
  </div>
</template>

<script>

import Student from './components/Student';
import School from './components/School';

export default {
  name'App',
  data () {
    return { msg'你好啊' };
  },
  mounted () {
    //绑定自定义事件
    this.$refs.student.$on('demo'this.getStudentName);
  },
  methods: {
    getSchoolName (name) {
      console.log('App收到了学校的名称:', name);
    },
    getStudentName (name) {
      console.log('App收到了学生的姓名:', name);
    }
  },
  components: {
    Student,
    School
  }
};
</script>

<style lang="less">
.app {
  background-color: gray;
  padding5px;
}
</style>

School.vue

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <button @click="sendSchoolName">将学校名称发送给App</button>
  </div>
</template>

<script>
export default {
  name'School',
  props: ['getSchoolName'],
  methods: {
    sendSchoolName () {
      this.getSchoolName(this.name);
    }
  },
  data () {
    return {
      name'江苏师范大学',
      address'江苏省徐州市泉山区'
    };
  }
};
</script>

<style scoped>
.school {
  background-color: skyblue;
  padding5px;
}
</style>

Student.vue

<template>
  <div class="student">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
    <button @click="sendStudentName">将学生名称发送给App</button>
  </div>
</template>

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18
    };
  },
  methods: {
    sendStudentName () {
      console.log(this);
      //触发Student组件实例身上的demo事件
      this.$emit('demo'this.name);
    }
  }
};
</script>

<style scoped>
.student {
  background-color: pink;
  padding5px;
  margin-top30px;
}
</style>

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- School.vue
|   |   `-- Student.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

<template>
  <div class="app">
    <h1>{{ msg }}</h1>
    <!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
    <School :getSchoolName="getSchoolName"/>

    <!-- 通过父组件给子组件绑定一个自定义事件:子给父传递数据(第一种写法,使用@或v-on) -->
    <!-- <Student v-on:demo="getStudentName"/> -->

    <!-- 通过父组件给子组件绑定一个自定义事件:子给父传递数据(第二种写法,使用ref) -->
    <Student ref="student" @click.native="show"/>
  </div>
</template>

<script>

import Student from './components/Student';
import School from './components/School';

export default {
  name'App',
  data () {
    return { msg'你好啊' };
  },
  mounted () {
    //绑定自定义事件
    this.$refs.student.$on('demo'this.getStudentName);
    this.$refs.student.$on('demo1'this.demo1);
  },
  methods: {
    getSchoolName (name) {
      console.log('App收到了学校的名称:', name);
    },
    getStudentName (name) {
      console.log('App收到了学生的姓名:', name);
    },
    demo1 () {
      console.log('demo1事件被触发了');
    },
    show () {
      alert(123);
    }
  },
  components: {
    Student,
    School
  }
};
</script>

<style lang="less">
.app {
  background-color: gray;
  padding5px;
}
</style>

School.vue

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <button @click="sendSchoolName">将学校名称发送给App</button>
  </div>
</template>

<script>
export default {
  name'School',
  props: ['getSchoolName'],
  methods: {
    sendSchoolName () {
      this.getSchoolName(this.name);
    }
  },
  data () {
    return {
      name'江苏师范大学',
      address'江苏省徐州市泉山区'
    };
  }
};
</script>

<style scoped>
.school {
  background-color: skyblue;
  padding5px;
}
</style>

Student.vue

<template>
  <div class="student">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
    <h2>求和为:{{ num }}</h2>
    <button @click="add">点我+1</button>
    <button @click="sendStudentName">将学生名称发送给App</button>
    <button @click="unbind">解绑自定义事件</button>
    <button @click="dead">销毁当前Student组件的实例(VC)</button>
  </div>
</template>

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18,
      num0
    };
  },
  methods: {
    add () {
      console.log('add回调被调用了');
      this.num++;
    },
    sendStudentName () {
      //触发Student组件实例身上的demo事件
      this.$emit('demo'this.name);
      // this.$emit('demo1');
    },
    unbind () {
      //解绑Student组件实例身上的demo事件
      this.$off('demo'); //解绑一个自定义事件
      // this.$off(['demo', 'demo1']); //解绑多个自定义事件
      // this.$off();//解绑所有的自定义事件
    },
    dead () {
      //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全部不奏效
      this.$destroy();
    }
  }
};
</script>

<style scoped>
.student {
  background-color: pink;
  padding5px;
  margin-top30px;
}
</style>

总结

组件的自定义事件是一种组件间通信的方式,适用于:子组件 => 父组件

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

绑定自定义事件:

  • ① 在父组件中:<Demo @demo="test"/><Demo v-on:demo="test">
  • ② 在父组件中:
<template>
 <Demo ref="demo"/>
</template>

<script>
 export default {
        
        mounted(){
            this.$refs.demo.$on('demo',this.test);
        }
        
    }
</script>
  • 触发自定义事件:this.$emit('demo',数据);

  • 解绑自定义事件:this.$off('demo');

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

  • 注意:通过this.$refs.xxx.$on('demo',回调函数)绑定自定义事件时,回调要么配置在methods中,要么使用箭头函数,否则this会指向触发事件的组件。

全局事件总线(GlobalEventBus)

概述

全局事件总线是一种组件间的通信方式,适用于任意组件间通信。

安装全局事件总线:


使用事件总线:

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

<script>
export default {
  ...
  mounted () {
    this.$bus.$on('demo', (data) => {
      console.log('School组件接收到的数据:', data);
    });
  },
  beforeDestroy () {
    this.$bus.$off('demo');
  }
};
</script>

②提供数据:

this.$bus.$emit('xxx',数据);

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

应用示例

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- School.vue
|   |   `-- Student.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
  beforeCreate () {
    Vue.prototype.$bus = this//安装全局事件总线
  }
});

App.vue

<template>
  <div class="app">
    <h1>{{ msg }}</h1>
    <School/>
    <Student/>
  </div>
</template>

<script>

import Student from './components/Student';
import School from './components/School';

export default {
  name'App',
  data () {
    return { msg'你好啊' };
  },
  components: {
    Student,
    School
  }
};
</script>

<style lang="less">
.app {
  background-color: gray;
  padding5px;
}
</style>

Student.vue

<template>
  <div class="student">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
    <button @click="sendStudentName">将学生姓名交给School组件</button>
  </div>
</template>

<script>
export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18,
    };
  },
  methods: {
    sendStudentName () {
      this.$bus.$emit('demo'this.name);
    }
  }
};
</script>

<style scoped>
.student {
  background-color: pink;
  padding5px;
  margin-top30px;
}
</style>

School.vue

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
  </div>
</template>

<script>
export default {
  name'School',
  data () {
    return {
      name'江苏师范大学',
      address'江苏省徐州市泉山区'
    };
  },
  mounted () {
    this.$bus.$on('demo', (data) => {
      console.log('School组件接收到的数据:', data);
    });
  },
  beforeDestroy () {
    this.$bus.$off('demo');
  }
};
</script>

<style scoped>
.school {
  background-color: skyblue;
  padding5px;
}
</style>

消息订阅和发布

概述

使用方式和全局事件总线类似。

包含以下的操作:

  • ① 订阅消息:对应绑定事件监听。
  • ② 发布消息:分发事件。
  • ③ 取消消息订阅:解绑事件监听。

需要引入一个消息订阅和发布的第三方库:pubsub-js

使用

在线文档:https://github.com/mroderick/PubSubJS

下载:

yarn add pubsub-js

相关语法:

  • ① 引入:
import PubSub from 'pubsub-js'
  • ② 订阅消息:
PubSub.subscribe(‘msgName’, functon(msgName, data){ })
  • ③ 发布消息,触发订阅的回调函数:
PubSub.publish(‘msgName’, data)

④ 取消消息的订阅:

PubSub.unsubscribe(token)

应用示例

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- School.vue
|   |   `-- Student.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

安装pubsub-js

yarn add pubsub-js

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App)
});

App.vue

<template>
  <div class="app">
    <h1>{{ msg }}</h1>
    <School/>
    <Student/>
  </div>
</template>

<script>

import Student from './components/Student';
import School from './components/School';

export default {
  name'App',
  data () {
    return { msg'你好啊' };
  },
  components: {
    Student,
    School
  }
};
</script>

<style lang="less">
.app {
  background-color: gray;
  padding5px;
}
</style>

School.vue

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
  </div>
</template>

<script>
import PubSub from 'pubsub-js';

export default {
  name'School',
  data () {
    return {
      name'江苏师范大学',
      address'江苏省徐州市泉山区'
    };
  },
  mounted () {
    this.token = PubSub.subscribe('demo', (msgName, data) => {
      console.log('School组件接收到的数据:', msgName, data);
    });
  },
  beforeDestroy () {
    PubSub.unsubscribe(this.token);
  }
};
</script>

<style scoped>
.school {
  background-color: skyblue;
  padding5px;
}
</style>

Student.vue

<template>
  <div class="student">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
    <button @click="sendStudentName">将学生姓名交给School组件</button>
  </div>
</template>

<script>
import PubSub from 'pubsub-js';

export default {
  name'Student',
  data () {
    return {
      name'筱晶哥哥',
      age18,
    };
  },
  methods: {
    sendStudentName () {
      PubSub.publish('demo'this.name);
    }
  }
};
</script>

<style scoped>
.student {
  background-color: pink;
  padding5px;
  margin-top30px;
}
</style>

过渡和动画

概述

作用:在插入、更新或移除DOM元素的时候,在合适的时候给元素添加样式类名。

Vue高级部分(一)

写法:

① 准备好样式:

  • 元素进入的样式:

    • v-enter:进入的起点。
    • v-enter-active:进入过程中。
    • v-enter-to:进入的终点。
  • 元素离开的样式:

    • v-leave:离开的重终点。
    • v-leave-active:离开过程中。
    • v-leave-to:离开的终点。

② 使用<transition></transition>包裹要过渡的元素,并配置name属性。

<transition :appear="true" name="hello">
      <h1 v-show="isShow">你好啊!</h1>
</transition>

③ 备注:如果有多个元素需要过渡,则需要使用<transition-group></transition-group>,并为每个元素指定key值。

应用示例

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Test.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App)
});

App.vue

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

<script>
import Test from './components/Test';

export default {
  name'App',
  components: {
    Test
  }
};
</script>

Test.vue

<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <transition :appear="true" name="hello">
      <h1 v-show="isShow">你好啊!</h1>
    </transition>
  </div>
</template>

<script>
export default {
  name'Test',
  data () {
    return {
      isShowtrue
    };
  }
};
</script>

<style scoped>
h1 {
  background-color: orange;
}

.hello-enter-active {
  animation: demo 1s;
}

.hello-leave-active {
  animation: demo 1s reverse;
}

@keyframes demo {
  from {
    transformtranslateX(-100%);
  }
  to {
    transformtranslateX(0px);
  }
}
</style>

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Test.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App)
});

App.vue

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

<script>
import Test from './components/Test';

export default {
  name'App',
  components: {
    Test
  }
};
</script>

Test.vue

<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <transition :appear="true" name="hello">
      <h1 v-show="isShow">你好啊!</h1>
    </transition>
  </div>
</template>

<script>
export default {
  name'Test',
  data () {
    return {
      isShowtrue
    };
  }
};
</script>

<style scoped>
h1 {
  background-color: orange;
}

/* 进入的起点和离开的终点 */
.hello-enter.hello-leave-to {
  transformtranslateX(-100%);
}

.hello-enter-active.hello-leave-active {
  transition0.5s linear;
}

/* 离开的起点和进入的终点 */
.hello-leave.hello-enter-to {
  transformtranslateX(0);
}

</style>

示例:集成第三方动画

安装第三方动画:

yarn add animate.css

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Test.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App)
});

App.vue

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

<script>
import Test from './components/Test';

export default {
  name'App',
  components: {
    Test
  }
};
</script>

Test.vue

<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <transition :appear="true" enter-active-class="animate__swing" leave-active-class="animate__backOutUp"
                name="animate__animated animate__bounce">

      <h1 v-show="isShow">你好啊!</h1>
    </transition>
  </div>
</template>

<script>
import 'animate.css';

export default {
  name'Test',
  data () {
    return {
      isShowtrue
    };
  }
};
</script>

<style scoped>
h1 {
  background-color: orange;
}
</style>

vue ajax

vue项目中常用的2个Ajax库

vue-resource

vue插件,非官方库,vue1.x使用广泛,已经弃用。

axios

通用的ajax请求库,官方推荐,vue2.x使用广泛。

2 解决开发环境Ajax跨域问题

解决开发环境Ajax跨域的问题思路

Vue高级部分(一)

① 使用Nginx

② 借助webpack的devServer。

应用示例

示例:

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

vue.config.js

module.exports = {
  //关闭语法检查
  lintOnSavefalse,
  //开启代理服务器
  devServer: {
    proxy: {
      '/api1': {
        target'http://localhost:5000',
        wstrue,        //如果要代理 websockets,配置这个参数
        securefalse,  // 如果是https接口,需要配置这个参数
        changeOrigintrue,  //用于控制请求头中的HOST值
        pathRewrite: {
          '^/api1'''
        }
      },
      '/api2': {
        target'http://localhost:5001',
        wstrue,        //如果要代理 websockets,配置这个参数
        securefalse,  // 如果是https接口,需要配置这个参数
        changeOrigintrue,  //用于控制请求头中的HOST值
        pathRewrite: {
          '^/api2'''
        }
      }
    }
  }
};

main.js

import Vue from 'vue';
import App from './App';
Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

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

<script>

import axios from 'axios';

export default {
  name'App',
  methods: {
    async getStudents () {
      try {
        const result = await axios.get('/api1/students');
        console.log(result.data);
      } catch (e) {
        console.log(e.message);
      }
    },
    async getCars () {
      try {
        const result = await axios.get('/api2/cars');
        console.log(result.data);
      } catch (e) {
        console.log(e.message);
      }
    }
  },
};
</script>

插槽slot

概述

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

注意:插槽内容是在父组件中编译后,再传递给子组件的。

分类:

  • ① 默认插槽:
<template>
<!-- 父组件 -->
 <Category>
     <div>HTML结构</div>
    </Category>
</template>
<template>
<!-- 子组件 -->
  
   <div>
          <!-- 定义插槽 -->
    <slot>插槽默认内容</slot>
   </div>
  <
</template>
  • ② 具名插槽:
<template>
<!-- 父组件 -->
 <Category>
        <template slot="center">
      <div>HTML结构</div>
        </template>
  
    </Category>
 <Category>
        <template v-slot:footer>
         <div>HTML结构</div>
      </template>
    </Category>
</template>
<template>
<!-- 子组件 -->
  <div class="category">
    <h3>{{ title }}</h3>
    <!--  定义一个插槽(等着组件的使用者进行填充)   -->
    <slot name="center"></slot>
    <slot name="footer"></slot>
  </div>
</template>
  • ③ 作用域插槽:

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

<template>
<!-- 父组件 -->
  <div class="container">
    <Category title="游戏">
      <template scope="{games}">
        <!-- 生成的是ul列表 -->
        <ul>
          <li v-for="(item,index) in games" :key="index">{{ item }}</li>
        </ul>
      </template>
    </Category>
</template>
<template>
  <div class="category">
    <h3>{{ title }}</h3>
    <slot :games="games"></slot>
  </div>
</template>

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

应用示例

示例:默认插槽

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Category.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

<template>
  <div class="container">
    <Category title="美食">
      <img src="xxx.jpg">
    </Category>
    <Category title="游戏">
      <ul>
        <li v-for="(item,index) in games" :key="index">{{ item }}</li>
      </ul>
    </Category>
    <Category title="电影">
      <video controls src="xxx.mp4"></video>
    </Category>
  </div>
</template>

<script>
import Category from './components/Category';

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

<style>
.container {
  display: flex;
  justify-content: space-around;
}

img {
  width100%;
}

video {
  width100%;
}
</style>

Category.vue

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

<script>
export default {
  name'Category',
  data () {
    return {};
  },
  props: {
    titleString
  }
};
</script>

<style scoped>
.category {
  background-color: skyblue;
  width200px;
  height300px;
}

h3 {
  text-align: center;
  background-color: orange;
}

</style>

示例:具名插槽

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Category.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

<template>
  <div class="container">
    <Category title="美食">
      <img slot="center" src="xxx.jpg">
      <a slot="footer" class="foot" href="#">更多美食</a>
    </Category>
    <Category title="游戏">
      <ul slot="center">
        <li v-for="(item,index) in games" :key="index">{{ item }}</li>
      </ul>
      <span slot="footer" class="foot">
        <a href="#">单机游戏</a>
        <a href="#">网络游戏</a>
      </span>
    </Category>
    <Category title="电影">
      <video slot="center" controls src="xxx.mp4"></video>
      <template v-slot:footer>
        <span class="foot">
          <a href="#">经典</a>
          <a href="#">热门</a>
          <a href="#">推荐</a>
        </span>
        <h4>欢迎来到影院观看</h4>
      </template>
    </Category>
  </div>
</template>

<script>
import Category from './components/Category';

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

<style>
.container.foot {
  display: flex;
  justify-content: space-around;
}

h4 {
  text-align: center;
}

img {
  width100%;
}

video {
  width100%;
}
</style>

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',
  data () {
    return {};
  },
  props: {
    titleString
  }
};
</script>

<style scoped>
.category {
  background-color: skyblue;
  width200px;
  height300px;
}

h3 {
  text-align: center;
  background-color: orange;
}

</style>

示例:作用域插槽

目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Category.vue
|   `-- main.js
|-- vue.config.js
`-- yarn.lock

main.js

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

Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
});

App.vue

<template>
  <div class="container">
    <Category title="游戏">
      <template scope="{games}">
        <ul>
          <li v-for="(item,index) in games" :key="index">{{ item }}</li>
        </ul>
      </template>
    </Category>

    <Category title="游戏">
      <template scope="{games}">
        <ol>
          <li v-for="(item,index) in games" :key="index">{{ item }}</li>
        </ol>
      </template>
    </Category>

    <Category title="游戏">
      <template slot-scope="{games}">
        <h4 v-for="(item,index) in games" :key="index">{{ item }}</h4>
      </template>
    </Category>
  </div>
</template>

<script>
import Category from './components/Category';

export default {
  name'App',
  components: {
    Category
  },
};
</script>

<style>
.container {
  display: flex;
  justify-content: space-around;
}

h4 {
  text-align: center;
}

img {
  width100%;
}

video {
  width100%;
}
</style>

Categroy.vue

<template>
  <div class="category">
    <h3>{{ title }}</h3>
    <slot :games="games"></slot>
  </div>
</template>

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

<style scoped>
.category {
  background-color: skyblue;
  width200px;
  height300px;
}

h3 {
  text-align: center;
  background-color: orange;
}

</style>

vuex

Vuex的简介

Vue是什么?

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

文档地址:https://vuex.vuejs.org/zh/

什么时候使用Vuex?

  • 多个组件依赖于同一状态。

  • 来自不同组件的行为需要变更同一状态。

  • 多个组件要共享状态。

Vuex的工作原理

Vue高级部分(一)
image-20220217164315179

Vuex核心概念和API

核心概念和API

state

  • Vuex管理的状态对象。

  • state是唯一的。

  • 示例:

const state = {count:0}

mutations

  • 值是一个对想,包含多个直接更新state的函数(也可以称为方法)。

  • 在actions中使用context.commit('方法名',数据)触发mutations中的方法。

  • mutations中方法的特点:不能写异步代码,只能单纯的操作state。

  • 示例:

const mutations ={
    INCREMENT (state, value) {
      state.count += value;
    },
}

actions

  • 值是一个对象,包含多个响应用户动作的回调函数。

  • 通过commit方法来触发mutations中对应函数的执行,间接的更新state。

  • actions中方法的特点:可以包含异步代码(定时器、Ajax等)。

  • 示例:

const actions =  { //准备actions,用于响应组件中的动作
    increment (context, value) {
      context.commit('INCREMENT', value);
    },
    decrement (context, value) {
      context.commit('DECREMENT', value);
    },
    incrementIfOdd (context, value) {
      const { count } = context.state;
      if (count % 2 !== 0) {
        context.commit('INCREMENT', value);
      }
    },
    incrementAsync (context, value) {
      setTimeout(() => {
        context.commit('INCREMENT', value);
      }, 2000);
    }
  },

getters

  • 当state中的数据需要经过加工后再使用,可以使用getters进行加工。

  • 值为一个对象,包含多个用于返回数据的函数。

  • 使用:

$store.getters.xxx
  • 示例:
const getters =  { //准备getters,用于将state中的数据进行加工
    bigCount (state) {
      return state.count * 10;
    }
 }

四个map方法的使用

  • ① mapState方法:用于帮助我们映射state中的数据为计算属性。
import { mapState } from 'vuex'
computed: {
   /* 借助mapState生成计算属性,从state中读取数据。(对象写法) */
   ...mapState({ count'count'school'school'subject'subject' })
}
import { mapState } from 'vuex'
computed: {
   /* 借助mapState生成计算属性,从state中读取数据。(数组写法) */
   ...mapState(['count''school''subject']),
}
  • ② mapGetters方法:用于帮我们映射getters中的数据为计算属性。
import { mapGetters, mapState } from 'vuex';
computed: {
    /* 借助mapGetters生成计算属性,从getters中读取数据。(对象写法) */
    ...mapGetters({bigCount:'bigCount'}),
},
import { mapGetters, mapState } from 'vuex';
computed: {
    /* 借助mapGetters生成计算属性,从getters中读取数据。(数组写法) */
    ...mapGetters(['bigCount'])
},
  • ③ mapActions方法:用于帮我们生成和actions对话的方法,即包含$storer.dispatch(xxx)的函数。
import { mapActions } from 'vuex';  
methods: {
     /* 借助mapActions调用对应的方法,方法中会调用dispatch去联系action(对象写法) */
    ...mapActions({ incrementIfOdd'incrementIfOdd'incrementAsync'incrementAsync' }),
}
import { mapActions } from 'vuex';  
methods: {
    /* 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法) */
    ...mapActions(['incrementIfOdd','incrementAsync']),
}
  • ④ mapMutations方法:用于帮我们生成和mutations对话的方法,即包含$store.commit(xxx)的函数。
import {  mapMutations } from 'vuex';
 methods: {
    /* 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法) */
    ...mapMutations({ increment'INCREMENT'decrement'DECREMENT' }),
},
import {  mapMutations } from 'vuex';
 methods: {
    /* 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法) */
    ...mapMutations([increment,decrement]),
},

注意:mapActions和mapMutations使用的时候,如果需要传递参数需要在模板绑定事件时传递好参数,否则参数就是事件对象event

模块化+命名空间

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

  • store.js:

const countAbout = {
  namespaced:true//开启命名空间
  state:{
      sum:1
  },
  actions:{},
  mutations:{},
  getters:{
   bigCount(state){
        return state.sum * 10
    }  
  }      
}

const personAbout = {
  namespaced:true//开启命名空间
  state:{},
  actions:{},
  mutations:{},
  getters:{}      
}


const store = new Vuex.Store({
    module:{
        countAbout,
        personAbout
    }
})
  • 开启命名空间后,组件中读取state数据:
//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助mapSate读取
...mapState('countAbout',['count','school','subject'])
  • 开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取
...mapGetters('countAbout',[bigCount])
  • 开启命名空间后,组件中调用dispatch:
//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions
...mapActions('countAbout', { incrementIfOdd'incrementIfOdd'incrementAsync'incrementAsync' })
  • 开启命名空间后,组件中调用commit:
//方式一:自己直接调用commit
this.$store.commit('personAbout/ADD_PERSON', person);
//方式二:借助mapMutations
...mapMutations('countAbout', { increment'INCREMENT'decrement'DECREMENT' }),

安装Vuex

安装Vuex命令:

yarn add vuex

应用示例

搭建Vuex环境

  • 示例:

  • 目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Count.vue
|   |-- main.js
|   `-- vuex
|       `-- store.js
|-- vue.config.js
`-- yarn.lock
  • main.js
import Vue from 'vue';
import App from './App';
//引入store
import store from './vuex/store';
//关闭生产提示
Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
  store
});
  • App.vue
<template>
  <div>
    <Count/>
  </div>
</template>

<script>
import Count from './components/Count';

export default {
  name'App',
  components: { Count },
};
</script>
  • vuex/store.js
//该文件用于创建Vuex中最为核心的store对象
//引入Vue
import Vue from 'vue';
//引入Vuex
import Vuex from 'vuex';
//使用Vuex插件
Vue.use(Vuex);
//准备actions,用于响应组件中的动作
const actions = {};
//准备mutations,用于操作数据(state)
const mutations = {};
//准备state,用于存储数据
const state = {};

//创建store并暴露store
export default new Vuex.Store({
  state,
  actions,
  mutations,
});
  • components/Count.vue
<template>
  <div>
    <h2>当前求和为:{{ count }}</h2>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>&nbsp;
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementIfOdd">奇数再加</button>
    <button @click="incrementAsync">异步加</button>
  </div>
</template>

<script>
export default {
  name'Count',
  data () {
    return {
      n1,//用户选择的数字
      count0 //当前的和
    };
  },
  methods: {
    increment () {
      this.count += this.n;
    },
    decrement () {
      this.count -= this.n;
    },
    incrementIfOdd () {
      if (this.count % 2 === 0) {
        return;
      }
      this.count += this.n;
    },
    incrementAsync () {
      setTimeout(() => {
        this.count += this.n;
      }, 1000);
    }
  },
  mounted () {
    console.log(this);
  }
};
</script>

<style scoped>
button {
  margin-left5px;
}
</style>

vuex-求和案例

  • 示例:

  • 目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Count.vue
|   |-- main.js
|   `-- vuex
|       `-- store.js
|-- vue.config.js
`-- yarn.lock
  • main.js
import Vue from 'vue';
import App from './App';
//引入store
import store from './vuex/store';
//关闭生产提示
Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
  store
});
  • App.vue
<template>
  <div>
    <Count/>
  </div>
</template>

<script>
import Count from './components/Count';

export default {
  name'App',
  components: { Count },
};
</script>
  • vuex/store.js
//该文件用于创建Vuex中最为核心的store对象
//引入Vue
import Vue from 'vue';
//引入Vuex
import Vuex from 'vuex';
//使用Vuex插件
Vue.use(Vuex);

//创建store并暴露store
export default new Vuex.Store({
  state: { //准备state,用于存储数据
    count0
  },
  actions: { //准备actions,用于响应组件中的动作
    increment (context, value) {
      context.commit('INCREMENT', value);
    },
    decrement (context, value) {
      context.commit('DECREMENT', value);
    },
    incrementIfOdd (context, value) {
      const { count } = context.state;
      if (count % 2 !== 0) {
        context.commit('INCREMENT', value);
      }
    },
    incrementAsync (context, value) {
      setTimeout(() => {
        context.commit('INCREMENT', value);
      }, 2000);
    }
  },
  mutations: {  //准备mutations,用于操作数据(state)
    INCREMENT (state, value) {
      state.count += value;
    },
    DECREMENT (state, value) {
      state.count -= value;
    }
  },
});
  • Components/Count.vue
<template>
  <div>
    <h2>当前求和为:{{ $store.state.count }}</h2>
    <select v-model.number="num">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>&nbsp;
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementIfOdd">奇数再加</button>
    <button @click="incrementAsync">异步加</button>
  </div>
</template>

<script>
export default {
  name'Count',
  data () {
    return {
      num1,//用户选择的数字
    };
  },
  methods: {
    increment () {
      this.$store.dispatch('increment'this.num);
    },
    decrement () {
      this.$store.dispatch('decrement'this.num);
    },
    incrementIfOdd () {
      this.$store.dispatch('incrementIfOdd'this.num);
    },
    incrementAsync () {
      this.$store.dispatch('incrementAsync'this.num);
    }
  },
  mounted () {
    console.log('Count'this);
  }
};
</script>

<style scoped>
button {
  margin-left5px;
}
</style>

vuex-求和案例-getters

  • 示例:

  • 目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Count.vue
|   |-- main.js
|   `-- vuex
|       `-- store.js
|-- vue.config.js
`-- yarn.lock
  • main.js
import Vue from 'vue';
import App from './App';
//引入store
import store from './vuex/store';
//关闭生产提示
Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
  store
});
  • App.vue
<template>
  <div>
    <Count/>
  </div>
</template>

<script>
import Count from './components/Count';

export default {
  name'App',
  components: { Count },
};
</script>
  • vuex.store.js
//该文件用于创建Vuex中最为核心的store对象
//引入Vue
import Vue from 'vue';
//引入Vuex
import Vuex from 'vuex';
//使用Vuex插件
Vue.use(Vuex);

//创建store并暴露store
export default new Vuex.Store({
  state: { //准备state,用于存储数据
    count0
  },
  actions: { //准备actions,用于响应组件中的动作
    increment (context, value) {
      context.commit('INCREMENT', value);
    },
    decrement (context, value) {
      context.commit('DECREMENT', value);
    },
    incrementIfOdd (context, value) {
      const { count } = context.state;
      if (count % 2 !== 0) {
        context.commit('INCREMENT', value);
      }
    },
    incrementAsync (context, value) {
      setTimeout(() => {
        context.commit('INCREMENT', value);
      }, 2000);
    }
  },
  mutations: {  //准备mutations,用于操作数据(state)
    INCREMENT (state, value) {
      state.count += value;
    },
    DECREMENT (state, value) {
      state.count -= value;
    }
  },
  getters: { //准备getters,用于将state中的数据进行加工
    bigCount (state) {
      return state.count * 10;
    }
  }
});
  • components/Count.vue
<template>
  <div>
    <h2>当前求和为:{{ $store.state.count }}</h2>
    <h2>当前求和放大10倍后为:{{ $store.getters.bigCount }}</h2>
    <select v-model.number="num">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>&nbsp;
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementIfOdd">奇数再加</button>
    <button @click="incrementAsync">异步加</button>
  </div>
</template>

<script>
export default {
  name'Count',
  data () {
    return {
      num1,//用户选择的数字
    };
  },
  methods: {
    increment () {
      this.$store.dispatch('increment'this.num);
    },
    decrement () {
      this.$store.dispatch('decrement'this.num);
    },
    incrementIfOdd () {
      this.$store.dispatch('incrementIfOdd'this.num);
    },
    incrementAsync () {
      this.$store.dispatch('incrementAsync'this.num);
    }
  },
  mounted () {
    console.log('Count'this);
  }
};
</script>

<style scoped>
button {
  margin-left5px;
}
</style>

vuex-求和案例-mapState和mapGetters

  • 示例:

  • 目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Count.vue
|   |-- main.js
|   `-- vuex
|       `-- store.js
|-- vue.config.js
`-- yarn.lock
  • main.js
import Vue from 'vue';
import App from './App';
//引入store
import store from './vuex/store';
//关闭生产提示
Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
  store
});
  • App.vue
<template>
  <div>
    <Count/>
  </div>
</template>

<script>
import Count from './components/Count';

export default {
  name'App',
  components: { Count },
};
</script>
  • vuex/store.js
//该文件用于创建Vuex中最为核心的store对象
//引入Vue
import Vue from 'vue';
//引入Vuex
import Vuex from 'vuex';
//使用Vuex插件
Vue.use(Vuex);

//创建store并暴露store
export default new Vuex.Store({
  state: { //准备state,用于存储数据
    count0,
    school'江苏师范大学',
    subject'前端'
  },
  actions: { //准备actions,用于响应组件中的动作
    increment (context, value) {
      context.commit('INCREMENT', value);
    },
    decrement (context, value) {
      context.commit('DECREMENT', value);
    },
    incrementIfOdd (context, value) {
      const { count } = context.state;
      if (count % 2 !== 0) {
        context.commit('INCREMENT', value);
      }
    },
    incrementAsync (context, value) {
      setTimeout(() => {
        context.commit('INCREMENT', value);
      }, 2000);
    }
  },
  mutations: {  //准备mutations,用于操作数据(state)
    INCREMENT (state, value) {
      state.count += value;
    },
    DECREMENT (state, value) {
      state.count -= value;
    }
  },
  getters: { //准备getters,用于将state中的数据进行加工
    bigCount (state) {
      return state.count * 10;
    }
  }
});
  • components/Count.vue
<template>
  <div>
    <h2>当前求和为:{{ count }}</h2>
    <h2>当前求和放大10倍后为:{{ bigCount }}</h2>
    <h2>学校名称:{{ school }}</h2>
    <h2>学科:{{ subject }}</h2>
    <select v-model.number="num">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>&nbsp;
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementIfOdd">奇数再加</button>
    <button @click="incrementAsync">异步加</button>
  </div>
</template>

<script>
import { mapGetters, mapState } from 'vuex';

export default {
  name'Count',
  data () {
    return {
      num1,//用户选择的数字
    };
  },
  computed: {
    /* 靠程序员自己去写计算属性 */
    /* count () {
       return this.$store.state.count;
     },
     school () {
       return this.$store.state.school;
     },
     subject () {
       return this.$store.state.subject;
     },*/

    /* 借助mapState生成计算属性,从state中读取数据。(对象写法) */
    // ...mapState({ count: 'count', school: 'school', subject: 'subject' }),
    /* 借助mapState生成计算属性,从state中读取数据。(数组写法) */
    ...mapState(['count''school''subject']),
    // bigCount () {
    //   return this.$store.getters.bigCount;
    // },
    /* 借助mapGetters生成计算属性,从getters中读取数据。(对象写法) */
    // ...mapGetters({bigCount:'bigCount'}),
    /* 借助mapGetters生成计算属性,从getters中读取数据。(数组写法) */
    ...mapGetters(['bigCount'])
  },
  methods: {
    increment () {
      this.$store.dispatch('increment'this.num);
    },
    decrement () {
      this.$store.dispatch('decrement'this.num);
    },
    incrementIfOdd () {
      this.$store.dispatch('incrementIfOdd'this.num);
    },
    incrementAsync () {
      this.$store.dispatch('incrementAsync'this.num);
    }
  },
  mounted () {
    console.log('Count', mapState({
      count'count',
      school'school',
      subject'subject'
    }));
  }
};
</script>

<style scoped>
button {
  margin-left5px;
}
</style>

vue-求和案例-mapActions和mapMutations

  • 示例:

  • 目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- Count.vue
|   |-- main.js
|   `-- vuex
|       `-- store.js
|-- vue.config.js
`-- yarn.lock
  • main.js
import Vue from 'vue';
import App from './App';
//引入store
import store from './vuex/store';
//关闭生产提示
Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
  store
});
  • App.vue
<template>
  <div>
    <Count/>
  </div>
</template>

<script>
import Count from './components/Count';

export default {
  name'App',
  components: { Count },
};
</script>
  • vuex/store.js
//该文件用于创建Vuex中最为核心的store对象
//引入Vue
import Vue from 'vue';
//引入Vuex
import Vuex from 'vuex';
//使用Vuex插件
Vue.use(Vuex);

//创建store并暴露store
export default new Vuex.Store({
  state: { //准备state,用于存储数据
    count0,
    school'江苏师范大学',
    subject'前端'
  },
  actions: { //准备actions,用于响应组件中的动作
    incrementIfOdd (context, value) {
      const { count } = context.state;
      if (count % 2 !== 0) {
        context.commit('INCREMENT', value);
      }
    },
    incrementAsync (context, value) {
      setTimeout(() => {
        context.commit('INCREMENT', value);
      }, 2000);
    }
  },
  mutations: {  //准备mutations,用于操作数据(state)
    INCREMENT (state, value) {
      state.count += value;
    },
    DECREMENT (state, value) {
      state.count -= value;
    }
  },
  getters: { //准备getters,用于将state中的数据进行加工
    bigCount (state) {
      return state.count * 10;
    }
  }
});
  • components/Count.vue
<template>
  <div>
    <h2>当前求和为:{{ count }}</h2>
    <h2>当前求和放大10倍后为:{{ bigCount }}</h2>
    <h2>学校名称:{{ school }}</h2>
    <h2>学科:{{ subject }}</h2>
    <select v-model.number="num">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>&nbsp;
    <button @click="increment(num)">+</button>
    <button @click="decrement(num)">-</button>
    <button @click="incrementIfOdd(num)">奇数再加</button>
    <button @click="incrementAsync(num)">异步加</button>
  </div>
</template>

<script>
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex';

export default {
  name'Count',
  data () {
    return {
      num1,//用户选择的数字
    };
  },
  computed: {
    /* 借助mapState生成计算属性,从state中读取数据。(对象写法) */
    // ...mapState({ count: 'count', school: 'school', subject: 'subject' }),
    /* 借助mapState生成计算属性,从state中读取数据。(数组写法) */
    ...mapState(['count''school''subject']),
    /* 借助mapGetters生成计算属性,从getters中读取数据。(对象写法) */
    // ...mapGetters({bigCount:'bigCount'}),
    /* 借助mapGetters生成计算属性,从getters中读取数据。(数组写法) */
    ...mapGetters(['bigCount'])
  },
  methods: {
    /*
    increment () {
      this.$store.commit('INCREMENT', this.num);
    },
    decrement () {
      this.$store.commit('DECREMENT', this.num);
    },
    */

    /* 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法) */
    ...mapMutations({ increment'INCREMENT'decrement'DECREMENT' }),
    /* 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法) */
    // ...mapMutations([increment,decrement]),
    /*
    incrementIfOdd () {
      this.$store.dispatch('incrementIfOdd', this.num);
    },
    incrementAsync () {
      this.$store.dispatch('incrementAsync', this.num);
    },
    */

    /* 借助mapActions调用对应的方法,方法中会调用dispatch去联系action(对象写法) */
    ...mapActions({ incrementIfOdd'incrementIfOdd'incrementAsync'incrementAsync' }),
    /* 借助mapActions调用对应的方法,方法中会调用dispatch去联系action(数组写法) */
    // ...mapActions(['incrementIfOdd','incrementAsync'])
  },
  mounted () {
    mapState({ count'' });
  }
};
</script>

<style scoped>
button {
  margin-left5px;
}
</style>

vuex-求和案例-多组件共享

  • 示例:

  • 目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- Count.vue
|   |   `-- Person.vue
|   |-- main.js
|   `-- vuex
|       `-- store.js
|-- vue.config.js
`-- yarn.lock
  • main.js
import Vue from 'vue';
import App from './App';
//引入store
import store from './vuex/store';
//关闭生产提示
Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
  store
});
  • 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 },
};
</script>
  • vuex/store.js
//该文件用于创建Vuex中最为核心的store对象
//引入Vue
import Vue from 'vue';
//引入Vuex
import Vuex from 'vuex';
//使用Vuex插件
Vue.use(Vuex);

//创建store并暴露store
export default new Vuex.Store({
  state: { //准备state,用于存储数据
    count0,
    school'江苏师范大学',
    subject'前端',
    personList: [
      { id'001'name'筱晶哥哥' }
    ]
  },
  actions: { //准备actions,用于响应组件中的动作
    incrementIfOdd (context, value) {
      const { count } = context.state;
      if (count % 2 !== 0) {
        context.commit('INCREMENT', value);
      }
    },
    incrementAsync (context, value) {
      setTimeout(() => {
        context.commit('INCREMENT', value);
      }, 2000);
    }
  },
  mutations: {  //准备mutations,用于操作数据(state)
    INCREMENT (state, value) {
      state.count += value;
    },
    DECREMENT (state, value) {
      state.count -= value;
    },
    ADD_PERSON (state, value) {
      state.personList.unshift(value);
    }
  },
  getters: { //准备getters,用于将state中的数据进行加工
    bigCount (state) {
      return state.count * 10;
    }
  }
});
  • components/Count.vue
<template>
  <div>
    <h2>当前求和为:{{ count }}</h2>
    <h2>当前求和放大10倍后为:{{ bigCount }}</h2>
    <h2>学校名称:{{ school }}</h2>
    <h2>学科:{{ subject }}</h2>
    <h3 style="color: red">Person组件的总人数是:{{ personList.length }}</h3>
    <select v-model.number="num">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>&nbsp;
    <button @click="increment(num)">+</button>
    <button @click="decrement(num)">-</button>
    <button @click="incrementIfOdd(num)">奇数再加</button>
    <button @click="incrementAsync(num)">异步加</button>
  </div>
</template>

<script>
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex';

export default {
  name'Count',
  data () {
    return {
      num1,//用户选择的数字
    };
  },
  computed: {
    ...mapState(['count''school''subject''personList']),
    ...mapGetters(['bigCount'])
  },
  methods: {

    /* 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法) */
    ...mapMutations({ increment'INCREMENT'decrement'DECREMENT' }),

    /* 借助mapActions调用对应的方法,方法中会调用dispatch去联系action(对象写法) */
    ...mapActions({ incrementIfOdd'incrementIfOdd'incrementAsync'incrementAsync' }),
  },
  mounted () {
    mapState({ count'' });
  }
};
</script>

<style scoped>
button {
  margin-left5px;
}
</style>
  • components/Person.vue
<template>
  <div>
    <h1>人员列表</h1>
    <h3 style="color: skyblue">Count组件的求和是:{{ count }}</h3>
    <input v-model.trim="name" placeholder="请输入名字" type="text">
    <button @click="add">添加</button>
    <ul>
      <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;
    },
    count () {
      return this.$store.state.count;
    }
  },
  methods: {
    add () {
      let person = { id: nanoid(), namethis.name };
      this.$store.commit('ADD_PERSON', person);
      this.name = '';
    }
  }
};
</script>

<style scoped>

</style>

vuex-求和案例-namespaced

  • 示例:

  • 目录结构:

|-- README.md
|-- babel.config.js
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   |-- Count.vue
|   |   `-- Person.vue
|   |-- main.js
|   `-- vuex
|       |-- count.js
|       |-- person.js
|       `-- store.js
|-- vue.config.js
`-- yarn.lock
  • main.js
import Vue from 'vue';
import App from './App';
//引入store
import store from './vuex/store';
//关闭生产提示
Vue.config.productionTip = false;

new Vue({
  el'#app',
  renderh => h(App),
  store
});
  • 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 },
};
</script>
  • vuex/count.js
const countOptions = {
  namespacedtrue,
  state: {
    count0,
    school'江苏师范大学',
    subject'前端',
  },
  actions: {
    incrementIfOdd (context, value) {
      const { count } = context.state;
      if (count % 2 !== 0) {
        context.commit('INCREMENT', value);
      }
    },
    incrementAsync (context, value) {
      setTimeout(() => {
        context.commit('INCREMENT', value);
      }, 2000);
    }
  },
  mutations: {
    INCREMENT (state, value) {
      state.count += value;
    },
    DECREMENT (state, value) {
      state.count -= value;
    },
  },
  getters: {
    bigCount (state) {
      return state.count * 10;
    }
  }
};

export default countOptions;
  • vuex/person.js
const personOptions = {
  namespacedtrue,
  state: {
    personList: [
      { id'001'name'筱晶哥哥' }
    ]
  },
  actions: {
    addPersonWang (context, value) {
      if (value.name.indexOf('王') === 0) {
        context.commit('ADD_PERSON', value);
      } else {
        alert('添加的姓名不是以王开头');
      }
    }
  },
  mutations: {
    ADD_PERSON (state, value) {
      state.personList.unshift(value);
    }
  },
  getters: {
    firstPersonName (state) {
      return state.personList[0].name;
    }
  }
};

export default personOptions;
  • vuex/store.js
//该文件用于创建Vuex中最为核心的store对象
//引入Vue
import Vue from 'vue';
//引入Vuex
import Vuex from 'vuex';
//求和相关配置
import countOptions from './count';
//人员管理相关配置
import personOptions from './person';
//使用Vuex插件
Vue.use(Vuex);

//创建store并暴露store
export default new Vuex.Store({
  modules: {
    countAbout: countOptions,
    personAbout: personOptions
  }
});
  • components/Count.vue
<template>
  <div>
    <h2>当前求和为:{{ count }}</h2>
    <h2>当前求和放大10倍后为:{{ bigCount }}</h2>
    <h2>学校名称:{{ school }}</h2>
    <h2>学科:{{ subject }}</h2>
    <h3 style="color: red">Person组件的总人数是:{{ personList.length }}</h3>
    <select v-model.number="num">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>&nbsp;
    <button @click="increment(num)">+</button>
    <button @click="decrement(num)">-</button>
    <button @click="incrementIfOdd(num)">奇数再加</button>
    <button @click="incrementAsync(num)">异步加</button>
  </div>
</template>

<script>
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex';

export default {
  name'Count',
  data () {
    return {
      num1,//用户选择的数字
    };
  },
  computed: {
    ...mapState('countAbout', ['count''school''subject']),
    ...mapState('personAbout', ['personList']),
    ...mapGetters('countAbout', ['bigCount'])
  },
  methods: {

    /* 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法) */
    ...mapMutations('countAbout', { increment'INCREMENT'decrement'DECREMENT' }),

    /* 借助mapActions调用对应的方法,方法中会调用dispatch去联系action(对象写法) */
    ...mapActions('countAbout', { incrementIfOdd'incrementIfOdd'incrementAsync'incrementAsync' }),
  },
  mounted () {
    console.log(this);
  }
};
</script>

<style scoped>
button {
  margin-left5px;
}
</style>
  • components/Person.vue
<template>
  <div>
    <h1>人员列表</h1>
    <h3 style="color: skyblue">Count组件的求和是:{{ count }}</h3>
    <h3>列表中第一个人的名字是:{{ firstPersonName }}</h3>
    <input v-model.trim="name" placeholder="请输入名字" type="text">
    <button @click="add">添加</button>
    <button @click="addPersonWang">添加一个姓王的人</button>
    <ul>
      <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;
    },
    count () {
      return this.$store.state.countAbout.count;
    },
    firstPersonName () {
      return this.$store.getters['personAbout/firstPersonName'];
    }
  },
  methods: {
    add () {
      let person = { id: nanoid(), namethis.name };
      this.$store.commit('personAbout/ADD_PERSON', person);
      this.name = '';
    },
    addPersonWang () {
      let person = { id: nanoid(), namethis.name };
      this.$store.dispatch('personAbout/addPersonWang', person);
      this.name = '';
    }
  },
  mounted () {
    console.log(this.$store);
  }
};
</script>

<style scoped>

</style>


原文始发于微信公众号(程序员阿晶):Vue高级部分(一)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/19855.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!