Vue开发入门(一)

344 阅读10分钟

vue简介

是一个前端的双向绑定类的框架,发音[读音 /vjuː/, 类似于 view]。新的Vue版本参考了React的部分设计,当然也有自己独特的地方,比如Vue的单文件组件开发方式都很有创新,另外Vue自身的一些绑定的语法、用法等都非常精炼,很容易上手,而且第三方的插件都非常丰富,社区非常活跃,最新的文档都有中文版本。而且Vue配合官方的和第三方的库可以实现单文件的组件化开发、SPA等现代化前端开发。

什么是vue.js

单独来讲,Vue.js被定义成一个用来开发Web界面的前端库,是个非常轻量级的工具。 Vue.js本身具有响应式编程和组件化的特点。

所谓响应式编程,即为保持状态和视图的同步,这个在大多数前端MV* ( MVC/MVVM/ MVW )框架,不管是早期的backbone.js还是现在AngularJS都对这一特性进行了实现(也 称之为数据绑定),但这几者的实现方式和使用方式都不相同。相比而言,Vue.js使用起来更 为简单,也无需引入太多的新概念,声明实例new Vue({ data : data })后自然对data里面 的数据进行了视图上的绑定。修改data的数据,视图中对应数据也会随之更改。

Vue.js的组件化理念和ReactJS异曲同工一“一切都是组件”,可以将任意封装好的代 码注册成标签,例如:Vue.component(‘example’, Example),可以在模板中以 </ example>的形式调用。如果组件抽象得台理,这在很大程度上能减少重复开发,而且配合 Vue.js的周边工具vue-loader,我们可以将一个组件的CSS.HTML和js都写在一个文件里, 做到模块化的开发。

除此之外,Vue.js也可以和一些周边工具配合起来,例如vue-router和vue-resource, 支持了路由和异步请求,这样就满足了开发单页面应用的基本条件。

什么是mvvm

MVVM 由 Model、View、ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。

在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

vue编程环境搭建

开发工具安装
安装node.js
  • 下载node.js

    下载地址:nodejs.cn/download/

  • 查看是否安装成功

    node -v

    npm -v

  • npm常用命令

    • 添加用户 npm adduser

    • 添加镜像

      添加淘宝的镜像

      npm  config  set  registry  https://registry.npm.taobao.org
      
    • 删除镜像

      npm config delete registry 删除镜像

      npm config edit 打开配置文件,手动编辑删除

    • npm安装模块

      【npm install】 根据package.json文件安装

      【npm install xxx】利用 npm 安装xxx模块到当前命令行所在目录;

      【npm install -g xxx】利用npm安装全局模块xxx;

      【npm install xxx】安装但不写入package.json;

      【npm install xxx –save】 安装并写入package.json的”dependencies”中;

      【npm install xxx –save-dev】安装并写入package.json的”devDependencies”中。

    • npm 删除模块

      【npm uninstall xxx】删除xxx模块;

      【npm uninstall -g xxx】删除全局模块xxx;

    • npm更新模块

      【npm update -g XXX】全局更新模块

      【npm update XXX】本地更新模块

    • 查看已安装的模块

      【npm ls】查看所有已安装的模块

    • 执行脚本

      【npm run】 在package.json的scripts中定义的脚本命令

    • 发布 - 了解

      【npm login】 登录

      【npm init】 初始化

      【npm publish】发布

      【npm -f unpublish】撤销发布

安装cnpm
  • 安装

    npm install -g cnpm --registry=https://registry.npm.taobao.org

  • 输入 cnpm -v ,检测是否正常

安装vue-cli脚手架
  • 使用 npm

    npm install -g @vue/cli

  • 或者使用淘宝npm镜像源

    cnpm install -g @vue.cli

安装webpack
  • 使用 npm

    npm install -g webpack

  • 或者使用淘宝npm镜像源

    cnpm install -g webpack

vue下载安装

vue.js下载及安装的三种方法。要下载安装vue首先得下载安装node.js和npm。下载安装好这两样以后就可以安装vue了

官网:cn.vuejs.org/

  • 方法一:直接用npm进行下载

    npm install vue

  • 方法二:script标签引用

    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
  • 方法三:直接在官网上下载(推荐)

快速开始

vue组件结构

一个vue组件主要包括3个部分:界面展示代码template(html代码)、业务实现代码script(js代码)、界面布局代码style(样式代码)

<template>
    <div class="class_1">
      <h2>{{msg}}</h2>
      这是一个fry VueComponentTest
    </div>
</template>

<script>
  export default {
    name: 'FryTest',
    data () {
      return {
        msg: 'Welcome to Your Vue.js App'
      }
    }
  }
</script>

<style scoped>
  .class_1{
    color: red;
  }
</style>

script基本结构

<script>
 
export default {
 
  name: "App",
 
  data() {//数据定义 函数方法,返回数据的方式
 
    return {};
 
  },
 
  methods: {
 
    // 组件的方法
 
  },
 
  watch: {
 
    // watch监听方法,擅长处理的场景:一个数据影响多个数据 
watch是去监听一个值的变化,然后执行相对应的函数。
 
  },
 
  computed: {
 
    // computed擅长处理的场景:一个数据受多个数据影响 
computed是计算属性,也就是依赖其它的属性计算所得出最后的值
 
  },
 
  beforeCreate () {
 
    // 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。
 
  },
 
  created () {
 
    // (在实例创建完成后被立即调用。实例已经创建完成之后被调用。
在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算,
 watch/event 事件回调。然而,挂载阶段还没开始,
$el 属性目前不可见。初始化数据请求写这里
 
  },
 
  beforeMount () {
 
    // 在挂载开始之前被调用:相关的 render 函数首次被调用。
 
  },
 
  mounted () {//页面初始化方法
 
    // 编译好的HTML挂载到页面完成后执行的事件钩子
 初始化数据除非有依赖dom的放在mounted()里面,加个nextTick
 
    // el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
 
    // 此钩子函数中一般会做一些ajax请求获取数据进行数据初始化
 
    console.log("Home done");
 
  },
 
  beforeUpdate () {
 
    // 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 
你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
 // 只有更新和模板发生关联的数据才会触发这个钩子
                // 和模板绑定的数据更新之前
 
  },
 
  updated () {
 
    // 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
 
    // 当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。
 
    // 该钩子在服务器端渲染期间不被调用。
 
  },
 
  beforeDestroy () {
 
    // 实例销毁之前调用。在这一步,实例仍然完全可用。一般用于清除定时器
    //$once来监听定时器,在beforeDestroy钩子可以被清除。
    this.$once('hook:beforeDestroy', () => {            
    clearInterval(timer);   })
 
  },
 
  destroyed () {
 
    // Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,
所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。
 
  }
 
};
 
</script>

vue常用指令

插值表达式

数据绑定最常见的形式就是使用 “Mustache” 语法(双大括号)的文本插值,比如模板引擎:handlebars中就是用的{{}},创建的Vue对象中的data属性就是用来绑定数据到HTML的。

  • 让文本“hello,测开大佬”以标题形式显示,以前我们是这样写:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    
        <meta charset="UTF-8">
    
        <title></title>
    </head>
    <body>
    
        <div>
            <h1>hello,测开大佬</h1>
        </div>
    </body>
    </html>
    
  • 绑定文本:双花括号

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 引入vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <meta charset="UTF-8">

    <title></title>
</head>
<body>
    <!-- 视图层 -->
    <div id="app">
        <h1>{{msg}}</h1>  <!--使用双花括号+变量名 -->
    </div>

    <script>
        var app =new Vue({ // 创建Vue对象。Vue的核心对象。
            el:'#app', // el属性:把当前Vue对象挂载到div标签上,#app是id选择器
            <!-- 数据层 -->
            data:{ // data: 是Vue对象中绑定的数据
                msg:"hello,测开大佬" // message 自定义的数据
            }
            }
        )
    </script>
</body>
</html>
  ```
  
![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/84e8456bf056425b9f6bdd3d3a1fc685~tplv-k3u1fbpfcp-zoom-1.image)

- 绑定文本:v-text

使用v-text传递数据,可以传递变量名

```
  • 绑定html标签:v-html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <!-- 引入vue -->
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
        <meta charset="UTF-8">
    
        <title></title>
    </head>
    <body>
    
        <div id="app">
            <!-- 绑定html标签 -->
            <h1 v-html="content"></h1>  
        </div>
    
        <script>
            var app =new Vue({ 
                    el:'#app',
                    data:{ 
                        content:"<p>hello,</p><p>测开大佬</p>" 
                    }
                }
            )
        </script>
    </body>
    </html>
    

属性的绑定

  • 原本的写法style="color: red"

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
        <meta charset="UTF-8">
    
        <title></title>
    </head>
    <body>
    
    <div id="app">
        <h1 v-html="content" style="color: red"></h1>
    </div>
    
    <script>
        var app =new Vue({
                el:'#app',
                data:{
                    content:"<p>hello,</p><p>测开大佬</p>"
                }
            }
        )
    </script>
    </body>
    </html>
    
  • 绑定属性

    语法:

    <标签 v-bind:属性名="要绑定的Vue对象的data里的属性名"></标签>
    

    示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
        <meta charset="UTF-8">
    
        <title></title>
    </head>
    <body>
    
    <div id="app">
        <h1 v-html="content" style="color: red"></h1>
        <!--  v-bind绑定属性 -->
        <h1 v-html="content" v-bind:style="col"></h1>
        <!--  简写,不写v-bind,用: -->
        <h1 v-html="content" :style="col"></h1>
    </div>
    
    <script>
        var app =new Vue({
                el:'#app',
                data:{
                    content:"<p>hello,</p><p>测开大佬</p>",
                    col:"color:blue"
                }
            }
        )
    </script>
    </body>
    </html>
    

事件绑定

Vue提供了协助我们为标签绑定时间的方法,当然我们可以直接用dom原生的方式去绑定事件。Vue提供的指令进行绑定也是非常方便,而且能让ViewModel更简洁,逻辑更彻底。所以还是推荐大家使用的。

  • 常用事件 click

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
        <meta charset="UTF-8">
    
        <title></title>
    </head>
    <body>
    
        <div id="app">
            <h1 v-html="content" v-bind:style="col"></h1>
            <!--  绑定事件  -->
            <button v-on:click="changeColor">更改颜色</button>
            <br>
            <!--  绑定事件简写:@  -->
            <button @click="changeColor">更改颜色</button>
        </div>
    
        <script>
            var app =new Vue({
                    el:'#app',
                    data:{
                        content:"<p>hello,</p><p>测开大佬</p>",
                        col:"color:blue"
                    },
                    methods:{ // methods下是组件的方法
                        changeColor:function () {
                            this.col="color:pink" //this表示vue对象
    
                        }
                    }
                }
            )
        </script>
    </body>
    </html>
    
    

  • 鼠标事件修饰符

    在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。 为了解决这个问题, Vue.js 为 v-on 提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。

    • stop
    • prevent
    • capture
    • self
    • once
    <!-- 阻止单击事件冒泡 -->
    <a v-on:click.stop="doThis"></a>
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    <!-- 修饰符可以串联  -->
    <a v-on:click.stop.prevent="doThat"></a>
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    <!-- 添加事件侦听器时使用事件捕获模式 -->
    <div v-on:click.capture="doThis">...</div>
    <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
    <div v-on:click.self="doThat">...</div>
    <!-- the click event will be triggered at most once -->
    <a v-on:click.once="doThis"></a>
    

    示例:(.once)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
        <meta charset="UTF-8">
    
        <title></title>
    </head>
    <body>
    
        <div id="app">
            <h1 v-html="content" v-bind:style="col"></h1>
            <!--  绑定事件  -->
            <button @click="changeColor">更改颜色</button>
            <br>
            <!-- .once,防止重复点击 -->
            <button @click.once="changeColor">更改颜色</button>
        </div>
    
        <script>
            var app =new Vue({
                    el:'#app',
                    data:{
                        content:"<p>hello,</p><p>测开大佬</p>",
                        col:"color:blue"
                    },
                    methods:{ // methods下是组件的方法
                        changeColor:function () {
                            this.col="color:pink" 
                            console.log("点击了一次按钮") //添加日志测试是否防止重复点击
                        }
                    }
                }
            )
        </script>
    </body>
    </html>
    

  • 按键事件修饰符 在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

    <!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
    <input v-on:keyup.13="submit">
    记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
    <!-- 同上 -->
    <input v-on:keyup.enter="submit">
    <!-- 缩写语法 -->
    <input @keyup.enter="submit">
    

    keydown和keyup的区别,keydown,按下键盘的键触发,keyup,按下键盘释放后触发,常用keyup。

    全部的按键别名:

    • enter

    • tab

    • delete (捕获 “删除” 和 “退格” 键)

    • esc

    • space

    • up

    • down

    • left

    • right

    • ctrl

    • alt

    • shift

    • meta

    • 示例:

      <!DOCTYPE html>
        <html lang="en">
        <head>
            <script src="https://cdn.jsdelivr.net/npm/vue"></script>
      
            <meta charset="UTF-8">
      
            <title></title>
        </head>
        <body>
      
            <div id="app">
                <h1 v-html="content" v-bind:style="col"></h1>
                <input @keyup.enter="changeColor"> 回车键更改颜色</input>
            </div>
      
            <script>
                var app =new Vue({
                        el:'#app',
                        data:{
                            content:"<p>hello,</p><p>测开大佬</p>",
                            col:"color:blue"
                        },
                        methods:{ // methods下是组件的方法
                            changeColor:function () {
                                this.col="color:pink"
                                console.log("点击了一次按钮") 
                            }
                        }
                    }
                )
            </script>
        </body>
        </html>
      

    按下回车键,效果:

条件渲染

控制两视图之间切换 有时候我们要根据数据的情况,决定标签是否进行显示或者有其他动作。最常见的就是,表格渲染的时候,如果表格没有数据,就显示无数据。如果有数据就显示表格数据。 Vue帮我们提供了一个 v-if的指令,帮助我们完成判断的模板处理。

  • v-if

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
        <meta charset="UTF-8">
    
        <title></title>
    </head>
    <body>
    
        <div id="app">
            <h1 v-html="content" v-bind:style="col"></h1>
            <button @click="changeColor">更改颜色</button>
            <br>
            <button @click.enter="deleteEI">删除元素</button>
            <br>
            <span v-if="display">点击按钮会被删除</span>
    
        </div>
    
        <script>
            var app =new Vue({
                    el:'#app',
                    data:{
                        content:"<p>hello,</p><p>测开大佬</p>",
                        col:"color:blue",
                        display:true
                    },
                    methods:{ // methods下是组件的方法
                        changeColor:function () {
                            this.col="color:pink";
                            console.log("点击了一次按钮");
                        },
                        deleteEI:function () {
                            this.display=false;
                        }
                    }
                }
            )
        </script>
    </body>
    </html>
    
  • v-else

当if中的值,不为true时,执行v-else。

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>

    <meta charset="UTF-8">

    <title></title>
</head>
<body>

    <div id="app">
        <h1 v-html="content" v-bind:style="col"></h1>
        <button @click="changeColor">更改颜色</button>
        <br>
        <button @click.enter="deleteEI">删除元素</button>
        <br>
        <span v-if="display">点击按钮会被删除</span>
        <span v-else>点击按钮会显示</span>

    </div>

    <script>
        var app =new Vue({
                el:'#app',
                data:{
                    content:"<p>hello,</p><p>测开大佬</p>",
                    col:"color:blue",
                    display:true
                },
                methods:{ // methods下是组件的方法
                    changeColor:function () {
                        this.col="color:pink";
                        console.log("点击了一次按钮");
                    },
                    deleteEI:function () {
                        this.display=false;
                    }
                }
            }
        )
    </script>
</body>
</html>

  • v-show

    控制单个视图显示和隐藏

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
        <meta charset="UTF-8">
    
        <title></title>
    </head>
    <body>
    
        <div id="app">
            <h1 v-html="content" v-bind:style="col"></h1>
            <button @click="changeColor">更改颜色</button>
            <br>
            <button @click.enter="deleteEI">删除元素</button>
            <br>
            <span v-if="display">点击按钮会被删除</span>
            <span v-else>点击按钮会显示</span>
            <br>    
            <span v-show="display">点击按钮会被删除</span>
    
        </div>
    
        <script>
            var app =new Vue({
                    el:'#app',
                    data:{
                        content:"<p>hello,</p><p>测开大佬</p>",
                        col:"color:blue",
                        display:true
                    },
                    methods:{ // methods下是组件的方法
                        changeColor:function () {
                            this.col="color:pink";
                            console.log("点击了一次按钮");
                        },
                        deleteEI:function () {
                            this.display=false;
                        }
                    }
                }
            )
        </script>
    </body>
    </html>
    
    

    v-show 与v-if的区别:

    v-if是将display:false的元素移除了;v-show是给该元素添加一个display:none的属性

列表渲染

  • 基本v-for循环渲染标签 (一次渲染单个标签)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    
        <div id="app">
            <ul>
                <!--  循环ol标签,写在ol标签中  -->
                <ol v-for="item in fruit" :key="item.id">{{item.name}}</ol>
            </ul>
        </div>
    
        <script>
            var app =new Vue({
                    el:'#app',
                    data:{
                        content:"<p>hello,</p><p>测开大佬</p>",
                        col:"color:blue",
                        display:true,
                        fruit:[
                            {"id":"1","name":"apple"},
                            {"id":"2","name":"peal"},
                            {"id":"3","name":"orange"}
                        ]
                    }
                }
            )
        </script>
    </body>
    </html>
    
    
  • Template循环渲染多标签 (一次渲染单个标签)

    Vue给我们提供了template标签,供我们用于v-for循环中进行处理

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    
        <div id="app">
            <ul>
                <ol v-for="item in fruit" :key="item.id">{{item.name}}</ol>
            </ul>
      	  <!--  template标签循环渲染多标签  -->
            <ul>
                <template v-for="item in fruit" >
                    <!--  被重复渲染的标签,需要加key属性,防止重复渲染   -->
                    <span :key="item.id">水果名:{{item.name}}</span>
                    <span :key="item.id">产地:{{item.addr}}</span>
                    <br :key="item.id">
                </template>
            </ul>
        </div>
    
        <script>
            var app =new Vue({
                    el:'#app',
                    data:{
                        content:"<p>hello,</p><p>测开大佬</p>",
                        col:"color:blue",
                        display:true,
                        fruit:[
                            {"id":"1","name":"apple","addr":"陕西"},
                            {"id":"2","name":"peal","addr":"河南"},
                            {"id":"3","name":"orange","addr":"海南"}
                        ]
                    }
                }
            )
        </script>
    </body>
    </html>
    
    

什么是双向绑定

vue框架很核心的功能就是双向的数据绑定。 双向是指:HTML标签数据 绑定到 Vue对象,另外反方向数据也是绑定的。通俗点说就是,vue对象的改变会直接影响到HTML的标签的变化,而且标签的变化也会反过来影响Vue对象的属性的变化。

这样以来,就彻底变革了之前Dom的开发方式,之前Dom驱动的开发方式尤其是以jQuery为主的开发时代,都是dom变化后,触发js事件,然后在事件中通过js代码取得标签的变化,再跟后台进行交互,然后根据后台返回的结果再更新HTML标签,异常的繁琐。有了Vue这种双向绑定,让开发人员只需要关心json数据的变化即可,Vue自动映射到HTML上,而且HTML的变化也会映射回js对象上,开发方式直接变革成了前端由数据驱动的 开发时代,远远抛弃了Dom开发主导的时代了。

双向数据绑定

  • 使用v-model进行双向数据的绑定
<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<div id="app">
    <h1>{{msg}}</h1>
    <!-- 双向绑定 -->
    <input type="text" v-model="msg">
</div>

<script>
    var app =new Vue({
            el:'#app',
            data:{
                msg:"hello,world",
                content:"<p>hello,</p><p>测开大佬</p>",
                col:"color:blue",
                display:true,
                fruit:[
                    {"id":"1","name":"apple","addr":"陕西"},
                    {"id":"2","name":"peal","addr":"河南"},
                    {"id":"3","name":"orange","addr":"海南"}
                ]
            }
        }
    )
</script>
</body>
</html>

当修改掉输入框内的内容,也就是变量msg的内容时,上面的一级标题标签下的变量msg内容也会随之变化。

逻辑:在view层的数据改变(输入框内数据改变),通过viewmodel影响model层,model层的改变又直接反应在view层(h1标签下的msg变量)。

  • v-model修饰符

      <!-- 在每次 input 事件触发后将输入框的值与数据进行同步,添加 lazy 修饰符,从而转变为使用 change 事件进行同步 -->
      <input v-model.lazy="msg" >
      <!--去除字符串首尾的空格-->
      <input v-model.trim="msg">
      <!--将数据转化为值类型-->
      <input v-model.number="age" type="number">
    
  • 作业

    输入框+添加按钮,点击添加按钮,将输入框的内容显示在输入框下,以列表的形式,同时也是复选框,选中时为红色,不选中时为蓝色

    <!DOCTYPE html>
    <html lang="en" xmlns="http://www.w3.org/1999/html">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <meta charset="UTF-8">
        <style>
            /* 设置初始颜色  */
            li > span{
                color:blue;
            }
        </style>
        <title>添加功能</title>
    </head>
    <body>
        <div id="app">
            <span>{{msg}}</span>
            <div>
                <!--  v-model获取文本框输入的值  -->
                <input type="text" v-model="value">
                <!-- 绑定点击事件-->
                <button @click="addLi">添加</button>
            </div>
            <ul>
                <template v-for="item in valueItem" >
                    <li>
                        <!--   没有自定义id时,item.index相当于之前的id,避免重复渲染-->
                        <input type="checkbox" :key="item.index" v-model="item.checked">
                        <!--   给了一个对象,解析为color的值,不会去data中找-->
                        <span :key="item.index" :style="{color:item.checked?'red':'blue'}">{{item.value}}</span>
                    </li>
                </template>
            </ul>
        </div>
        <script>
            var vm = new Vue({
                //el表示挂载的元素
                el:"#app",
                data:{
                    msg:"hello,测开大佬们",
                    value:"",
                    valueItem:[],
                },
                methods:{
                    addLi:function () {
                        console.log(this.value)
                        // push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度
                        this.valueItem.push({value:this.value,checked:false})
                    }
                }
    
            })
        </script>
    </body>
    </html>
    

组件

组件其实就是一个拥有样式、动画、js逻辑、HTML结构的综合块。前端组件化确实让大的前端团队更高效的开发前端项目。而作为前端比较流行的框架之一,Vue的组件和也做的非常彻底,而且有自己的特色。尤其是她单文件组件开发的方式更是非常方便,而且第三方工具支持也非常丰富,社区也非常活跃,第三方组件也呈井喷之势。当然学习和使用Vue的组件也是我们的最重要的目标。

组件的创建

  • 使用vue.extend全局方法创建

    <body>
    <div id="mount-point"></div>
    <script>
    // 创建构造器
    var Profile = Vue.extend({
      // 新的对象的模板,所有子实例都会拥有此模板
      template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
      data: function () {   // 创建的Vue实例时,data可以是Object 也可以是Function,但是在扩展
        return {            // 的时候,data必须是一个函数,而且要返回值奥。
          firstName: 'Walter',
          lastName: 'White',
          alias: 'Heisenberg'
        }
      }
    })
    // 创建 Profile 实例,并挂载到一个元素上。
    // new Profile().$mount(css选择器)
    new Profile().$mount('#mount-point')
    // .$mount() 方法跟设置 el属性效果是一致的。
    </script>
    </body>
    

  • 使用Vue.component 创建

    <body>
    <div id="app">
        <!-- 还是使用 标签形式,引入自己的组件 -->
        <!-- 有点类似于,下面定义了方法,这里调用方法-->
        <mycom2></mycom2>
      </div>
    
      <script>
        // 注意:不论是哪种方式创建出来的组件,组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素
        Vue.component('mycom2', {
          template: '<div><h3>这是直接使用 Vue.component 创建出来的组件</h3><span>123</span></div>'
        })
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {}
        });
      </script>
      </body>
    

不过这种方式也有一个瑕疵,就是template 属性的值是HTML标签,而在软件中,并没有智能提示,容易出错,若使用这种方式,需要仔细,避免出错

另一个思路,我们可以在在被控制的 #app 外面使用 template 元素,定义组建的HTML模板结构,然后使用Vue.component 创建组件。

  • 模板结构定义在template标签中

    <div id="app">
        <!-- 还是使用 标签形式,引入自己的组件 -->
        <mycom2></mycom2>
      </div>
    
      <script>
        <!--注意:不论是哪种方式创建出来的组件,组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素-->
        Vue.component('mycom2', {
          template: '#tem'
        })
    <!--2.在被控制的 #app 外面使用 template 元素,定义组建的HTML模板结构-->
      <template id = "tem">
        <div>
          <h3>这是直接使用 Vue.component 创建出来的组件</h3> 
          <span>123</span>
        </div>
      </template>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {}
        });
      </script>
    

组件的注册

全局注册

使用Vue.component()注册一个全局组件,创建时就进行了注册。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id = 'app'>
    <tan></tan>
</div>
<script>
    //注册一个自定义组件
    Vue.component('tan',{
        template:`<button v-on:click='jump'>弹奏鱼尾纹{{count}}</button>`,
        //这里的data必须是一个方法,每次调用一个注册好的组件时,都会触发一个data方法
        data:function(){
            return {
                count:0
            }
        },
        methods:{
            jump:function(){
                this.count += 1
            }
        }
    })

    var vm = new Vue({
        el:"#app",
        data:{},

    })
</script>
</body>
</html>
局部注册

components 属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
    <div id="app">
        <tan></tan>
        <tan></tan>
    </div>

    <script>
        // 注册一个局部组件
        const tanComponent=({
            template:`<button v-on:click='jump'>跳一跳{{count}}</button>`,
            data:function(){
                return {
                    count:0
                }
            },
            methods:{
                    jump:function(){
                        this.count += 1;
                    }
                }
        })
        var vm=new Vue({
            el:'#app',
            data:{},
            methods:{},
            //局部注册
            components:{
                tan:tanComponent
            }
        })
    </script>
</body>
</html>
组件示例
  • 创建一个vue项目

    • vue create 项目名(项目名不能包含大写字母,必须全部小写)

    • 选择自定义选项配置

      按键盘上下键选择,空格选中/取消,按回车下一步,default: 使用默认设置,Manually: 自定义选项,我们选择自定义

    • 选择配置的内容

      选择您想要开始项目的Vue.js版本、选择router,这里版本使用2.x,2.x跟3.x还是有很多差异,截图时选错。

      选择ESLint with error prevention only作为代码检查、选择语法检查后保存

      把这些文件放在独立的文件里还是package.json里

      选择是否保存这套配置,选择是的话,需要命名

      等待一会,就会创建成功

    • 使用webstorm打开创建的项目

    • 启动项目

      双击serve (这个只有用命令行创建项目才会有)

      或者npm run serve,可访问http://localhost:8081/表示启动成功

  • 示例代码

    文件结构:

    App.vue

    <template>
      <div id="app">
    
        <!-- 注册组件后,可以直接当标签使用   -->
        <Tan></Tan>
      </div>
    </template>
    
    <script>
      //  1.导入第三方组件Tan
      import Tan from './views/base_demo/Tan'
      export default {
        name: "App",
        // 2. 注册组件
        components:{
          Tan
        }
      }
    </script>
    
    <style>
    </style>
    

    Tan.vue ,新建文件时,选择vue component

    <!--定义一个子组件-->
    <template>
        <!--  一个template下只能有一个div-->
        <div>
            <button v-on:click='jump'>跳一跳{{count}}</button>
        </div>
    </template>
    
    <script>
    
        export default {
            name: "Tan",
            //data要定义为一个方法,return那个数据
            data() {
                return{count:0}
            },
            methods:{
                jump(){
                    this.count += 1;
                }
            }
        }
    </script>
    
    <style scoped>
    
    </style>
    

    main.js

    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    
    Vue.config.productionTip = false
    
    new Vue({
      router,
      store,
      render: h => h(App)
    }).$mount('#app')
    

    组件Tan,在App中注册后,就可以直接在App中使用

    遇到的坑:新建文件时,没有vue component blog.csdn.net/meiko667/ar…

  • 谷歌vue插件简单使用(需要梯子)

    安装插件后重启浏览器

组件的通信

父子通信

父组件向子组件传递数据是通过prop传递的。

App.vue

<template>
  <div id="app">

    <!-- 注册组件后,可以直接当标签使用   -->
    <Parent></Parent>
  </div>
</template>

<script>
  //  1.导入父组件
  // import Tan from './views/base_demo/Tan'
  import Parent from "./views/组件间通信/父子同信/Parent";
  export default {
    name: "App",
    // 2. 注册父组件
    components:{
      Parent,
    }
  }
</script>
<style>
</style>

Child.vue

<!--子组件-->
<template>
    <div>
        {{message}}
    </div>
</template>

<script>
    export default {
        name: "Child",
        // prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
        props:{
            message:{
                type:String
            }
        },

    }
</script>

<style scoped>

</style>

Parent.vue

<!--父组件向子组件传递一个值-->

<template>
    <div>
        <button @click="sendmessage">点击给子组件传递数据</button>
        <!-- 调用子组件 ,通过属性message传给子组件 属性值要与子组件中的变量一致 -->
        <Child :message="cMsg"></Child>
    </div>
</template>

<script>
    // 导入子组件
    import Child from "./Child";
    export default {
        name: "Parent",
        // 注册组件
        components:{
            Child
        },
        data(){
            return {cMsg:""}
        },
        methods:{
            sendmessage(){
                this.cMsg = 'hello,儿子'

            }
        }
    }
</script>

<style scoped>

</style>

父传子:

  1. 子组件使用props定义属性,接收父组件传递的信息

  2. 父组件传递通过v-bind:绑定子组件中的message属性,给子组件传递信息

  3. 子组件接收到父组件传来的值,并使用

子父通信

子组件传递数据给父组件是通过$emit触发事件来做到的。

Child.vue

<!--子组件-->
<template>
    <div>
        <button @click="sendMessage">给父组件传递数据</button>
        {{message}}
    </div>
</template>

<script>
    export default {
        name: "Child",
        // prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
        props:{
            message:{
                type:String
            }
        },
        methods: {
            sendMessage(){
                console.log("子组件触发了一个事件")
                // 触发自定义事件
                this.$emit("getMessage","hello,粑粑")
            }
            }

    }
</script>

<style scoped>

</style>

Parent.vue

<!-- 父组件 -->
<!--父组件向子组件传递一个值-->

<template>
    <div>
        <button @click="sendmessage()">给子组件传递数据</button>
        {{msg}}
        <br>
        <!-- 调用子组件 ,通过属性message传给子组件 属性值要与子组件中的变量一致 -->
        <Child :message="cMsg" @getMessage="replay"></Child>
    </div>
</template>

<script>
    // 导入子组件
    import Child from "./Child";
    export default {
        name: "Parent",
        // 注册组件
        components:{
            Child
        },
        data(){
            return {cMsg:"",
            msg:""}
        },
        methods:{
            sendmessage(){
                this.cMsg = 'hello,儿子'

            },
            replay(value){
                this.msg = value
            }
        }
    }
</script>

<style scoped>

</style>

子传父:

  1. 父组件使用v-on监听自定义事件

  2. 子组件使用$.emit触发父组件中定义的事件,并把要传递的信息传递过去

  3. 子组件触发自定义事件后,就会执行该事件对应的方法。获取子组件传递过来的数据

兄弟通信

如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.emit触发事件,bus.on监听触发的事件。

  • 创建一个js文件

    bus.js

    import Vue from 'vue'
    
    var bus=new Vue(); // 1. 创建一个空的vue对象作为中转站(中央事件总线)
    
    export default bus;
    // 此时导出一个空的vue组件
    
  • 创建一个组件作为发送方

    BrotherOne.vue

    <template>
        <div>
            我是BrotherOne
            <button @click="sendTwo">给BrotherTwo发消息</button>
        </div>
    
    </template>
    
    <script>
        import bus from './bus'
        export default {
            name: "BrotherOne",
            data(){
                return{}
            },
            methods:{
                sendTwo(){
                    //触发事件
                    bus.$emit("sendToTwo","hello,two")
                }
            }
        }
    </script>
    
    <style scoped>
    
    </style>
    
  • 创建一个组件作为消息的接收方

    BrotherTwo.vue

    <template>
        <div>
            我是BrotherTwo
            <button @click="sendOne">给BrotherOne发消息</button>
            {{msg}}
        </div>
    </template>
    
    <script>
        import bus from './bus'
        export default {
            name: "BrotherTwo",
            data(){
                return{
                    msg:""
                }
            },
            methods:{
                sendOne(){
                    console.log("事件被触发")
                }
            },
            created() { //组件创建时会自动触发,以后学
                //监听事件
                bus.$on("sendToTwo", (value) => {this.msg = value})
            }
        }
    
    </script>
    
    <style scoped>
    
    </style>
    
任意组件通信

这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。

var Event=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});
跨级通信/爷孙通信
  • 简介

    Vue2.2.0新增API,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。一言而蔽之:祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

    需要注意的是:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的----vue官方文档 所以,上面 A.vue 的 name 如果改变了,B.vue 的 this.name 是不会改变的,仍然是 浪里行舟。

    低于2.2.0的版本,不能使用。

  • provide与inject 怎么实现数据响应式

    一般来说,有两种办法:

    • provide祖先组件的实例,然后在子孙组件中注入依赖,这样就可以在子孙组件中直接修改祖先组件的实例的属性,不过这种方法有个缺点就是这个实例上挂载很多没有必要的东西比如props,methods
    • 使用2.6最新API Vue.observable 优化响应式 provide(推荐)
  • 第一种示例

    第一种示例,provide 和 inject 绑定并不是可响应的,不能动态修改、动态传递

    • App.vue挂载GrandFather组件

    • 创建爷爷组件,通过provide存数据

      GrandFather.vue

      <!--爷爷组件-->
      <template>
          <div>
              <Parent></Parent>
          </div>
      
      </template>
      
      <script>
          import Parent from "./Parent";
          export default {
              name: "GrandFather",
              components:{
                  Parent,
              },
              // 创建一个provide 存储数据
              provide:{
                  data:"孙子,来家里玩呀"
              },
          }
      </script>
      
      <style scoped>
      
      </style>
      
    • 创建父组件,父组件不做任何操作,只引用它的子组件即可

      Parent.vue

      <template>
        <div>
            <Child></Child>
        </div>
      </template>
      
      <script>
          // 导入子组件
          import Child from "./Child";
          export default {
              name: "Parent",
              // 注册组件
              components:{
                  Child
              },
              data(){
                  return{}
              }
          }
      </script>
      
      <style scoped>
      
      </style>
      
    • 创建子组件,inject把数据注入data中

      Child.vue

      <!--子组件-->
      <template>
         <div>
             {{msg}}
         </div>
      </template>
      
      <script>
         export default {
             name: "Child",
             // inject注入数据,注入数据的名字是data,即爷爷组件中的provide下的参数
             inject:["data"],
             data(){
                 return{msg:this.data}
             }
         }
      </script>
      <style scoped>
      </style>
      
      ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d84cb11a35f5454397af7b3f9b57ed00~tplv-k3u1fbpfcp-zoom-1.image)
      
  • 第二种示例

    使用Vue.observable实现任意组件间传递数据

    • 新建store.js文件
    //store.js
    import Vue from 'vue';
    
    // 1. 创建observable时,预先把要使用的数据定义好,并写好set方法
    export let store =Vue.observable({data:''});
    export let mutations={
        //定义一个修改变量的方法
        setData(data){
            store.data=data;
        },
    };
    
    • 爷爷组件

      <!--爷爷组件-->
      <template>
          <div>
              <button @click="sendMsg">给孙子发消息</button>
              <Parent></Parent>
          </div>
      
      </template>
      
      <script>
          import Parent from "./Parent";
          // 导入mutations
          import {mutations} from './store.js'
          export default {
              name: "GrandFather",
              components:{
                  Parent,
              },
              methods:{
                  sendMsg(){
                      // 使用mutations的setData方法来改变数据
                      mutations.setData("孙子,来家里玩呀")
                  }
              }
          }
      </script>
      
      <style scoped>
      
      </style>
      
    • 父组件

    <!--父组件不做任何操作,只引用它的子组件即可-->
    
    <template>
       <div>
           <Child></Child>
       </div>
    </template>
    
    <script>
       // 导入子组件
       import Child from "./Child";
       export default {
           name: "Parent",
           // 注册组件
           components:{
               Child
           },
           data(){
               return{}
           }
       }
    </script>
    
    <style scoped>
    
    </style>
    
    • 子组件
    <!--子组件-->
    <template>
        <div>
            {{msg}}
        </div>
    </template>
    
    <script>
        // 数据存在store中的,所以导入store
        import {store} from './store'
        export default {
            name: "Child",
            // 计算属性,实时监控数据变化
            computed:{
                //变量名() {return 变量的值}
                //把store.data存到了msg这个变量里
                msg(){
                    return store.data
                }
            }
        }
    </script>
    <style scoped>
    </style>
    
    • App.vue
    <template>
      <div id="app">
        <!-- 注册组件后,可以直接当标签使用   -->
        <GrandFather></GrandFather>
      </div>
    </template>
    
    <script>
      //  1.导入组件
      import GrandFather from "./views/组件间通信/爷孙通信/GrandFather";
      export default {
        name: "App",
        // 2. 注册组件
        components:{
          GrandFather,
        }
      }
    </script>
    <style>
    </style>
    
    
    步骤
    
    - 创建observable对象时,预先把要使用的数据定义好,并写好set方法
    - 爷爷组件使用mutations存入数据
    - 孙子子组件通过计算属性,监控获取store.data中的数据
    

组件的slot

使用组件的时候,经常需要在父组件中为子组件中插入一些标签等。当然其实可以通过属性等操作,但是比较麻烦,直接写标签还是方便很多。 那么Vue提供了slot协助子组件对父容器写入的标签进行管理。

slot插槽,也就是槽,是组件的一块HTML模板,这块模板显示不显示,以及怎样显示由父组件来决定。

当父容器写了额外的内容时, 如果子组件恰好有一个slot标签,那边子容器的slot标签会被父容器写入的内容替换掉。

单个插槽

UserButton.vue

<template>
    <div>
        <!--中间的文字是无法传递的-->
        <NowButton>提交</NowButton>
    </div>
</template>

<script>
    import NowButton from "./NowButton";
    export default {
        name: "UserButton",
        components:{
            NowButton,
        }
        }
    }
</script>
<style scoped>
</style>

NowButton.vue

<template>
    <button class="btn1" name="btn1"></button>
</template>

<script>
    export default {
        name: "NowButton"
    }
</script>

<style scoped>
    /*设置颜色、背景色*/
    button{
        background-color: dodgerblue;
        color: white;
    }
</style>

此时,NowButton中间的“提交”是没法传递的。虽然可以使用父子通信的方式传递,比较麻烦,所以引入插槽的概念。

插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot>表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。

所以在NowButton.vue中使用<slot></slot>,父组件中的提交就可以传递过去。

效果:

具名插槽

UserButton.vue

把父组件中的内容改为 <NowButton><span>注册:</span><input type="text"></NowButton>

<template>
    <div>
        <NowButton><span>注册:</span><input type="text"></NowButton>
    </div>
</template>

<script>
    import NowButton from "./NowButton";
    export default {
        name: "UserButton",
        components:{
            NowButton,
        }
    }
</script>
<style scoped>
</style>

NowButton.vue

<template>
<!-- 两个插槽 -->
    <table>
        <tr>
            <td>
                <slot></slot>
            </td>
            <td>
                <slot></slot>
            </td>
        </tr>
    </table>
</template>

<script>
    export default {
        name: "NowButton"
    }
</script>

<style scoped>
</style>

此时,两个插槽都替换了父组件的标签效果:

如何指定某个数据放到哪个插槽?

假设我要span标签放入第一个插槽,input标签放入第二个插槽

给slot标签添加name属性

通过span标签、input标签添加slot属性关联

效果:

这种插槽叫做具名插槽,理解为有名字的插槽。父组件传值给子组件。

作用域插槽

父组件提供样式,子组件提供数据,这样就能实现子组件动态化展示(多态)

子组件传值给父组件。

UserButton.vue

<template>
    <div>
        <NowButton>
            <!--v-slot标签接收数据,v-slot:接收的组件的name="变量名"-->
            <template v-slot:label="c">
                <!-- <template #label="c"> v-slot:可以简写为#label-->
                <!--使用变量-->
                <span slot="label">{{c.value}}</span>
                <input slot="input" type="text">
            </template>
        </NowButton>
    </div>
</template>

<script>
    import NowButton from "./NowButton";
    export default {
        name: "UserButton",
        components:{
            NowButton,
        }
    }
</script>
<style scoped>
</style>

NowButton.vue

<template>
    <table>
        <tr>
            <td>
                <!-- v-bind通过属性传数据,只能传一个对象-->
                <slot name="label" v-bind='{value:"注册:"}'></slot>
            </td>
            <td>
                <slot name="input"></slot>
            </td>
        </tr>
    </table>
</template>

<script>
    export default {
        name: "NowButton"
    }
</script>

<style scoped>
</style>

组件状态保持

使用场景:比如,在网站填写资料时,点击下一步,跳转到下一页,此时点击上一步,返回上一页,你填写过的资料也仍然存在。如果没有保留组件状态。当从下一页返回上一页时,上一页的内容已被销毁了。

动态组件的切换过程中走的改变:切换走了->会销毁;切回来->重新构建(渲染)一次;所以组件状态不会保留

保留组件的状态,用keep-alive(模拟场景登录流程中的下一步下一步)

把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染

include - 字符串或正则表达式。只有匹配的组件会被缓存。

exclude - 字符串或正则表达式。任何匹配的组件都不会被缓存

<component></component>标签是Vue框架自定义的标签,它的用途就是可以动态绑定我们的组件,根据数据的不同更换不同的组件,根据is的值来决定那个组件被渲染

Login.vue

<template>
    <div>
        <!-- 使用keep-alive来保留组件的状态-->
        <keep-alive>
            <!--component是Vue框架自定义的标签,可以动态绑定我们的组件,根据is的值来渲染不同的组件-->
            <component :is="view"></component>
        </keep-alive>
        <!--点击时,view的值修改为Phone-->
        <button @click="view='Phone'">上一步</button>
        <!--点击时,view的值修改为CheckCode-->
        <button @click="view='CheckCode'">下一步</button>
    </div>
</template>

<script>
    import Phone from "./Phone";
    import CheckCode from "./CheckCode";
    export default {
        name: "Login",
        components:{
            Phone,
            CheckCode
        },
        data(){
           return {
               view:Phone
           }
        }

    }
</script>

<style scoped>

</style>

Phone.vue

<template>
    <div>
        <span>手机号:</span><input type="text">
    </div>

</template>

<script>
    export default {
        name: "Phone"
    }
</script>

<style scoped>

</style>

CheckCode.vue

<template>
    <div>
        <span>验证码:</span>
        <input type="text">
        <button>发送验证码</button>
    </div>
</template>

<script>
    export default {
        name: "CheckCode"
    }
</script>

<style scoped>

</style>

组件的异步加载

异步加载

Home.vue

<template>
    <div>
        <ComOne></ComOne>
        <ComTwo></ComTwo>
    </div>
</template>

<script>
    import Vue from 'vue'
    import ComOne from './ComOne'
    export default {
        name: "Home",
        components:{
            ComeOne,
            // 使用Vue.component重新注册
            // resolve,一个回调函数,即传入了一个回调函数
            ComeTwo:Vue.component("ComTwo",function (resolve) {
                //这里模拟接口长时间返回情况,实际应该定义要用的方法
                setTimeout(function () {
                    // 向resolve回调传递组件定义
                    require(['./ComTwo'], resolve)
                },3000)
                }

            )
        }
    }
</script>

<style scoped>

</style>

ComOne.vue

<template>
    <div>
        <h1>我是组件1</h1>
    </div>
</template>

<script>
    export default {
        name: "ComOne"
    }
</script>

<style scoped>

</style>

ComTwo.vue

<template>
    <div>
        <h1>我是组件2</h1>
    </div>
</template>

<script>
    export default {
        name: "ComTwo"
    }
</script>

<style scoped>

</style>
处理加载状态(未讲)

组件间数据共享

sessionStorage

sessionStorage 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。

提示: 如果你想在浏览器窗口关闭后还保留数据,可以使用 localStorage 属性, 改数据对象没有过期时间,今天、下周、明年都能用,除非你手动去删除。

1.方法

sessionStorage.key(int index) //返回当前 sessionStorage 对象的第index序号的key名称。若没有返回null。

sessionStorage.getItem(string key) //返回键名(key)对应的值(value)。若没有返回null。

sessionStorage.setItem(string key, string value) //该方法接受一个键名(key)和值(value)作为参数,将键值对添加到存储中;如果键名存在,则更新其对应的值。

sessionStorage.removeItem(string key) //将指定的键名(key)从 sessionStorage 对象中移除。

sessionStorage.clear() //清除 sessionStorage 对象所有的项。

2.存储数据

2.1 采用setItem()方法存储 sessionStorage.setItem(‘testKey’,‘这是一个测试的value值’); // 存入一个值

2.2 通过属性方式存储 sessionStorage[‘testKey’] = ‘这是一个测试的value值’;

2.3 存储Json对象 sessionStorage也可存储Json对象:存储时,通过JSON.stringify()将对象转换为文本格式;读取时,通过JSON.parse()将文本转换回对象。 var userEntity = { name: ‘tom’, age: 22 };

// 存储值:将对象转换为Json字符串 sessionStorage.setItem(‘user’, JSON.stringify(userEntity));

// 取值时:把获取到的Json字符串转换回对象 var userJsonStr = sessionStorage.getItem(‘user’); userEntity = JSON.parse(userJsonStr); console.log(userEntity.name); // => tom

3.读取数据

3.1 通过getItem()方法取值 sessionStorage.getItem(‘testKey’); // => 返回testKey对应的值

3.2 通过属性方式取值 sessionStorage[‘testKey’]; // => 这是一个测试的value值

Home.vue

<template>
    <div>
        <ComTwo></ComTwo>
        <button @click="getData">从sessionstorage中取数据</button>
    </div>
</template>

<script>
    import ComTwo from './ComTwo'
    export default {
        name: "Home",
        components:{
            ComTwo,
        },
        methods:{
            getData(){
                //打印token
                console.log(sessionStorage.getItem("token"))
                //取token
                sessionStorage.getItem("token")
            }
        }
    }
</script>

<style scoped>

</style>

ComeTwo.vue

<template>
    <div>
        <button @click="putData">存放数据至sessionStorage</button>
    </div>
</template>

<script>
    export default {
        name: "ComeTwo",
        methods:{
            putData(){
                //存token
                sessionStorage.setItem("token","asdbcdkhfewgh")
            }
        }
    }
</script>

<style scoped>

</style>

关闭标签页,点取数据,打印出null,说明sessionStorage 是临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。

LocalStorage
  • 什么是localStorage 对浏览器来说,使用 Web Storage 存储键值对比存储 Cookie 方式更直观,而且容量更大,它包含两种:localStorage 和 sessionStorage

    sessionStorage(临时存储) :为每一个数据源维持一个存储区域,在浏览器打开期间存在,包括页面重新加载

    localStorage(长期存储) :与 sessionStorage 一样,但是浏览器关闭后,数据依然会一直存在

    所以上次使用cookie的时候就遇到了一个坑,设置后马上访问session会获取不到,蛋疼,还需要刷新一下,原因是:

    当我们首次访问设置Cookie的页面时,服务器会把设置的Cookie值通过响应头发送过来,告诉浏览器将cookie存储的本地相应文件夹中(注意:第一次访问时本地还没有存储Cookie,所以此时获取不到值); 当第二次访问(或在进行cookie设置后,过期前所有的访问)时,请求头信息你中都会把Cookie值携带。(百度到的,暂时还没理解透彻,先搬过来).

  • 使用方法

    跟sessionStorage用法差不多,LocalStorage可以把数据永久存储。

    把上面sessionStorage的地方修改为LocalStorage,关闭标签页再点击第二个button,console中仍然能打印token,因为LocalStorage可以把数据永久存储。

    1.保存

    //对象
    
    const info = { name: 'hou', age: 24, id: '001' };
    
    //字符串
    
    const str="haha";
    
    localStorage.setItem('hou', JSON.stringify(info));
    
    localStorage.setItem('zheng', str);
    
    1. 获取
var data1 = JSON.parse(localStorage.getItem('hou'));

var data2 = localStorage.getItem('zheng');
  1. 删除(因为永久保存,所以需要删除他)
//删除某个
localStorage.removeItem('hou');
//删除所有
localStorage.clear();
  1. 监听
Storage 发生变化(增加、更新、删除)时的 触发,同一个页面发生的改变不会触发,只会监听同一域名下其他页面改变 Storage
window.addEventListener('storage', function (e) {
  console.log('key', e.key); console.log('oldValue', e.oldValue);
  console.log('newValue', e.newValue); console.log('url', e.url);
})

  1. 浏览器中查看
  2. vue中实践

根据我的需求来的一个默认记住上次选择的,很简单

添加数据的时候,下次添加默认记住我上次的选择

所以,在添加或者提交的时候存储值即可,

localStorage.setItem(‘projectId’,me.workhourData.projectId+","+me.workhourData.projectManager);

在打开新建页面的时候获取一下就好了,只需要判断非空就行

//记住上次选中的审核人
            if(localStorage.length>0){
                var mydata = localStorage.getItem('projectId');
                if(mydata!=null){
                    var arr3=mydata.split(",");
                    if(arr3[0]==me.workhourData.projectId){
                        me.workhourData.projectManager=arr3[1];
                    }
                }
            }

  1. 注意点
  • localStorage有效期是永久的。一般的浏览器能存储的是5MB左右。

  • sessionStorage api与localStorage相同。

  • sessionStorage默认的有效期是浏览器的会话时间(也就是说标签页关闭后就消失了)。

  • localStorage作用域是协议、主机名、端口。(理论上,不人为的删除,一直存在设备中)

  • sessionStorage作用域是窗口、协议、主机名、端口。 知道了这些知识点后,你的问题就很好解决了。

  • localStorage是window上的。所以不需要写this.localStorage,vue中如果写this,是指vue实例。会报错

  1. 把localStorage挂载到Vue实例中使用
Vue.prototype.setLocalValue = function(name, value) {
     if (window.localStorage) {
         localStorage.setItem(name, value);
     } else {
         alert('This browser does NOT support localStorage');
     }
 };
 Vue.prototype.getLocalValue = function (name) {
     const value = localStorage.getItem(name);
     if (value) {
         return value;
     } else {
         return '';
     }
 };

但是这个只能用于web端,如果项目包含移动端,就不能使用,所以跨平台的数据如何实现共享,使用vuex。

vuex
  • vuex的原理

  • vuex的使用

    • 安装vuex

      npm install vuex --save

      --save表示把依赖保存在package.json中

    • main.js文件中引入vux并使用

    import Vuex from 'vuex'
    Vue.use(Vuex)
    

    • 创建store并注册进app

      但,实际在项目创建时,因为我们选择创建了vue项目,所以实际早已引入了vuex 在项目文件下/store/index.js。所以,我们可以不在main.js文件中进行代码编写。将vuex和vue的配置分离。

      import Vue from 'vue'
      import Vuex from 'vuex'
      
      Vue.use(Vuex)
      
      export default new Vuex.Store({
        state: {
      
          data:null
        },
        mutations: {
      	//定义存放数据的方法
          setData(state,value){
            state.data =value
      
          }
        },
        actions: {
        },
        modules: {
        }
      })
      
    • 组件中使用

      ComTwo.vue

      <template>
      <div>
          <button @click="putData">存放数据</button>
      </div>
      </template>
      
      <script>
          export default {
              name: "ComeTwo",
              methods:{
                  putData(){
                      let a = {
                          token:"asdbcdkhfewgh"
                      }
        				//存放token
                      this.$store.commit("setData",a)
                  }
              }
          }
      </script>
      
      <style scoped>
      
      </style>
      

      Home.vue

      <template>
      <div>
          <ComTwo></ComTwo>
          <button @click="getData">取数据</button>
      </div>
      </template>
      
      <script>
          import ComTwo from './ComTwo'
          export default {
              name: "Home",
              components:{
                  ComTwo,
              },
              methods:{
                  getData(){
                      //取token
                      let a = this.$store.state.data
                      console.log(a)
                  }
              }
          }
      </script>
      
      <style scoped>
      
      </style>
      

vue实例化选项配置对象详解

el

限制: 只在由 new 创建的实例中遵守

提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标,也就是说Vue绑定数据到哪里去找。可以是CSS 选择器,也可以是一个 HTMLElement实例。

在实例挂载之后(生命周期的内容后面会详细讲的奥), 元素可以用 vm.$el 访问。

如果这个选项在实例化时有作用,实例将立即进入编译过程,否则,需要显式调用 vm.$mount() 手动开启编译。

// 几乎所有例子都用到这个,所以就不再赘述
var app = new Vue({
  el: '#app',
  ...
});
data

Vue的实例的数据对象data 我们已经用了很多了,数据绑定离不开data里面的数据。也是Vue的核心属性。 它是Vue绑定数据到HTML标签的数据源泉,另外Vue框架会自动监视data里面的数据变化,自动更新数据到HTML标签上去。本质原理是:Vue会自动将data里面的数据进行递归抓换成getter和setter,然后就可以自动更新HTML标签了,当然用getter和setter所以老的浏览器Vue支持的不够好。

  • data对象的类型:

    类型是Object或者Function。

    如果是组件对象中,data必须是Function类型。【后面学了组件后就明白了,暂时对组件先放放。】

  • 实例:

    // 创建普通的Vue实例
    var vm = new Vue({
      data: data
    })
    
    // 组件定义【后面会详细讲的】
    // Vue.extend() 中 data 必须是函数
    var Component = Vue.extend({
      data: function () {   //这里必须是函数!!!!
        return { a: 1 }
      }
    })
    
    
computed对象
  • 介绍

    Vue的计算属性(computed)的属性会自动混入Vue的实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。这就很强大了,再计算属性中定义的函数里面可以直接使用指向了vue实例的this,异常方便的啊。

  • 类型

    { 键:函数} { [key: string]: Function | { get: Function, set: Function } } 当然,可以省略setter,如果省略了setter,那么值就可以是普通函数,但是必须有返回值。

  • 官方的实例

    var vm = new Vue({
    data: { a: 1 },
    computed: {
      // 仅读取,值只须为函数
      aDouble: function () {
        return this.a * 2
      },
      // 读取和设置
      aPlus: {
        get: function () {
          return this.a + 1
        },
        set: function (v) {
          this.a = v - 1
        }
      }
    }
    })
    vm.aPlus   // -> 2
    vm.aPlus = 3
    vm.a       // -> 2
    vm.aDouble // -> 4
    
    
methods
  • 类型: { [key: string]: Function }

  • 详细:

    methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue 实例。

    注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。

  • 示例

var vm = new Vue({
   data: { a: 1 },
   methods: {
     plus: function () {
       this.a++
     }
   }
 })
 vm.plus()
 vm.a // 2
watch
  • 类型

    { [key: string]: string | Function | Object }

  • 详细

    一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。

  • 示例:

    var vm = new Vue({
      data: {
        a: 1,
        b: 2,
        c: 3
      },
      watch: {
        // 监控a变量变化的时候,自动执行此函数
        a: function (val, oldVal) {
          console.log('new: %s, old: %s', val, oldVal)
        },
        // 深度 watcher
        c: {
          handler: function (val, oldVal) { /* ... */ },
          deep: true
        }
      }
    })
    vm.a = 2 // -> new: 2, old: 1
    //注意,不应该使用箭头函数来定义 watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.updateAutocomplete 将是 undefined。