vue2

260 阅读8分钟

vue基础

一、vue的基本认识

1652445681762.png

二、vue的指令

1.插值表达式

语法
<template>
  <div>
    <ul>
    <li>{{value}}</li>  语法为{{变量}},变量要在data函数返回的对象里声明
  </ul>
  </div>
</template>

<script>
export default {
  data () {
    return {
      value:'张三'
    }
  }
};
</script>

<style>
</style>

2.v-bind

v-bind可以将变量和标签的属性值绑定在一起

语法
<template>
  <div>
   <a v-bind:href="link">百度</a> v-bind:属性名="变量"
   <a :href="link">百度</a> v-bind简写 => :属性名="变量"
  </div>
</template>

<script>
export default {
  data () {
    return {
      link:'https://www.baidu.com'
    }
  }
};
</script>

<style>
</style>

3.v-on

给元素绑定事件

语法
<template>
  <div>
    <a href="https://www.baidu.com" @click="fn1">跳转</a>
    <a href="https://www.baidu.com" @click="fn2($event,10)">跳转</a>
  </div>
</template>

<script>
export default {
    // 方法写在methods对象里
  methods: {
    fn1(e) {
      e.preventDefault(); // 当函数未携带参数时,默认的参数就是e
    },
    fn2(e,num) { // 当函数有多个参数时,e和$event位置要对应才能阻止默认行为
    console.log(num);
    e.preventDefault(); // 和$event位置对应即可
  },
  }
};
</script>

<style>
</style>

v-on的修饰符

语法  @事件名.修饰符="事件函数"

<a href="https://www.baidu.com" @click.once="fn1">跳转</a>

.once表示只能触发一次,.prevent表示阻止默认行为,.stop表示阻止冒泡

4.v-model

<template>
  <div>
    用户名<input type="text" v-model="username"><br>
    密码<input type="text" v-model="password"><br>
    <button @click="login">登录</button>
  </div>
</template>

<script>
// v-model绑定后,一个变化,另一个也会发生变化,input的value和变量双向绑定
export default {
  data() {
    return {
      username:'123',
      password:''
    }
  },
  methods: {
    login() {
     console.log(this.username,this.password);
    }
  }
};
</script>

<style>
</style>

v-model修饰符

.number 表示转换成数字类型

.trim 表示去除首尾空白符

.lazy 表示当表单失去焦点时才赋值

5.v-for

<template>
  <div>
      
        对象格式
      <ul>
      <!-- value相当于属性值"张三"等 -->
      <li v-for="value in obj">{{ value }}</li>
    </ul>
      <!-- obj.key = value -->
      <li v-for="(value, key) in obj">{{ key }}:{{ value }}</li>
    </ul>

        字符串格式
    <ul>
      <li v-for="value in str">{{ value }}</li>
    </ul>
    <ul>
      <!-- 这里的index和数组下标一个道理,数字类型的index也等同 -->
      <li v-for="(value, index) in str">{{ index }}:{{ value }}</li>
    </ul>

         数字格式
    <ul>
      <!-- 数字遍历表示从1到num -->
      <li v-for="value in num">{{ value }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      obj:{
        name:"张三",
        age:198,
        sex:"男"
      },
      str:"捏麻麻地太潮啦",
      num:5
    };
  },
};
</script>

<style>
</style>

tips:当v-for不加上 :key 时,默认的是就地更新,会将新旧数据结构进行对比,在旧的dom基础上进行修改

缺点:

1652619301164.png

当用表单的输入值渲染页面时, input是临时DOM状态,在元素复用时,input里的值也是会被保留的。

通过加上:key="唯一标识",vue就会根据这个唯一标识的变化重新排列元素顺序,并且会移除 key 不存在的元素

6.v-text和v-html

<template>
  <div>
    <!-- v-text不会解析标签 -->
    <p v-text="text"></p> 在页面上显示的是<button>点击<button>的文字
    <!-- v-html可以解析标签 -->
    <p v-html="html"></p> 在页面上显示的是按钮
  </div>
</template>

<script>


export default {
  data () {
    return {
      text:'文本内容',
      html:'<button>点击</button>'
    }
  }
}
</script>

<style>

</style>

7.v-show和v-if

<template>
  <div>
      
   v-show原理是控制display:none来控制标签显示隐藏,条件为true则显示,false则隐藏
   <h1 v-show="num > 4000">4000+</h1>
   <h1 v-show="num <= 4000">4000-</h1>

      
  v-if原理是删除标签来控制标签显示隐藏,条件为true则显示(新建dom元素),false则删除(删除dom元素)   
   <h1 v-if="num > 4000">4000+</h1>
   <h1 v-if="num <= 4000">4000-</h1>
   <!-- 大部分情况下,v-show和v-if可以相互替换 -->
  </div>
</template>

<script>


export default {
  data () {
    return {
      num:4001
    }
  }
}
</script>

<style>

</style>

tips:v-else和v-else-if的使用语法和if else else if 的语法相同 , 但是注意要在同级且相邻的标签中使用

8.:class和:style

<template>

利用v-bind动态修改类名 => :class="{类名:布尔值}" true为添加类名,false为移除类名

  <div :class="{ daylight: flag }" @click="change"></div>


动态设置stlye样式 => :style="{css属性名:css属性值}" 其中,css属性名可以用小驼峰也可以用''包着

  <div :style="{ 'background-color': 'red' }" @click="change"></div>

</template>

<script>
export default {
  data() {
    return {
      flag: false,
    };
  },
};
</script>

<style>
.daylight {
  background-color: #fff;
}
</style>

三、vue的属性

1.过滤器

作用就是将一些数据的格式处理成我们想要的格式

1.在vue单文件下声明
<template>
  <div>
    <h1>{{ 9 | addZero }}</h1> 数字补零
    <h2>{{ 'hello' | toUp }}</h2> 转大写
    <h3>{{ 'hello' | reverse}}</h3> 反转,在mian.js进行全局声明
  </div>
</template>

<script>
export default {
 // 
  filters: {
    addZero(num) {
      return `${num < 10 ? "0" + num : num}`;
    },
    toUp(str) {
      return str.toUpperCase();
    }
  },
};
   
</script>

<style>
</style>




2.在main.js中进行声明,vue过滤器在main.js声明可以在别的页面使用
<script>
Vue.filter('reverse', str => str.split('').reverse().join(''))
</script>

2.计算属性

<template>
  <div>
      计算属性的语法为{{ 计算属性名 }},并且要在computed对象里进行方法声明
    <h1>{{ sum }} = {{ a }} + {{ b }}</h1>
    a<input type="number" v-model.number="a" />
    <br />
    b<input type="number" v-model.number="b" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      a: 25,
      b: 26,
    };
  },
  computed: {
    // 函数名为计算属性名,要有返回值
    sum() {
      return this.a + this.b;
    },
  },
};
</script>

<style>
</style>

优点:提高性能(笑)

3.监听器

<template>
  <div>
    <!-- 简单数据类型 -->
    <input type="text" v-model="value">
    <br>
    <!-- 复杂数据类型 -->
    <input type="text" v-model="user.name">
    <br>
    <!-- 立即执行 -->
    <input type="text" v-model.number="num">
    总价:{{sum}}
  </div>
</template>

<script>
export default {
data () {
  return {
    value:'',
    user:{
      name:'zs'
    },
    num:2,
    sum:0
  }
},
    // 监听器作为方法放在watch对象里
watch: {
    // 方法名是要监听的变量
  value(newValue,oldValue) {
    console.log('新:',newValue,'旧:',oldValue);
  },
  // 监听复杂数据类型写法
  user:{
    deep:true, // deep为true表示深监听
    handler(newVal,oldVal) { // 监听复杂数据类型的新旧值都会返回最新的值
    // tips:浏览器打印数据类型,只有当你鼠标点击展开对象时才会去赋值
      console.log(newVal,oldVal);
    }
  },
  num: {
    immediate:true, // 这里表示在打开页面的时候就立即执行一次
    handler(newVal) {
      this.sum += newVal
    }
  }
}
}
</script>

<style>

</style>

四、vue的组件

1.组件的概念

组件是可复用的new实例,一个vue文件就是一个组件。当我们所写代码重复性高,过于冗余时,可以使用组件将代码拆分,从而达到结构简洁的效果

2.组件的全局引入和局部引入

全局引入

在main.js里引入

import 组件对象 form '文件路径'
Vue.component('组件名',组件对象)

引入后所有vue文件都可以使用这个组件,作为自定义标签使用
<组件名 />

局部引入

在需要引入的文件里使用
<script>
import 组件对象 form '文件路径'
export default {
  components: { 组件对象 },
};
</script>

3.父组件向子组件传值

在父组件中
<template>
 <!-- 第一步,定义所要传递给子组件的变量,若想传递变量,则利用:自定义属性接收;若传递的是字符串,可直接在子组件标签中设置自定义属性进行接收 -->
      <div>
          <changeColor :personName="value" />
    </div>
</template>


在子组件中
<template>
  <div>
    <!-- 第三步,在子组件中直接使用 -->
    <div>{{personName}}</div>
  </div>
</template>


<script>
export default {
  // 第二步,将父组件的自定义属性名放到props数组中,注意加引号
 props: ['personName']
}
</script>

4.子组件向父组件传值

在子组件中
<script>
// 第一步,利用this.$emit()进行数据传递,第一个参数是自定义函数名,后续的参数都是你想传递的什么参数
this.$emit('delPrice',this.index,10)
</script>


在父组件中
<template>
  <div>
    <!-- 第二步,定义父组件接收数据的函数,语法 @子组件所传递的自定义函数名="处理业务代码的函数" -->
    <changeColor @delPrice="delPrice"/>
  </div>
</template>

<script>
 methods: {
    // 第三步,写业务代码
    delPrice(index, price) {
      // 业务代码
    },
  },
 </script>

五、vue的生命周期

1.什么是vue的生命周期

Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。

2.vue的四个周期

vue分为四个周期,初始化、挂载、更新、销毁

每个周期又分别有两个钩子函数

①初始化

beforeCreate() 实例创建前触发

created() 实例创建完成,但此时dom元素还未开始渲染,可以在这里发送ajax请求拿数据

②挂载

beforeMount() 会在此时去找到虚拟Dom,并将其编译成Render

mounted() 虚拟Dom已经被挂载到真实Dom上,此时我们可以获取Dom节点,$refs 在此时也是可以访问的。

③更新

beforeUpdate() 响应式数据更新的时候会被调用,beforeUpdate的阶段虚拟Dom还没更新,所以在此时依旧可以访问现有的Dom。

updated() 此时补丁已经打完了,Dom已经更新完毕,可以执行一些依赖新Dom的操作。

④销毁

beforeDestroy()  在Vue实例销毁之前被调用,在此时我们的实例还未被销毁,在这个阶段可以做销毁定时器等操作

destroyed() vue实例被销毁,绑在实例身上的属性事件等都会被销毁

六、 nextTicknextTick和refs

1.$refs

<template>
  <div>
    <refBox ref="refMe" id="box" />
  </div>
</template>

<script>
import refBox from "@/components/02 $refs的用法子组件.vue";
export default {
  components: {
    refBox
  },
  mounted () {
    
    console.log(document.querySelector('#box'));
    console.log(this.$refs.refMe);
    setTimeout(() => {
    // 类似自定义属性,给标签设置ref属性,用this.$refs.设置的属性名来获取。如果是子组件标签,this.$refs可以获取子组件的所有数据和方法
      this.$refs.refMe.msg = '父组件'
      this.$refs.refMe.sayHi()
    },1000)
  }
}
</script>

<style>

</style>

2.$nextTick

<template>
  <div>
    <button @click="del">开始搜索</button>
    <input v-if="flag" ref="ipt" type="text">
  </div>
</template>

<script>
export default {
  data () {
    return {
      flag:false
    }
  },
  methods: {
    del() {
      this.flag = !this.flag;
// this.$nextTick(回调函数) 当页面渲染完毕后,才会触发回调函数。主要用于数据更新时想立即获取最新的值
      this.$nextTick(() => {
        this.$refs.ipt.focus();
      })
    }
  }
}
</script>

<style>

</style>

七、动态切换组件

父组件内
<template>
  <div>
    <button @click="check = 'sonOne' ">子一</button>
    <button @click="check = 'sonTwo' ">子二</button>
   keep-alive包起来的子组件标签会被缓存到内存中,这样就可以避免重复创建而浪费性能,数据也会得到保存 
    <keep-alive>
  <!-- 将components作为自定义标签,给components通过v-bind添加is属性,与接收组件名的变量关联起来 -->
      <Components :is="check" /> is绑定的是那个组件名就显示哪个组件
    </keep-alive>
  </div>
</template>

<script>
import sonOne from "@/components/04 动态切换组件-子组件1.vue";
import sonTwo from "@/components/04 动态切换组件-子组件2.vue";
export default {
  data () {
    return {
      // 这里的组件名是字符串格式
      check:'sonOne'
    }
  },
  components: {
    sonOne,
    sonTwo
  }
}
</script>

<style>

</style>


子组件内
<template>
  <div>天才</div>
</template>

<script>
export default {
    created () {
   // 当父组件Components未用keep-alive标签包裹时,这里的log会在标签出现时被打印,说明Components动态切换组件是创建和销毁的过程(不加keep-alive)
        console.log('被创建啦');
    }
}
</script>

<style scoped>
div {
    height: 200px;
    display: flex;
    background-color: aqua;
    justify-content: center;
    align-items: center;
}
</style>

tips:动态切换组件用keep-alive标签包裹的话会触发自身独有且仅有的两个钩子函数(因为被keep-alive标签包裹的组件在第一次创建后会被缓存,所以就没有被创建和被销毁这个概念),activated()和deactivated()。

activated()是在组件被激活时侯触发,deactivated()是在组件失去激活状态时侯触发

八、slot插槽

1.slot匿名插槽

父组件内
<template>
  <div>
    <!-- 使用slot时,自定义标签要设置为双标签,双标签包裹的标签结构就是要传进去的标签结构 -->
    <sonC>
      <p>月初1</p>
    </sonC>
      
    <sonC>
      <button>哈哈</button>
    </sonC>
      
    <!-- 这里什么都没传给子组件,显示的就是子组件准备的默认内容 -->
    <sonC />
      
  </div>
</template>

<script>
import sonC from "@/components/05 slot组件插槽的使用-子组件.vue";
export default {
  components: {
    sonC
  }
}
</script>



子组件内
<template>
  <div>
      <div class="box">
          <!-- 用slot接收时,可以用单标签,也可以双。接收的就是父组件传过来的标签结构 -->
          <slot />


  当要设置默认值时,slot要写成双标签,里面包裹着默认内容。当父组件未传标签过来时,默认显示的是包裹的内容 
          <slot>
              <p>这是默认内容</p>
          </slot>
      </div>
  </div>
</template>

<script>
export default {

}
</script>

2.slot具名插槽

父组件内
<template>
  <div>
    <sonC>
      <!-- 如果想要在子组件中多处使用slot插槽,父组件需要在子组件自定义标签内用template双标签将自定义的标签包裹起来,通过v-slot属性和在子组件的slot上的name属性对应,就会在name对应的地方插入标签 -->
      <template #left="obj">
     <!-- 在v-slot属性上可以绑定一个变量名,这个变量是一个对象,这个对象包含子组件传过来的所有数据 -->
        <p>{{obj.data.first}}</p>
      </template>
      <template #right="obj">
        <button>{{obj.data.second}}</button>
      </template>
    </sonC>
  </div>
</template>

<script>
import sonC from "@/components/06 slot具名插槽-子组件.vue";
export default {
  components: {
    sonC,
  },
};
</script>



子组件内
<template>
  <div>
      <div class="box">
          <!-- 这里用name对应父组件插入的位置,通过v-bind给父组件传值,父组件通过v-slot来接收 -->
          <slot name="left" :data="list" />
          <hr>
          <slot name="right" :data="list" />
      </div>
  </div>
</template>

<script>
export default {
    data () {
        return {
            list:{
                first:'一月',
                second:'二月'
            }
        }
    }
}
</script>

tips:#是v-slot:的简写

九、自定义指令

局部注册方式
<template>
  <div>
    <!-- 自定义指令使用方式和vue自带的一致 -->
    <div v-bgc=" 'red' " class="box"></div>
  </div>
</template>

<script>
export default {
  // 局部注册方式
directives: {
  // 指令名 :{ 方法 }
  bgc:{
    // 在dom元素被插入后触发的函数
    inserted(el,options) { // 这里的第一个形参就是使用指令的那个dom元素,后面的形参都是自定义指令传过来的变量
      el.style.backgroundColor = options.value //传过来的变量放在形参的value里
    },
    // 当dom元素的值或模板更新时会触发这个函数
    update(参数与上述一致) {
      // 业务代码
    }
  }
}
}
</script>




全局注册方式(在mian.js里注册,注册后用法与局部注册一致)
<script>
Vue.directive("指令名",{
    "inserted" (dom) {
        // 对dom标签额外做什么功能
    }
})
</script>

tips:自定义指令是vue指令的拓展,当vue指令不能满足我们的一些需求时,就可使用自定义指令

tips:自定义指令所绑定的dom元素有两个钩子函数,一个是inserted(),在dom元素被插入后触发;一个是update(),当dom元素的值或模板更新时触发

tips:使用钩子函数时可以接收自定义指令所传过来的值,inserted(el,options),el就是所绑的dom元素,options就是自定义指令所绑的变量值,注意这个变量值是放在options.value里

十、路由

1.路由的概念

路由实际上就是可以理解为指向,就是我在页面上点击一个按钮需要跳转到对应的页面,这就是路由跳转

因为vue都是单页面应用,所有内容都在一个页面上显示,很少使用html跳转去新页面显示。而靠路由实现的页面跳转则没有真正的html跳转

路由又隐性的把组件进行了两种分类(本质并无区别),分为页面组件和复用组件。页面组件是负责路由跳转的组件,复用组件则是每个页面使用的多处都用到的组件

2.引入路由和路由的配置

在mian.js里进行引入
<script>   
// 1. 引入库
import VueRouter from 'vue-router'
    
// 2.在 Vue 安装这个库
Vue.use(VueRouter)
    
// 3 引入组件对象
import Find from '@/views/Find.vue'
import My from '@/views/My.vue'
    
// 4 配置路由表(决定在哪个路径显示哪个组件)
const routes = [
  {
    // path 路径
    path: '/find',
    // component 组件
    component: Find
  },
  {
    path: '/my',
    component: My,
    // 这个属性表示重定向,就是当页面跳转到当前组件时,强制跳转到目标路径
    redirect: '/find/ranking',
  },
  {
    // 表示匹配上述配置表之外的所有路径,常用于做404页面
    path: '*',
    component: Found404
  }
]

// 3. 创建一个实例
const router = new VueRouter({
  // 配置对象
   routes //因为这里的变量名固定写法为routes,在上面声明的配置名最好与这个相同,方便简写
})


new Vue({
  // 4. 挂载到 new Vue 根实例上
  router, // 和上面简写道理一样
  render: h => h(App),
}).$mount('#app')
</script>


在需要使用的页面组件上进行挂载
<template>
  <div>
    <!-- 路由挂载的地方 -->
    <router-view></router-view>
  </div>
</template>

tips:在mian.js引入路由中,用上了两次简写,一个是routes:routes,另一个是router:router

3.声明式导航和编程式导航

在Vue中路由跳转可以有两种方式: 声明式和编程式

声明式
<template>
 <div>
  <router-link to="/home/news">News</router-link>
  <router-link to="/home/mes">Mes</router-link> 
  <router-view></router-view>
 </div>
</template>
像上述一样,直接在组件里写router-link标签,用to属性进行页面组件的跳转,但整个页面没有进行跳转。这种就叫做声明式导航


编程式
<template>
  <div>
   <button @click="change">跳转</button>
  </div>
</template>

<script>
export default {
methods: {
    change() {
    // 利用button点击进行页面的跳转    
      this.$router.push('/part')
    }
  }
}
</script>
利用this.$router.push()方法进行页面组件的切换,同时页面也会发生跳转,这样叫做编程式导航

编程式导航的传参

在传递参数的组件内
 <!-- query传递参数写法:在路径后面拼接 ?+键值对 -->
 <router-link to="/my/?name=张三">我的音乐</router-link>
  
 <!-- params传递参数写法:在路由的路径配置里 /路径/:参数名 -->
 <router-link to="/part/114514">朋友</router-link>


在接收参数的组件内
<!-- query的传参接收参数写法: $route.query.参数名 -->
<div>params的传参:{{$route.query.name}}</div>

<!-- params的传参接收参数写法: $route.params.参数名 -->
<div>query的传参:{{$route.params.id}}</div>


注意:用params传参还需要在路由的配置表中在所要接收参数的组件路径后添加 /:id
<script>  
// params写法: /路径/:参数名
     {  path: '/part/:id',
        component: Part   }
</script>

tips:this.$router.push方法中,有着不同的写法

方式1, 直接 path 作为字符串传入 
this.$router.push('/my')

方式2 传入一个对象, 其中带有 path 属性
this.$router.push({
        path: '/my', //后面可以拼接?+键值对,query的传参本质也是拼接,所以path拼接传参后面可以不需要再加个query
        name: 'abc', //name属性, 需要在路由中预先配置
        query:{
            '参数名':值
        },
        params:{
            '参数名':值
        }
    })
其中,path和name属性二选一,query和params看传参方式也是二选一。但是使用path会忽略params

4.嵌套路由

嵌套路由是在所要嵌套的组件路径配置表里添加children对象
// routes 配置中添加
  {
    // 所要嵌套的父路由
    path: '/find',
    component: Find,
    // 嵌套子路由
    children: [
      // 依旧是 path 跟 component 的配对
      // 不要加斜杠, 因为需要改上一层拼接在一起
      {
        path: 'ranking',
        component: Ranking
      },
      {
        path: 'recommend',
        component: Recommend
      },
      {
        path: 'songlist',
        component: SongList
      },
    ]
  },
      
      
路由表配置完成后在父路由里设置嵌套子路由挂载点
<router-view></router-view>

5.导航守卫

导航守卫类似于ajax中的拦截器
// router 创建实例之后
// 可以往这个 router 路由实例添加导航守卫(路由守卫)
// 全局前置, 所有页面跳转之前都会经过
router.beforeEach((to, from, next)=>{
  // 拦住了必须放行, 默认这个函数可以接收到三个参数
  // to 要去往哪, from 从哪里来, next 放行回调函数
    
    next() //如果没有next这个函数,那么页面跳转后就会一直不显示内容,所以next回调函数是必须添加的
  }
})

十一、vant组件库

引入vant组件库

1.安装vant组件库
npm i vant@2 (使用vue几就装对应的版本)

2.在main.js中进行全局引入

全部引入(将整个组件库全部引入,会影响性能)
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);

按需引入(需要用到那个组件就引入那个,有利于提高性能)
import { Button } from 'vant';
import 'vant/lib/button/style';
Vue.use(Button);

tips:.native,事件修饰符,可以在组件上添加原生的事件

十二、vuex

1.vuex的概念

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 总而言之就是一个声明全局变量的地方,使得各个组件都可以访问这个全局变量

2.vuex的导入和使用

// 1.下载vuex  npm i vuex -S

// 2.导入
import Vuex from 'vuex'

// 3.注册
Vue.use(Vuex)

// 4.实例化vuex
const store = new Vuex.Store({
    // 配置项
})


new Vue({
    // 5.挂载
    store,
    router,
    render: h => h(App)
}).$mount('#app')

3.state和getters

在main.js中的store进行配置
<script>
 const store = new Vuex.Store({
    state: {  // 专门用来声明全局变量的地方
        count: 0,
        list: [1, 4, 5, 3, 8, 9, 2, 6, 7]
    },
    getters: { // getters声明的变量是从state派生出来的,例如filterList就是从state的list属性所派生而来的
        filterList(state) {
            return state.list.filter(value => value % 2 !== 0)
        }
    }
})
</script>

在app.vue里
<template>
  <div>
    <h1>{{ list }}</h1>
    <h1>{{ filterList }}</h1>
  </div>
</template>

<script>
// 导入辅助函数(具名导入)
import { mapState, mapGetters } from "vuex";
export default {
  computed: {
    // 读取store/getters里的属性优化写法
    // list/filterList() {
    //   return this.$store.state.count
    // }

    // 辅助函数更优化写法
    ...mapState(["list"]),
    ...mapGetters(["filterList"])
  }
};
</script>

<style>
</style>

tips:state和getters不使用辅助函数在页面上插入值写法为$store.state/getters.属性名

4.actions和mutations

在main.js中的store进行配置
<script>
 const store = new Vuex.Store({
    mutations: { // mutations是专门用来修改state中的变量的对象(属性)
        addCount(state, num) {
            state.count += num
        }
    },
    actions: {  // actions就是可以通过异步操作,调用mutations中的函数,从而修改state中的变量。
        asyncAdd(store, num) { //actions默认的参数和其他几个属性的默认参数不同,是store
        setInterval(() => {
            store.commit('addCount', num)
           }, 1000);
        }
    },
})
</script>

在app.vue里
<template>
  <div>
    <h1>{{ count }}</h1>
     <!--mutations的使用 -->
      
     <!--直接在点击事件上写业务代码-->
    <button @click="$store.commit('addCount', 10086)">增加</button><br />
     <!--声明函数去处理业务代码-->
    <button @click="sumAdd(100)">+100</button><br />
     <!--辅助函数写法--> 
    <button @click="addCount(50)">+50</button>  
    
     <!-- actions的使用(与上述说明一致) -->
    <button @click="$store.dispatch('asyncAdd', 1)">一秒后加1</button><br />
    <button @click="timeLose">一秒后加5</button><br />
    <button @click="asyncAdd(8)">一秒后加8</button>
  </div>
</template>

<script>
// 导入辅助函数(具名导入)
import { mapState,mapMutations, mapActions } from "vuex";
export default {
  computed: {
    ...mapState(["count"]),
  },
  methods: {
    // 函数写法
    sumAdd(num) {
      this.$store.commit("addCount", num);
    },
    timeLose() {
      this.$store.dispatch('asyncAdd', 5)
    },
    // 辅助函数写法
    ...mapMutations(["addCount"]),
    ...mapActions(['asyncAdd'])
  },
};
</script>

<style>
</style>

tips1:辅助函数所用数组包裹起来的变量名,必须与在该属性下声明的变量同名

tips2:mutations不用辅助函数去调用方法的写法:$store.commit('变量名', 参数值);

tips3: ations不用辅助函数去调用方法的写法:$store.dispatch('变量名', 参数值)

5.modules

<script>
const store = new Vuex.Store({
    state:{}
    getters:{ // 模块里的state属性值可以通过外层的state进行访问,因为模块看似是分开写了,但是里面的对象还是挂载在最外层的四个对象里
       access: state => state.user.access 
     }
    ... 
    modules: { // modules可以将这四个属性进行模块化,以便更好管理store实例,而且代码也显得不那么臃肿
         user:{
            namespaced: true, // 当加上锁时,就不能通过全局的store.commit/dispatch('函数名',变量)来调用模块里的mutations/actions方法。
                             
            state:{ // 相当于在外层state:{user:{access:1}}
              access: 1
             },
                             
            mutations:{
            // 这里的state是admin里的state
              cgeAccess: state => {state.access = 10}         
             },
                 
            actions:{},
                
            getters:{}
    
        }
    }
})
</script>


在app.vue的使用
<template>
  <div>
 <!--未上锁时,全局调用模块内的方法可以直接调用,因为是挂载在最外层的对象上-->
 <button @click="$store.commit('cgeAccess')">通过全局调用模块里的mut修改(未上锁)</button>
      
<!--如果上锁了,全局调用模块内的方法就必须通过$store.commit/dispatch('模块名/方法名')的方式来调用-->
<button @click="$store.commit('admin/cgeAccess')">通过全局调用模块里的mut修改(上锁)</button>
      
<button @click="changeAccess">通过辅助函数调用模块里的mutations修改</button>
      
<button @click="addCount(10)">通过辅助函数调用全局的mutations修改</button>
  </div>
</template>

<script>
import { mapGetters,mapMutations } from "vuex";
export default {
  computed: {
    ...mapGetters(["name", "access",'filterList'])
  },
  methods: {
    // 通过辅助函数调用全局的mutations修改(上锁),建议一次解构一个模块
    ...mapMutations('admin',['changeAccess']) 
    // 模块结构后并不会影响最外层函数解构
    ...mapMutations(['addCount']) 
  }
};
</script>

tips1:外层数据用外层的方法进行操作和调用,模块里的数据就用模块里的方法进行操作和调用

tips2:全局的actions对象的内置形参store与store实例有所不同,但是还是可以访问里面的变量和方法

tips3:模块上锁只是将全局调用模块里的方法上锁了,但是模块state里的数据还是一样在全局能访问

总结:vuex就是围绕着state里的数据进行操作,getters是state派生的数据,mutations作用是通过同步操作来修改state里的数据,actions作用是通过异步操作来修改state里的数据。而modules则是将state的数据进行模块化,使得每个模块通过自身的getters、mutations、actions对象去操作state数据,做到数据方便管理和结构清晰