22-12-19 西安 vue-cli(01) vue-cli脚手架、组件化编程、插槽、vue-router路由、Vuex共享数据

"对A,我还剩一张牌啦!"

"呃。。。要不起"

周六(12-03),早上刷到印度的三相神。梵天,毗湿奴,湿婆,看来很多个相关的视频介绍,结果睡觉(不管是在床上还是在桌子上)的时候,脑子里都是创造与毁灭。。。

周末(12-11),放纵得看了一天de恐怖末日小说(林叔护体),后来我知道为啥自己管不住自己了。少了一样东西,所以有了那样东西,我才能认真去完成这篇博客

周末(12-17,12-18)俩天被洗脑了,看了好几个主播的“鸭鹅杀”。脑子里总是那一句:“叼得一发言:叼的一认为.....,对是不对”


Vue CLI

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统(脚手架)

 参考官网:介绍 | Vue CLI 

CLI (@vue/cli) 是一个全局安装的 npm 包,提供了终端里的 vue 命令。它可以通过 vue create 快速搭建一个新项目,或者直接通过 vue serve 构建新想法的原型。你也可以通过 vue ui 通过一套图形化界面管理你的所有项目。

1.安装vue cli 

在这之前,确保安装了Node(推荐 v10 以上)

npm install -g @vue/cli

验证它是否安装成功

vue --version

如下:则安装成功


2.创建项目

vue create 项目名

vue create vue-xiaoyumao

选择vue2 ,回车,完成后就会在桌面生成一个文件夹


3.项目目录结构分析

使用VsCode打开

main.js 是 npm run serve 的开端

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

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

index.html

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <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">
    <!--配置网页标题-->
    <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>

4.npm run serve 启动项目

打开终端,执行 npm run serve 命令

补充:npm run build 命令会生成最纯粹的js,css,html

最后的效果

ctrl+单击网址(哪个都行),出现如下页面就欧克了

接下来换成我们自己写的组件进行渲染

新建pages目录,下面建2个.vue文件

新增Bedroom.vue

<template>
  <div>
    <p>{
    
    { msg }}</p>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Bedroom",
  data() {
    return {
      msg: "欢迎来到卧室:你要睡觉吗",
    };
  },
};
</script>

新增Kitchen.vue

<template>
  <div>
    <p>{
    
    { msg }}</p>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Kitchen",
  data() {
    return {
      msg: '欢迎来到厨房:你要做饭吗',
    };
  },
};
</script>

修改App.vue,引入我们自定义的2个组件并注册使用。如下:

<template>
  <div id="app">
    <Bedroom />
    <Kitchen />
  </div>
</template>

<script>
import Bedroom from "./pages/Bedroom.vue";
import Kitchen from "./pages/Kitchen.vue";
export default {
  name: "App",
  components: {
    Bedroom,
    Kitchen,
  },
};
</script>

页面打开后,渲染效果如下:


组件component

1、组件概念

模块化(只针对js文件)请参考:

22-08-02 西安 尚医通(02)Vscode、ES6、nodejs、npm、Bable转码器、js模块化、webpack_£小羽毛的博客-CSDN博客_尚医通 nodejs 实现

组件的定义
实现应用中局部功能代码(js,css,html)和资源的集合

从上图得出2点结论:

1.所有的组件都要听大哥vm的指挥

2.组件可以产生嵌套


2、组件嵌套

在单文件组件Bedroom.vue种引入Kitchen组件并使用:

<!--Bedroom组件内容-->
<template>
  <div>
    <p>{
    
    { msg }}</p>
    <kitchen/>
  </div>
</template>

<script>
import Kitchen from './Kitchen.vue';
export default {
  components: { Kitchen },
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Bedroom",
  data() {
    return {
      msg: "欢迎来到卧室:你要睡觉吗",
    };
  },
};
</script>


---------------------------------
<!--Kitchen组件内容-->

<template>
  <div>
    <p>{
    
    { msg }}</p>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Kitchen",
  data() {
    return {
      msg: '欢迎来到厨房:你要做饭吗',
    };
  },
};
</script>

打开vue开发者工具,直观效果"组件嵌套"

页面显示效果:

光标放在Bedroom标签:

 光标放在Kitchen标签上:

实际上在源码里:

div元素没有特定的含义,一般和CSS一同使用。用于对内容块设置样式属性浏览器会在其前后显示折行

VM非常省心,只管理app组件(约定)


3、VueComponent(简称VC)

VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。

组件本质
1、Bedroom组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
2、我们只需要写<Bedroom/>或<Bedroom></Bedroom>,Vue解析时会帮我们创建Bedroom组件的实例对象,即Vue帮我们执行的:new VueComponent(options).

3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!

关于this指向:
(1)组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是vc【VueComponent实例对象】


(2)new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是【Vue实例对象】

vm管理着vc

vm能通过el决定为哪个容器服务,vc不行,只能跟着大哥vm混

vc中,data必须是一个函数,vm中可以是data函数也可以是data对象


组件通信

1.父传子props

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

接收数据:
第一种方式(只接收):props:['name']
第二种方式(限制数据类型):props:{name:String}
第三种方式(限制类型、限制必要性、指定默认值):
props:{
    name:{
    type:String, //类型
        required:true, //必要性
        default:'JOJO' //默认值
    }
}


2.子传父this.$emit

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


3.this.$refs

应用在html标签上获取的是真实DOM元素,应用在组件标签上获取的是组件实例对象(vc)
使用方式:

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

SlOT插槽

1.默认插槽

先弄一个基本效果

创建Category.vue

<template>
  <div class="category">
    <h3>{
    
    {title}}分类</h3>
    <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>
.category {
  background-color: aqua;
  width: 200px;
  height: 300px;
}
h3{
    text-align: center;
    background-color: burlywood;
}
</style>

在App.vue中引入并使用Category.vue

<template>
  <div id="app" class="container">
    <Category title="中立阵营" :listData="zhongli" />
    <Category title="好人阵营" :listData="haoren" />
    <Category title="狼人阵营" :listData="lang" />
  </div>
</template>

<script>
import Category from "./components/Category.vue";

export default {
  name: "App",
  components: {
    Category,
  },
  data() {
    return {
      zhongli: ["呆呆鸟", "猎鹰", "秃鹫", "鸽子", "鹈鹕"],
      haoren: [
        "加拿大鹅",
        "观鸟者",
        "鹅",
        "网红",
        "星界",
        "警长",
        "正义使者",
        "模仿",
        "侦探",
        "通灵",
      ],
      lang: [
        "刺客",
        "间谍",
        "食鸟鸭",
        "专业杀手",
        "承办丧葬者",
        "身份窃贼",
        "忍者",
        "爆炸王",
      ],
    };
  },
};
</script>
<style >
.container {
  display: flex;
  justify-content: space-around;
}
</style>

页面效果:

接着我们开始引入插槽

在Category.vue中做改变,加<slot>标签

<template>
  <div class="category">
    <h3>{
    
    {title}}分类</h3>
    <!-- 定义一个插槽,等别的组件填充 -->
    <slot>我是插槽的默认值,当没有传递具体结构,我会出现</slot>
  </div>
</template>

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

<style>
.category {
  background-color: aqua;
  width: 200px;
  height: 300px;
}
h3{
    text-align: center;
    background-color: burlywood;
}
</style>

在App.vue中使用<Category>时给插槽传入具体的结构和数据

<template>
  <div id="app" class="container">
    <Category title="中立阵营" :listData="zhongli">
      <img src="./static/image/zhongli.jpg" />
    </Category>
    <Category title="好人阵营" :listData="haoren">
      <ul>
        <li v-for="(item, index) in haoren" :key="index">{
    
    { item }}</li>
      </ul>
    </Category>
    <Category title="狼人阵营" :listData="lang">
      <img src="./static/image/lang.jpg" />
    </Category>
  </div>
</template>

<script>
import Category from "./components/Category.vue";

export default {
  name: "App",
  components: {
    Category,
  },
  data() {
    return {
      zhongli: ["呆呆鸟", "猎鹰", "秃鹫", "鸽子", "鹈鹕"],
      haoren: [
        "加拿大鹅",
        "观鸟者",
        "鹅",
        "网红",
        "星界",
        "警长",
        "正义使者",
        "模仿",
        "侦探",
        "通灵",
      ],
      lang: [
        "刺客",
        "间谍",
        "食鸟鸭",
        "专业杀手",
        "承办丧葬者",
        "身份窃贼",
        "忍者",
        "爆炸王",
      ],
    };
  },
};
</script>
<style >
.container {
  display: flex;
  justify-content: space-around;
}
img{
 width:100%
}
</style>

页面效果:


2.具名插槽

在Category.vue中做改变,name属性给插槽起名字

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

在App.vue中,slot属性指定填充哪个插槽

<template>
  <div id="app" class="container">
    <Category title="中立阵营" :listData="zhongli">
      <img slot="center" src="./static/image/zhongli.jpg" />
      <a slot="footer" href="">点我查看更多</a>
    </Category>
    <Category title="好人阵营" :listData="haoren">
      <ul slot="center">
        <li v-for="(item, index) in haoren" :key="index">{
    
    { item }}</li>
      </ul>
      <div slot="footer">
        <a href="">好人阵营</a>
        <h2>欢迎加入好人阵营</h2>
      </div>
    </Category>
    <Category title="狼人阵营" :listData="lang">
      <img slot="center" src="./static/image/lang.jpg" />
      <template slot="footer">
        <a href="">狼人阵营</a>
        <h4>欢迎来到我们狼人阵营</h4>
      </template>
    </Category>
  </div>
</template>

效果如下:

如果使用template包裹,可以有新的写法

    <!-- 旧的写法如下 -->
    <Category title="狼人阵营" :listData="lang">
      <img slot="center" src="./static/image/lang.jpg" />
      <template slot="footer">
        <a href="">狼人阵营</a>
        <h4>欢迎来到我们狼人阵营</h4>
      </template>
    </Category>

新的写法:注意v-slot只能写在组件的<template>

    <Category title="狼人阵营" :listData="lang">
      <img slot="center" src="./static/image/lang.jpg" />
      <template v-slot:footer>
        <a href="">狼人阵营</a>
        <h4>欢迎来到我们狼人阵营</h4>
      </template>
    </Category>

区别:


3.作用域插槽

数据和结构不在一块

数据放在Category.vue中

<template>
  <div class="category">
    <h3>{
    
    {title}}</h3>
    <!-- 定义一个插槽,等别的组件填充 sanxianshen会传给插槽的使用者-->
    <slot :sanxianshen="sanxianshen">我是插槽的默认内容</slot>
  </div>
</template>

<script>
export default {
  name: "Category",
  props:['title'],
  data(){
    return{
     sanxianshen: ["大天湿婆", "梵天", "毗湿奴"]
    }
  }
};
</script>

<style>
.category {
  background-color: aqua;
  width: 200px;
  height: 300px;
}
h3{
    text-align: center;
    background-color: burlywood;
}
</style>

在App.vue中接收到插槽传上来的数据。使用template包裹并且使用scope属性

<template>
  <div id="app" class="container">
    <Category title="印度三相神">
      <!-- 必须要用template包裹才能拿到插槽给的数据 -->
      <template scope="India">
        {
    
    {India}}
      </template>
      </Category>
  </div>
</template>

<script>
import Category from "./components/Category.vue";

export default {
  name: "App",
  components: {
    Category,
  },
  data() {
    return {}
  },
};
</script>
<style >
.container {
  display: flex;
  justify-content: space-around;
}
img {
  width: 100%;
}
</style>

页面效果:

 在App.vue中展示数据的时候,使用不同的样式展示(无序列表,有序列表,p标签) 

<template>
  <div id="app" class="container">
    <Category title="印度三相神">
      <!-- 必须要用template包裹才能拿到插槽给的数据 -->
      <template scope="India">
        <ul>
          <li v-for="(item, index) in India.sanxianshen" :key="index">{
    
    { item }}</li>
        </ul>
      </template>
    </Category>
    <Category title="印度三相神">
      <template scope="India">
        <ol>
          <li v-for="(item, index) in India.sanxianshen" :key="index">{
    
    { item }}</li>
        </ol>
      </template>
    </Category>
    <Category title="印度三相神">
      <template scope="India">
        <p v-for="(item, index) in India.sanxianshen" :key="index">{
    
    { item }}</p>
      </template>
    </Category>
  </div>
</template>

当然还可以使用ES6的解构赋值,看起来更好看

<template>
  <div id="app" class="container">
    <Category title="印度三相神">
      <!-- ES6解构赋值 -->
      <template scope="{sanxianshen}">
        <ul>
          <li v-for="(item, index) in sanxianshen" :key="index">{
   
   { item }}</li>
        </ul>
      </template>
    </Category>
    <!-- 使用slot-scope,是新的api -->
    <Category title="印度三相神">
      <template slot-scope="{sanxianshen}">
        <ol>
          <li v-for="(item, index) in sanxianshen" :key="index">{
   
   { item }}</li>
        </ol>
      </template>
    </Category>
  </div>
</template>

路由Vue Router

1.路由route和路由器router概述

路由route是一组key-value的对应关系;多个路由需要经过路由器的管理

对应在vue中就是 路径与组件的映射成为路由

路由器router时时刻刻检测路径变化

2.使用路由后有哪些变化

vue-router是vue的一个插件库,专门用来实现spa应用(单页面web应用),即整个页面只有一个完成的页面。

vue-router相比之前的多页面(多个html)的区别

1.点击页面中的导航链接不会刷新页面

2.做页面的局部更新,数据需要通过ajax请求获取


3.创建路由器/引入路由器

npm install vue-router --save

后续可能会报错:vue_router__WEBPACK_IMPORTED_MODULE_2__.default is not a constructor

解决办法:卸载原本的vue-router,指定安装版本

npm uninstall vue-router
npm install vue-router@3

router/index.js创建路由器

新建router文件夹

在index.js中写入如下内容 

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";

//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      path: "/bedroom",
      component: () => {
        import("../pages/Bedroom");
      },
    },
    {
      path: "/kitchen",
      component: () => {
        import("../pages/Kitchen");
      },
    },
  ],
});

main.js配置路由器

在main.js中添加内容如下

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入VueRouter
import VueRouter from 'vue-router'
//引入路由器
import router from './router'

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

//应用插件
Vue.use(VueRouter);
new Vue({
  router:router,
  render: h => h(App),
}).$mount('#app')

4.router-link/rouer-view使用路由器

router-link实现点击不同的导航,路径发生变化

<router-link>:该标签是一个vue-router中已经内置的组件,他会被渲染成一个<a>标签。

router-link属性介绍
to:用于指定跳转的路径
tag:tag可以指定<router-link>之后渲染成什么组件,比如我们下面的代码会被渲染成一个<li>元素,而不是<a> 。 如:<router-link to='/home' tag='li'>

<router-view>:该标签会根据当前的路径,动态渲染出不同的组件。

在App.vue中,修改为如下内容

<template>
  <div id="app">
    <div>
      <!--vue中借助router-link 实现路由的切换 -->
      <router-link to="/bedroom">卧室</router-link>
      <br/>
      <router-link to="/kitchen">厨房</router-link>
      <!--指定组件的呈现位置-->
      <router-view></router-view>
    </div>
  </div>
</template>

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

在页面的效果:

点击卧室

点击厨房:


5.路由参数query和params

params要在path设置占位


6.编程式路由导航

不借助<router-link>实现路由跳转,让路由跳转更加灵活

this.$router.push({

})


this.$router.replace({

})

this.$router.forward()//前进
this.$router.back()//后退
this.$router.go()

路由缓存

路由切走之后,再切回来。数据就没了,因为组件会销毁和重新挂载


7.路由器的2种工作模式

路由器的默认工作模式是hash

hash模式

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


2.hash值不会包含在HTTP请求中,即:hash值不会随着http请求发给服务器

3.hash模式

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

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


VueX 多组件共享数据

VueX不属于任何一个组件,它不在app里

vuex定义:专门在Vue中实现集中式状态(数据)管理的一个vue插件

1、纯vue版实现求和案例

创建组件Count.vue

<template>
  <div>
    <h1>当前求和为:{
    
    { sum }}</h1>
    <select v-model.number="n">
      <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>
export default {
  name: "Count",
  data() {
    return {
      n: 1, //用户选择的数字
      sum: 0, //当前的和
    };
  },
  methods: {
    increment() {
        this.sum+=this.n
    },
    decrement() {
        this.sum-=this.n
    },
    incrementOdd() {
        if(this.sum%2){
            this.sum+=this.n
        }
    },
    incrementWait() {
        setTimeout(() => {
            this.sum+=this.n
        }, 500);
    },
  },
};
</script>

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

在App.vue中引入Count.vue

<template>
  <div id="app">
    <count />
  </div>
</template>

<script>
import Count from "./components/Count.vue";

export default {
  name: "App",
  components: {
    Count,
  },
};
</script>

页面效果:

说实话,我写完觉得也没啥大的毛病啊,看看vuex能做什么优化呢


2、Vuex工作原理图

Backend API:不知道加几去action后端问问,要是知道加几可以vc直接commit

工作对象

state:状态,用于存储对象数据
Actions:行为,用于保存方法的行为,可以包含异步操作
Mutations:转变,用于提交行为的结果,不可以包含异步操作
Getters:类似于在store中的计算属性
Modules:模块,将store分割成不同的模块,每个模块有自己的state、actions、mutations

store.dispatch

store.commit

state、Actions、Mutations这三个都要经过store管理

工作原理

Rendervue组件中可以读取state中的数据(对应工作原理图中的①这一条线)
Dispatch:调用store中的dispatch方法,由
vue组件派发给Actions执行,Actions可以继续给自身派发,也可以调用异步方法(Backend API)(对应工作原理图中的②这一条线)
Commit:调用store中的commit方法,由
Actions提交给Mutations执行,也可以直接由组件提交(对应工作原理图中的③⑤这两条线)
Mutate
ActionsMutations中更改state中的数据,不需要手动执行,由api直接调用。一般是Mutations调用,在此处调用,可以被开发者工具(Devtools)直接监控,由Actions调用时,不被监控。(对应工作原理图中的④⑥这两条线)


3、创建并引入store

因为我们使用的是vue2,对应就要安装vuex3

npm i vuex@3

创建store目录,并在其下创建index.js

index.js文件内容如下

import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用插件
Vue.use(Vuex)

//准备actions,用于响应组件中的动作
const actions={}

//准备mutations,用于操作数据
const mutations={}

//准备state,用于存储数据
const state={}

//创建并暴露store
export default new Vuex.Store({
    actions,
    mutations,
    state
})

============

在main.js引入vuex插件,并在创建vm时传入store

import Vue from 'vue'
import App from './App.vue'
//引入store
import store from './store'

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

//创建vm
const vm=new Vue({
  store,
  render: h => h(App),
}).$mount('#app')
console.log(vm)

打开控制台就可以看到$store


4、使用Vuex对求和案例改造

改造store目录下的index.js

//该文件用于创建vuex中最为核心的store

import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用插件
Vue.use(Vuex)

//准备actions,用于响应组件中的动作
const actions={
    'jia':function(context,value){
      //context上下文对象,可以理解为mini版store
      console.log('actions中的jia被调用了',context,value)
      context.commit('JIA',value)
    },
    'jian':function(context,value){
        //context上下文对象,可以理解为mini版store
        console.log('actions中的jian被调用了',context,value)
        context.commit('JIAN',value)
      }
}

//准备mutations,用于操作数据
const mutations={
    'JIA':function(state,value){
        console.log('mutations中的JIA被调用了',state,value)
        state.sum+=value
      },
      'JIAN':function(state,value){
        console.log('mutations中的JIAN被调用了',state,value)
        state.sum-=value
      }
}

//准备state,用于存储数据
const state={
    sum:0
}

//创建并暴露store
export default new Vuex.Store({
    actions,
    mutations,
    state
})

======改造Conut.vue

<template>
  <div>
    <!--模板中可以直接使用vc中的数据,不用写this.-->
    <h1>当前求和为:{
    
    { $store.state.sum }}</h1>
    <select v-model.number="n">
      <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>
export default {
  name: "Count",
  data() {
    return {
      n: 1//用户选择的数字
    };
  },
  methods: {
    increment() {
        this.$store.dispatch('jia',this.n)
    },
    decrement() {
        this.$store.dispatch('jian',this.n)
    },
    incrementOdd() {
        if(this.$store.state.sum%2){
            this.$store.dispatch('jia',this.n)
        }
    },
    incrementWait() {
        setTimeout(() => {
           this.$store.dispatch('jia',this.n)
        }, 500);
    },
  },
};
</script>

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

此时效果就和原来的一样了,每个按钮都生效

可以做优化,没有业务逻辑可以跳过actions,在组件里使用commit方法而不是dispatch


5、store中的getters配置项

当state中的数据需要经过加工后再使用,可以使用getters加工(适合逻辑复杂并需要被复用)

getters配置项 

在Count.vue中使用

<h1>当前求和为:{
    
    { $store.state.sum }}</h1>    
<h1>当前求和放大10倍为:{
    
    { $store.getters.bigSum }}</h1>


computed和watch

计算属性computed

vue认为data里写的就是属性,计算属性放在computed

计算属性要求把计算的整个过程配置成一个对象

get的return返回值是什么,计算属性的值就是什么

对App.vue做内容修改

<template>
  <div id="app">
    <div>
      姓: <input type="text" v-model="firstname" /> <br />
      名: <input type="text" v-model="lastname" /> <br />
      全名: <span>{
    
    { fullname }}</span>
    </div>
  </div>
</template>
 
<script>
export default {
  name: "App",
  components: {},
  data() {
    return {
      firstname: "小",
      lastname: "羽毛",
    };
  },
  computed: {
    // 是属性fullname通过data里的属性计算出来的
    fullname: {
      get() {
        console.log('get被调用了'); //此处this是vc
        return this.firstname + "-" + this.lastname;
      },
    },
  },
};
</script>   

界面效果:

打开vue开发者工具,就能看到哪些是计算属性了

 再看看这个效果,猜猜get被调用了几次,由于computed的缓存机制,get方法只被调用了一次

get方法调用时机总结:

1.初次读取fullname时,get会被调用。

2.所依赖的数据发生变化时,get会被调用。

依赖指的就是它是通过谁计算出来的,它就依赖谁。

set方法是可以不写的,在计算属性发生改变时会调set方法,入参就是改变后的值

  computed: {
    // 是属性fullname通过data里的属性计算出来的
    fullname: {
      get() {
        console.log('get被调用了'); //此处this是vc
        return this.firstname + "-" + this.lastname;
      },
      set(value){
      //value是改变后的值
      console.log('set被调用了',value)
      const arr=value.split('-')
      this.firstname=arr[0]
      this.lastname=arr[1]
      }
    },
  },

计算属性简写形式如下,

要求只有computed里只有get,没有set修改

原来的计算属性:

简写后

  computed: {
    // 是属性fullname通过data里的属性计算出来的
    fullname() {
      return this.firstname + "-" + this.lastname;
    },
  },

猜你喜欢

转载自blog.csdn.net/m0_56799642/article/details/128137186