Vue入门1

B站吴悠老师的vue课程学习笔记

概述

Vue是一个渐进式JS框架。什么是框架呢?与库又有什么区别?
库会以工具的方式(比如属性或方法)来帮助我们完成一些特定的功能,封装好一些函数供开发者使用,比如jQuery就是一个常用的JS库。而框架比较复杂,有很多自己的语法,因此需要学习框架的使用方式。
Vue将网页开发中最常见的DOM操作内置到了框架之中,可以使我们专注于数字逻辑处理而避免了繁琐的dom操作,大大降低开发难度。同时使用MVVM模式,将数据和页面呈现相分离,降低代码耦合度,支持组件化开发。
组件是web页面上抽出来一个个包含模板html、功能js、样式css的单元,好的组件具备封装性、正确性、扩展性、复用性

Vue2核心语法

image.png

响应式数据与插值表达式

在使用js编写的传统页面中,如果想要修改某个页面上的值,需要先获取要修改的dom,再通过textContent方法改值,每次修改都需要加一行修改代码,dom操作非常的繁琐。
在vue中这项操作变得方便快捷。只需要创建一个vue,绑定好要修改的类,然后在data的return里直接设置要修改的值。页面会同步响应,无需再手动进行dom操作。后续也可以在控制台通过vue实例访问甚至修改这个变量,页面上也会同步显示。对了,别忘了在html标签中使用两个大括号绑定插值表达式,这个和模板字符串有点类似。
还有methods函数属性,可以在其中定义一些函数,在页面上调用,调用时记得加括号

<body>
    <div id="app">
        <!--  插值表达式 -->
        <p>{{ title }}</p>
        <p>{{ content }}</p>
        <!-- 插值表达式也可以进行一些逻辑运算 -->
        <p>{{1 +2 + 3}}</p> 
        <p>{{ 1 > 2 ? '对' : '错' }}</p>
        <p>{{ output() }}</p>
    </div>

    <script src="./vue.min.js"></script>
    <script>
        const vm = new Vue({
            // 1. 响应式数据与插值表达式
            // 在vue内部对数据做操作会自动更新到视图中
            el: '#app', // el属性用于设置vue的生效位置,是选择器的语法
            data () { // data用于声明响应式数据 
                return { // 可以直接通过vue实例访问
                    title: '这是标题', 
                    content: '这是内容'
                }
            },
            methods: { // methods函数属性
                output () {
                    return '标题为:' + this.title + ',内容为:' + this.content
                }
            }
        })
    </script>
</body>

image.png

计算属性

如果在页面中频繁调用method函数属性里面的方法,会造成冗余的运算,这时候就可以用computed计算属性,它与函数属性类似,不过具有缓存的功能,只有在响应式数据变化时才会重新计算,所以如果都设置控制台输出,分别调用三次methods和三次computed,methods会输出三次,而computed只会输出一次。注意,调用computed里的方法时不加括号。

// 2. computed计算属性:具有缓存性,响应式数据变化时才会重新计算
            computed: {
                outputContent () {
                    console.log('computed执行了')
                    return '标题为:' + this.title + ',内容为:' + this.content
                }
            },

image.png

监听器

如果想要在响应式数据出现变化时进行一些其他的操作,就可以使用watch监听器

            // 3. watch监听器:监听某个数据是否有变化,传入两个值,分别是新值和旧值
            watch: { // 比如监听title数据
                title (newValue, oldValue) {
                    console.log(newValue, oldValue);
                }
            }

image.png

指令

有几类可以绑定在标签中的指令

        <!-- 4. 指令v- -->
        <!-- 内容指令 -->
        <p v-text="htmlContent"></p> <!-- 会覆盖标签原始内容 -->
        <p v-html="htmlContent"></p> <!-- 可以解析html标签 -->

        <!-- 渲染指令 -->
        <!-- for循环,item是值,key是键,index是索引 -->
        <p v-for="item in arr">这是数组:{{item}}</p>
        <p v-for="(item, key,index) in obj">这是对象:{{item}}{{key}}{{index}}</p>
        <p v-if="bool">标签内容</p> <!-- 条件判断元素销毁 -->
        <p c-show="bool">标签内容</p> <!-- 元素显示,如果是false,display属性会变成none -->

        <!-- 属性指令 -->
        <p v-bind:title="title">鼠标悬停显示标题内容</p>
        <pv :title="title">这是内容</p> <!-- 简写 -->

        <!-- 事件指令 -->
        <button v-on:click="output">按钮</button>
        <button @click="output">按钮</button> <!-- 简写 -->

        <!-- 表单指令:v-model实现双向数据绑定 -->
        <input type="text" v-model="inputValue">
        <p v-text="inputValue"></p>
        <!-- 下拉框,v-model会忽略元素表单的value、checked、selected属性的初始值,使用vue实例的数据作为数据来源。并且,v-model的表达式未设置值时,select元素将被渲染为未选中,可能导致用户无法选择第一个选项。因此建议设置一个值为空的禁用选项 -->
        <select v-model="selected">
            <option value="" disabled>请选择--</option>
            <option value="A">A</option>
            <option value="B">B</option>
            <option value="C">C</option>
        </select>

修饰符

用来实现与指令相关的一些操作,用来简化代码和dom操作

        <!-- 5. 修饰符 -->
        <input type="text" v-model.trim="inputValue"> <!-- 去除前后空格 -->
        <!-- 还有一些事件修饰符 -->

Vue CLI

Vue CLI是Vue基于Webpack打造的脚手架工具,内置了很多模板和工具,可以快速进行Vue的项目搭建
具体的安装过程就不赘述了,网上有很多教程,但是在安装vue/cli时记得使用镜像,不然会等一两个小时还装不好
常用的指令有几种

  • 创建项目:vue create 项目名,然后进入项目中
  • 进入脚手架内部的静态资源服务器:npm run serve
  • 进行代码打包:npm run build然后会出现dist目录
  • 进入指定目录下的静态资源服务器:npm i serve -g然后serve 目录名

组件化开发

组件听起来陌生,但是组件的思想我们早就已经接触过。如果一个程序中有很多冗余的代码来完成相似的任务,我们可以把这种功能抽出来封装成函数,在需要的时候直接调用就可以了。组件也是类似的功能,本质上是自定义的模板。比如需要写很多相似的切换按钮或者列表结构时,就可以自己写一些新标签作为模板,然后就可以把这些标签当作html标签拿来用,可以更好地完成前端页面功能的封装。而且组件可以多重嵌套,这样代码的复用度就会很高,也便于代码的维护。

<body>

    <!-- view层 -->
    <div id="app">
        <!-- 使用自定义组件 -->
        <!-- ite是在vm的items中取出的每一项数据,通过v-bind绑定到组件的item属性上 -->
        <my-component v-for="ite in items" v-bind:item="ite"></my-component>

    </div>

    <!-- module层 -->
    <script src="./vue.min.js"></script>
    <script>
        // 自定义组件
        Vue.component("my-component", { // 组件的名字
            props: ["item"], // 接收vue传递的参数,否则无法在组件中使用
            template: "<li>{{ item }}</li>" // 组件的模板
        })

        var vm = new Vue({
            el: "#app",
            data() {
                return {
                    items: ["java", "python", "linux"]
                }
            }
        })
    </script>

</body>

image.png

实例

每个组件文件(.vue)都由三个部分组成,template,script,style。
template是结构也就是模板;script是逻辑,其中的中的export default是暴露的接口;style是样式

  • src目录中的App.vue是根组件,其他子组件要先在根组件中导入路径并在compones中引入后才能使用,使用时用html标签的格式写在template中。子组件也是用.vue文件的形式写在src的components目录中。
  • 以helloworld为例,当打包时看到在某一个组件的结构里面存在一个helloworld标签,它就会明白这不是HTML内置的标签,就会去找有没有这样一个组件,就找到了helloworld.vue中的配置对象(export default),然后根据这个对象进行new vue操作。
  • App.vue这种根组件也有类似的结构,但是它没有父组件,是在入口处也就是main.js中的render函数进行组件的实例化创建。
  • vue组件在使用时就相当于一个自定义HTML标签,但其实每一个vue组件都是一个独立的vue实例,会在编译环节进行结构生成并替换掉自定义的标签。所以vue的实例属性在组件中也是可以使用的,不过el属性只能在根组件中进行设置,内部子组件无需el属性。

image.png

组件通信方式

在开发当中,组件和组件之间是有关联性的,体现在数据的交互上,父组件可以给子组件传数据,子组件也可以给父组件传数据,也可以双向传输。

父组件传子组件

父组件在template标签中引用了来自子组件的helloworld标签,并在标签内部自定义了几个属性,想要把这些属性传输给子组件
在子组件的export default中通过props进行处理,里面对父组件传来的每个数据进行设置,包括类型、默认值、是否必填等等。
也可以传输响应式数据,只需要在父组件标签添加属性时加上:,并且在export default中设置data就行,与前面学过的语法是一样的
下面是实例,为了避免啰嗦,style标签我就不粘上来了

父组件App.vue
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <!-- 引入组件使用html标签,给子组件设置属性msg、count和响应式数据xiangying -->
    <h1>父组件中接收到的数据: {{ childData }}</h1>
    <HelloWorld 
    msg="Welcome to Your Vue.js App"
    count="10"
    :xiangying="Parentxiangying"
    ></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
  name: 'App',
  components: { // 引入组件
    HelloWorld
  },
  data () { //设置响应式数据
    return {
      Parentxiangying: 1000,
    }
  }
}
</script>


子组件HelloWorld.vue
<template>
  <div class="hello">
    在子组件中展示从父组件中传来的值
    <h1>{{ msg }}</h1>
    <p>props中的count{{ count }}</p>
    <p>props中的响应式数据{{ xiangying }}</p>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  // 组件通信
  // 1. 父传子:通过 props 进行处理
  props: {
    msg: String,
    count:{
      type: [String, Number],
      default: 100, // 默认值,适用于可选项
      required: true // 是否必填,如果是true但不填控制台会报错
    },
    // 也可以设置响应式数据
    xiangying: Number
  }
</script>

子组件传父组件

这个有点复杂,需要通过自定义事件处理。
我们想把子组件的数据传输到父组件,就要在子组件编写一个事件,比如点击按钮。在子组件的template中加上一个按钮<button @click="handler">按钮</button>,并在export default中声明按钮中的函数,比如这个我们是点击按钮使得childCount属性++(别忘了在data中设置这个响应式数据),并且用$emit传输到父组件,参数是自定义事件名和要传递的数据。
父组件内部在HelloWorld标签中添加上这个事件属性。这里我们为了直观,新设置一个参数childData并在页面中展示出来(别忘了在data中设置这个响应式数据),然后在methods中编写这个父组件的方法。
最后效果就是点击页面上子组件的按钮,变化的数据就会传到父组件的标签中并显示出来
总之就是子组件自己编了一个child-count-change事件,由父组件做监听,通过子组件内部调用this.$emit来触发父组件的监听事件并传值,从而触发父组件的函数

父组件App.vue
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <h1>父组件中接收到的数据: {{ childData }}</h1>
    <HelloWorld 
    @child-count-change="handlers"
    ></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
  name: 'App',
  components: { // 引入组件
    HelloWorld
  },
  data () { //设置响应式数据
    return {
      childData: 0
    }
  },
  methods: {
    handlers (childCount) {
      this.childData = childCount
    }
  }
}
</script>


子组件HelloWorld.vue
<template>
  <div class="hello">
    <button @click="handler">按钮</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  // 2. 子传父:通过自定义事件处理
  // 子组件自己编的事件名为child-count-change,由父组件做监听
  // 通过子组件内部调用this.\$emit来触发父组件的监听事件并传值,从而触发父组件的函数
  data () {
    return {
      childCount: 0
    }
  },
  methods: {
    handler () {
      this.childCount++
      // 自定义事件名,要传递的数据
      this.$emit('child-count-change', this.childCount)
    }
  }
}
</script>

image.png

同级之间传递

可以通过父组件来中转,也可以通过EentBus(通过一个额外的vue实例来做存储),如果两个组件离得很远,就可以使用Vuex,具体在下节讲解

组件插槽

如果父组件在使用子组件的时候想自己定义一些东西,就可以使用插槽,在父组件引用的双标签中间写一些东西,就可以在子组件的slot标签的位置呈现出来。本质上就是父子传值,将父组件中定义的数据通过插槽的形式传输到子组件中。
插槽有几种形式,首先就是默认插槽,子组件的slot不加任何修饰,父组件的双标签中的内容分就会查到这个默认位置,如果双标签中没有内容,就会显示slot中的默认内容;其次是具名插槽,如果有好几个插槽,想指定某个特定位置,在slot插槽中加上name="插槽名",在父组件的双标签中加上<template v-slot:插槽名>,或者简写成#name,就可以把父组件的特定内容传到子组件特定位置的插槽;最后是作用域插槽,适用于想在父组件中使用子组件值的情况,在slot中写上:name="子组件中的值名",要注意传递的是整个对象,要在父组件中写清楚<template #插槽名="dataObj"> {{ dataObj.name }},或者用解构的写法,<template #header="{ name }"> {{ name }}

父组件App.vue
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld  
    msg="Welcome to Your Vue.js App"
    count="10"
    :xiangying="Parentxiangying"
    @child-count-change="handlers"
    ></HelloWorld>

    <hr>

    <HelloWorld>
      我是默认插槽,对应普通的slot
      <template v-slot:header>我是header插槽,使用特定插槽需要在template标签中加上相应的name,v-slot:name可简写成#name</template>
    </HelloWorld>

    <hr>

    <HelloWorld>
      <template #header="dataObj">作用域插槽,子组件给父组件传的值是整个对象,使用时需要在注明是对象的哪个值,或者在传值时加上大括号{{ dataObj.childcount }}</template>
    </HelloWorld>

  </div>
</template>

子组件HelloWorld.vue
<template>
  <div>
    <slot name="header" :childcount="childCount">我是hander插槽的默认内容</slot>
    <br>
    <slot>我是默认插槽的默认内容,如果父组件中没有自定义插槽内容,就显示我</slot>
  </div>
</template>

image.png

吴悠老师讲的例子可能比较复杂,这里加上一个秦疆老师的例子帮助理解。另外,数据存储在Vue实例中,如果想在组件中删除数据,会涉及到参数传递与事件分发,与前面讲过的是一样的用法

<body>

    <!-- view层 -->
    <div id="app">
        <!-- 使用组件和插槽,只不过插槽是用组件的形式插进来的 -->
        <todo>
            <todo-title slot="todo-title" :title="title"></todo-title>
            <todo-items slot="todo-items" v-for="(item, index) in todoItems" 
            :item="item" :index="index" v-on:remove="removeItems(index)"></todo-items>
            <!-- 前端的remove事件绑定到vue的removeItems方法 -->
        </todo>
    </div>

    <!-- module层 -->
    <script src="./vue.min.js"></script>
    <script>
        // todo父组件,规定了框架,里面有两个插槽,使用反斜杠换行
        Vue.component("todo", {
            template: '<div>\
                <slot name = "todo-title"></slot>\
                <ul>\
                    <slot name = "todo-items"></slot>\
                </ul>\
                </div>'           
        })

        // 两个子组件具名插槽,列表的名字和列表项,使用props传递数据
        Vue.component("todo-title", {
            props:["title"],
            template: '<div>{{ title }}<div>'
        })
        Vue.component("todo-items", {
            props:["item", "index"],
            // 只能绑定当前组件的方法
            template: '<li>{{ index }}--{{ item }}<button @click="remove">删除</button></li>',
            methods: {
                remove(index) {
                    this.$emit("remove", index) // 自定义事件分发,绑定到前端的remove事件
                }
            }
        })

        var vm = new Vue({
            el: '#app',
            data: {
                title: '前端三件套',
                todoItems: ['html', 'css', 'javascript']
            },
            methods: {
                removeItems(index) {
                    console.log("删除了"+this.todoItems[index])
                    this.todoItems.splice(index, 1) // 从数组中索引为index的元素开始删除几个元素
                }
            }
        })
    </script>

</body>

image.png

Axios

Axios是一个可以在浏览器和nodejs使用的异步通信框架,用来实现ajax的异步通信,与jQuery相比减少了频繁的dom操作。跟vue一样,需要下载或者引入后使用。axios提供了很多钩子,方便在生命周期的不同阶段获取数据。
使用的格式也比较固定: axios.get().then(response => ())

<body>

    <!-- view层 -->
    <div id="app">
        <div>{{ info.name }}</div>
        <div>{{ info.address.country }}</div>

        <a v-bind:href="info.url">点我</a>
    </div>

    <!-- module层 -->
    <script src="./vue.min.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            // data: 是属性,data(){}是方法
            data() {
                return {
                    // 请求的返回参数格式必须和json字符串格式一致
                    info:{
                        name: null,
                        sex: null,
                        address: {
                            street: null,
                            city: null,
                            country: null
                        },
                        url: null
                    }
                }
            },
            mounted() { // 钩子函数,页面加载完成后执行,格式是固定的axios.get().then(response => ()),这里是把读到的数据返回给info
                axios.get('../data.json').then(Response => (this.info = Response.data))
            }
        })
    </script>

</body>

image.png

VueRouter和Vuex

vue-router

是vue的官方路由插件,用于构建单页面应用。传统的页面应用是用超链接来实现页面切换和跳转的,但vue是单页面应用,相当于只有一个index.html的页面,不能用a标签。在vue-router单页面应用中,页面的切换是路径之间的切换,也就是组件的切换。路由模块的本质就是建立起url和页面之间的映射关系,做页面导航。

基本使用方法

  • 先定义要展示的子组件(路由),在其script中写上默认导出属性
  • 再在index.js也就是主页面中导入子组件的路径,并在routes中加上这个路由配置信息比如path、name、component
  • 最后在父组件中的写上router-link,绑定路由链接
VidoeView.vue
<template>
  <h3>一级组件视频信息</h3>
</template>
<script>
export default {
  name: 'VideoView'
}
</script>

index.js
import VideoView from '../views/VideoView.vue'
const routes = [
  {
    path: '/video',
    name: 'video',
    component: VideoView
  }
]

App.vue
<template>
  <div id="app">
    <nav>
      <!-- vue router提供的两个组件,router-link和router-view -->
      <!-- router-link用来定义路由链接,router-view用来渲染当前路由匹配到的组件 -->
      <router-link to="/">Home</router-link> |
      <!-- 也可以通过name属性绑定路由链接 -->
      <router-link :to="{name: 'video'}">Video</router-link>
    </nav>
    <router-view/>
  </div>
</template>

动态路由

如果我们想打开不同的视频,这些视频的地址几乎一样,只有编号不同,就可以使用动态路由。
在index.js的routes中的路径后面加上:id,并写上props: true,这样就可以在在子组件内部访问这个动态路由;子组件中通过来使用动态路由<p>视频id为:{{ id }}</p>;App.vue的router有两种写法,<router-link :to="{name: 'video', params: { id: 30 }}">Video</router-link>或者<router-link to="/video/30">Video</router-link>

嵌套路由

如果想查看某个视频的点赞量、弹幕等参数,也就是一级功能里还有二级功能,就需要二级的路由子组件。
在index.js中要嵌套的父路由中加一个children属性,是一个数组,里面写要嵌套的子路由,写法和普通路由类似,就是path、name、component;别忘了在文件头引入新的子路由,可以把子路由写在一个文件夹里。接下来就是写这两个子路由,定义样式和默认导出参数。最后在父路由中加上子路由的router-link和router-view,写法和App.vue中的一样。

index.js
import VideoView from '../views/VideoView.vue'
import VideoInfo1 from '../views/video/VideoInfo1.vue'
import VideoInfo2 from '../views/video/VideoInfo2.vue'
const routes = [
  {
    path: '/video/:id', // 动态路由
    name: 'video',
    component: VideoView,
    children: [ // 子路由,数组,形式和普通路由类似
      { path: 'info1', name: 'video-info1', component: VideoInfo1 },
      { path: 'info2', name: 'video-info2', component: VideoInfo2 }
    ],
    props: true // 这样就可以在组件内部访问到动态路由的值
  }
]

VideoInfo1.vue
<template>
  <div class="video-info1">
    <h3>二级组件:点赞情况分析</h3>
  </div>
</template>
<script>
export default {
  name: 'VideoInfo1'
}
</script>

VideoInfo2.vue
<template>
  <div class="video-info1">
    <h3>二级组件:互动情况分析</h3>
  </div>
</template>
<script>
export default {
  name: 'VideoInfo2'
}
</script>

VideoView.vue
<template>
  <div class="video">
    <h3>一级组件:视频信息</h3>
    <p>视频id为:{{ id }}</p>
    <router-link :to="{name: 'video-info1', params: { id: 30 }}">点赞信息</router-link>
    <router-link :to="{name: 'video-info2', params: { id: 30 }}">互动信息</router-link>
    <router-view></router-view>
  </div>
</template>

image.png

编程式导航

前面我们学的都是通过点击router-link来切换页面,那么如果我们想要主动地跳转页面比如登陆状态过期了跳转到首页,该怎么办呢?
在要跳转的页面的默认导出属性中加一个生命周期钩子create(组件创建完毕后执行),里面有一些操作,用router写具体要跳转的页面或者执行的函数,也可以写在计时器里

<script>
export default {
  name: 'VideoInfo1',
  created () { // 当组件创建完毕以后会执行的生命周期钩子
    setTimeout(() => { // 3秒后跳转到首页
      // router是用来进行路由操作的工具
      this.$router.push({ name: 'home' })
    }, 3000)
  }
}
</script>

路由传参与导航守卫

除了编程式导航以外还有一些搭配的操作,比如希望在跳转路由的时候进行数据的传递,就要在在上面的基础上通过query加入要传递的参数,并在跳转的目标页面也写create并使用route接收相应的数据

<script>
export default {
  name: 'VideoInfo1',
  created () { // 当组件创建完毕以后会执行的生命周期
    setTimeout(() => {
      // router是用来进行路由操作的工具
      // 3秒后跳转到info2并进行数据传递
      this.$router.push({ name: 'video-info2', query: { someData: 'info1传递的数据' } })
    }, 3000)
  }
}
</script>

VideoInfo2.vue
<script>
export default {
  name: 'VideoInfo2',
  created () {
    // route是用来接收数据的
    // 在控制台打印接收的数据
    console.log(this.$route.query)
  }
}
</script>

导航守卫:给所有导航统一做设置,比如进度条。在index.js中写router.beforeEach,三个参数是to,from,和next(接下来干什么)

index.js
    // 全局导航守卫,在每次导航触发之前会进行这个触发
    router.beforeEach((to, from, next) => {
      console.log('路由触发了')
      next()
    })

Vuex

是一个全局的数据存储工具,提供了五个功能,写在store的index.js当中

  • state:用来存储全局的数据,在其他组件中都可以访问,可以写成函数的形式
  • mutations:修改全局数据,类似于函数,通过commit提交,必须是同步的
  • actions:用来做异步包装
  • getters:具有缓存性,相当于计算属性,只有数据变化的是时候才会触发
  • modules:模块,便于数据管理避免混乱,在使用时注明是a中的数据还是b中的数据
index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state () { // 在全局存数据,其他组件都可以访问,可以写成函数方式
    return {
      loginStatus: '用户已经登陆',
      count: 0
    }
  },
  getters: { // 具有缓存性,相当于计算属性,只有数据变化的是时候才会触发
    len (state) {
      console.log('getters执行了')
      return state.loginStatus.length
    }
  },
  mutations: { // 修改全局数据,类似于函数,通过commit提交,必须是同步的
    changeCount (state, num) {
      state.count += num
      console.log('mutation执行了,count值为', state.count)
    }
  },
  actions: { // 用来做异步包装
    delaychangeCount (store, num) {
      setTimeout(() => {
        store.commit('changeCount', num)
      }, 3000)
    }
  },
  modules: { // 模块,便于数据管理避免混乱,在使用时注明是a中的数据还是b中的数据
    a: {
      state,
      mutations
    },
    b: {
      state,
      mutations
    }
  }
})

VideoInfo2.vue
<script>
export default {
  name: 'VideoInfo2',
  created () {
    // route是用来接收数据的
    // 在控制台打印接收的数据
    // console.log(this.$route.query)
    console.log(this.$store.state.loginStatus)
    this.handler()
  },
  methods: {
    handler () { // 全局状态往往在主逻辑中的某个位置,要用的时候才使用
      // 报错不知为何TypeError: Cannot read properties of undefined (reading 'commit')
      this.$sotre.commit('changeCount', 1)
      this.$sotre.commit('changeCount', 2)
      this.$store.dispatch('delayChangeCount', 10)
      this.$sotre.commit('changeCount', 3)
      console.log(this.$store.getters.len) // 虽然调用多次,但是数据没有变化,只会执行一次
      console.log(this.$store.getters.len)
      console.log(this.$store.getters.len)
    }
  }
}
</script>