vue2

76 阅读7分钟

VUE基本语法

每个 Vue 应用都需要通过实例化 Vue 来实现。

语法格式如下:

 <!DOCTYPE html>
 <html>
 <head>
     <meta charset="utf-8">
     <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
     <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
 </head>
 <body>
 <div id="vue_det">
     <h1>site : {{site}}</h1>
     <h1>url : {{url}}</h1>
     <h1>{{details('')}}</h1>
     <h1>{{full}}</h1>
 </div>
 <script>
     Vue.config.devtools = true;
     var vm = new Vue({
         el: '#vue_det',
         data: {
             site: "菜鸟教程",
             url: "www.runoob.com",
             alexa: "10000"
         },
         methods: {
             details: () {
                 console.log('methods');
                 return  this.site + " - 学的不仅是技术,更是梦想!";
             }
         },
         computed: {
             full(){
                 console.log('computed');
                 return this.url + this.alexa
             }
         }
     })
 </script>
 </body>
 </html>
  • 一个页面只需要实例化一个VUE对象,使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。
  • el标识被vue接管的标签元素,只有被接管的标签中才能使用vue的指令或表达式
  • data 用于定义属性,实例中有三个属性分别为:site、url、alexa。
  • methods 用于定义的函数,可以通过 return 来返回函数值。
  • {{ }} 用于输出对象属性和函数返回值。

Vue.js 模板语法

插值
文本

数据绑定最常见的形式就是使用双大括号的文本插值:

 <span>Message: {{ msg }}</span>
原始 HTML

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html:

 ​
 <div id="app">
     <div v-html="message"></div>
 </div>
     
 <script>
 new Vue({
   el: '#app',
   data: {
     message: '<h1>hello world</h1>'
   }
 })
 </script>
属性

html标签中的属性的值,可以是用v-bind指令动态设置:

 <div id="app">
     <a v-bind:href="baidu">百度</a>
     <button v-bind:disabled="disabled">确定</button>
 </div>
 <script>
 new Vue({
   el: '#app',
   data: {
     baidu: 'www.baidu.com',
     disabled:true
   }
 })
 </script>
使用 JavaScript 表达式

Vue.js 都提供了完全的 JavaScript 表达式支持。

 <!DOCTYPE html>
 <html>
 <head>
     <meta charset="utf-8">
     <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
     <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
 </head>
 <body>
 <div id="app">
     {{5+5}}<br>
     {{ ok ? 'YES' : 'NO' }}<br>
     {{ message.split('').reverse().join('') }}
     <div v-bind:id="'list-' + id">菜鸟教程</div>
 </div>
     
 <script>
 new Vue({
   el: '#app',
   data: {
     ok: true,
     message: 'RUNOOB',
     id : 1
   }
 })
 </script>
 </body>
 </html>
指令

指令是带有 v- 前缀的特殊属性。

指令用于在表达式的值改变时,将某些行为应用到 DOM 上。如下例子:

 <div id="app">
     <p v-if="seen">现在你看到我了</p>
 </div>
     
 <script>
 new Vue({
   el: '#app',
   data: {
     seen: true
   }
 })
 </script>
参数

一些指令能够接收一个“参数”,在指令名称之后以冒号表示。

例如:

v-bind 指令可以用于响应式地更新 HTML attribute,v-on指令,它用于监听 DOM 事件:

 <a v-bind:href="url">...</a>
 <a v-on:click="doSomething">
修饰符

修饰符是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如, .prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()

 <form v-on:submit.prevent="onSubmit"></form>
用户输入

在 input 输入框中我们可以使用 v-model 指令来实现双向数据绑定:

 ​
 <div id="app">
     <p>{{ message }}</p>
     <input v-model="message">
 </div>
     
 <script>
 new Vue({
   el: '#app',
   data: {
     message: 'Runoob!'
   }
 })
 </script>
 ​

v-model指令用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。

按钮的事件我们可以使用 v-on 监听事件,并对用户的输入进行响应。

以下实例在用户点击按钮后对字符串进行反转操作:

 ​
 <div id="app">
     <p>{{ message }}</p>
     <button v-on:click="reverseMessage">反转字符串</button>
 </div>
     
 <script>
 new Vue({
   el: '#app',
   data: {
     message: 'Runoob!'
   },
   methods: {
     reverseMessage: function () {
       this.message = this.message.split('').reverse().join('')
     }
   }
 })
 </script>
过滤器

Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。由"管道符"指示, 格式如下:

 <!-- 在两个大括号中 -->
 {{ message | capitalize }}
 ​
 <!-- 在 v-bind 指令中 -->
 <div v-bind:id="rawId | formatId"></div>

过滤器函数接受表达式的值作为第一个参数。

以下实例对输入的字符串第一个字母转为大写:

 <div id="app">
   {{ message | capitalize }}
 </div>
     
 <script>
 new Vue({
   el: '#app',
   data: {
     message: 'runoob'
   },
   filters: {
     capitalize: function (value) {
       if (!value) return ''
       value = value.toString()
       return value.charAt(0).toUpperCase() + value.slice(1)
     }
   }
 })
 </script>

过滤器可以串联:

 {{ message | filterA | filterB }}

过滤器是 JavaScript 函数,因此可以接受参数:

 {{ message | filterA('arg1', arg2) }}

这里,message 是第一个参数,字符串 'arg1' 将传给过滤器作为第二个参数, arg2 表达式的值将被求值然后传给过滤器作为第三个参数。

缩写
v-bind 缩写

Vue.js 为两个最为常用的指令提供了特别的缩写:

 <!-- 完整语法 -->
 <a v-bind:href="url"></a>
 <!-- 缩写 -->
 <a :href="url"></a>
v-on 缩写
 <!-- 完整语法 -->
 <a v-on:click="doSomething"></a>
 <!-- 缩写 -->
 <a @click="doSomething"></a>

Vue.js 条件语句

条件判断
v-if

条件判断使用 v-if 指令:

 <div id="app">
     <p v-if="seen">现在你看到我了</p>
     <template v-if="ok">
       <h1>菜鸟教程</h1>
       <p>学的不仅是技术,更是梦想!</p>
       <p>哈哈哈,打字辛苦啊!!!</p>
     </template>
 </div>
     
 <script>
 new Vue({
   el: '#app',
   data: {
     seen: true,
     ok: true
   }
 })
 </script>

这里, v-if 指令将根据表达式 seen 的值(true 或 false )来决定是否插入 p 元素。

在字符串模板中,我们得像这样写一个条件块:

 <div>
 {{#if ok}}
   <h1>Yes</h1>
 {{/if}}
 </div>
v-else

可以用 v-else 指令给 v-if 添加一个 "else" 块:

 <div id="app">
     <div v-if="Math.random() > 0.5">
       Sorry
     </div>
     <div v-else>
       Not sorry
     </div>
 </div>
     
 <script>
 new Vue({
   el: '#app'
 })
 </script>
v-else-if
 <div id="app">
     <div v-if="type === 'A'">
       A
     </div>
     <div v-else-if="type === 'B'">
       B
     </div>
     <div v-else-if="type === 'C'">
       C
     </div>
     <div v-else>
       Not A/B/C
     </div>
 </div>
     
 <script>
 new Vue({
   el: '#app',
   data: {
     type: 'C'
   }
 })
 </script>

注意:v-else 、v-else-if 必须跟在 v-if 或者 v-else-if之后。

v-show

我们也可以使用 v-show 指令来根据条件展示元素:

 <h1 v-show="ok">Hello!</h1>

Vue.js 循环语句

循环使用 v-for 指令。

v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组并且 site 是数组元素迭代的别名。

v-for 可以绑定数据到数组来渲染一个列表:

 <div id="app">
   <ol>
     <li v-for="site in sites">
       {{ site.name }}
     </li>
   </ol>
 </div>
  
 <script>
 new Vue({
   el: '#app',
   data: {
     sites: [
       { name: 'Runoob' },
       { name: 'Google' },
       { name: 'Taobao' }
     ]
   }
 })
 </script>

板中使用 v-for:

 <ul>
   <template v-for="site in sites">
     <li>{{ site.name }}</li>
     <li>--------------</li>
   </template>
 </ul>
v-for 迭代对象

v-for 可以通过一个对象的属性来迭代数据:

 <div id="app">
   <ul>
     <li v-for="value in object">
     {{ value }}
     </li>
   </ul>
   <ul>
     <li v-for="item in list">
     {{ item.name }}
     </li>
   </ul>
 </div>
  
 <script>
 new Vue({
   el: '#app',
   data: {
     object: {
       name: '菜鸟教程',
       url: 'http://www.runoob.com',
       slogan: '学的不仅是技术,更是梦想!'
     },
     list:[
       {name: '菜鸟教程1',url: 'http://www.runoob.com',slogan: '学的不仅是技术,更是梦想!'},
       {name: '菜鸟教程2',url: 'http://www.runoob.com',slogan: '学的不仅是技术,更是梦想!'},
       {name: '菜鸟教程3',url: 'http://www.runoob.com',slogan: '学的不仅是技术,更是梦想!'}
     ]
   }
 })
 </script>

你也可以提供第二个的参数为键名:

 <div id="app">
   <ul>
     <li v-for="(value, key) in object">
     {{ key }} : {{ value }}
     </li>
   </ul>
 </div>

第三个参数为索引:

 <div id="app">
   <ul>
     <li v-for="(value, key, index) in object">
      {{ index }}. {{ key }} : {{ value }}
     </li>
   </ul>
 </div>
v-for 迭代整数

v-for 也可以循环整数

 <div id="app">
   <ul>
     <li v-for="n in 10">
      {{ n }}
     </li>
   </ul>
 </div>

Vue.js 计算属性

计算属性关键词: computed。

计算属性在处理一些复杂逻辑时是很有用的。

可以看下以下反转字符串的例子:

 <div id="app">
   {{ message.split('').reverse().join('') }}
 </div>

接下来我们使用计算属性来实现字符串反转的实例:

 <!DOCTYPE html>
 <html>
 <head>
     <meta charset="utf-8">
     <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
     <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
 </head>
 <body>
 <div id="app">
     <p>原始字符串: {{ message }}</p>
     <p>计算后反转字符串: {{ reversedMessage }}</p>
     <p>计算后反转字符串: {{ reversedMessage1 }}</p>
     <p>计算后反转字符串: {{ reversedMessage1 }}</p>
     <p>计算后反转字符串: {{ reversedMessage2() }}</p>
     <p>计算后反转字符串: {{ reversedMessage2() }}</p>
 </div>
 ​
 <script>
     var vm = new Vue({
         el: '#app',
         data: {
             message: 'Runoob!'
         },
         computed: {
             reversedMessage: {
                 // 计算属性的 getter
                 get() {
                     return this.message.split('').reverse().join('')
                 },
                 // 计算属性的 setter
                 set(value){
                     this.message=value
                 }
             },
             // 计算属性如果只需要getter,可直接简写
             reversedMessage1(){
                 console.log('调用了计算属性');
                 return this.message.split('').reverse().join('')
             }
         },
 ​
         methods: {
             reversedMessage2() {
                 console.log('调用了method方法');
                 return this.message.split('').reverse().join('')
             }
         }
     })
 </script>
 </body>
 </html>

实例中声明了一个计算属性 reversedMessage 。

提供的函数将用作属性 vm.reversedMessage 的 getter 。

vm.reversedMessage 依赖于 vm.message,在 vm.message 发生改变时,vm.reversedMessage 也会更新。

计算属性 vs methods方法

我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

Vue.js 监听属性

本章节,我们将为大家介绍 Vue.js 监听属性 watch,我们可以通过 watch 来响应数据的变化。

以下实例通过使用 watch 实现计数器:

 <div id = "app">
     <p style = "font-size:25px;">计数器: {{ counter }}</p>
     <button @click = "counter++" style = "font-size:25px;">点我</button>
 </div>
 <script type = "text/javascript">
 var vm = new Vue({
     el: '#app',
     data: {
         counter: 1
     }
 });
 vm.$watch('counter', function(nval, oval) {
     alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!');
 });
 </script>

以下实例进行千米之间的换算:

 <div id = "computed_props">
     千米 : <input type = "text" v-model = "kilometers">
     米 : <input type = "text" v-model = "meters">
 </div>
 <p id="info"></p>
 <script type = "text/javascript">
     var vm = new Vue({
     el: '#computed_props',
     data: {
         kilometers : 0,
         meters:0
     },
     methods: {
     },
     computed :{
     },
     watch : {
         kilometers:function(val) {
             this.kilometers = val;
             this.meters = this.kilometers * 1000
         },
         meters : function (val) {
             this.kilometers = val/ 1000;
             this.meters = val;
         }
     }
     });
     // $watch 是一个实例方法
     vm.$watch('kilometers', function (newValue, oldValue) {
     // 这个回调将在 vm.kilometers 改变后调用
     document.getElementById ("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
 })
 </script>

以上代码中我们创建了两个输入框,data 属性中, kilometers 和 meters 初始值都为 0。watch 对象创建了 data 对象的两个监控方法: kilometers 和 meters。

当我们再输入框输入数据时,watch 会实时监听数据变化并改变自身的值

Vue.js 样式绑定

Vue.js class

class 与 style 是 HTML 元素的属性,用于设置元素的样式,我们可以用 v-bind 来设置样式属性。

Vue.js v-bind 在处理 class 和 style 时, 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。

class 属性绑定

我们可以为 v-bind:class 设置一个对象,从而动态的切换 class:

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
 <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
 <style>
 .active {
   width: 100px;
   height: 100px;
   background: green;
 }
 </style>
 </head>
 <body>
 <div id="app">
   <div v-bind:class="{ 'active': isActive }"></div>
 </div>
 ​
 <script>
 new Vue({
   el: '#app',
   data: {
     isActive: true
   }
 })
 </script>
 </body>
 </html>

我们也可以在对象中传入更多属性用来动态切换多个 class 。

 <div class="static"
      v-bind:class="{ 'active' : isActive, 'text-danger' : hasError }">
 </div>

以上实例 div class 为:

 <div class="static active text-danger"></div>

我们也可以直接绑定数据里的一个对象:

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
 <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
 <style>
 .active {
   width: 100px;
   height: 100px;
   background: green;
 }
 .text-danger {
   background: red;
 }
 </style>
 </head>
 <body>
 <div id="app">
   <div v-bind:class="classObject"></div>
 </div>
 ​
 <script>
 new Vue({
   el: '#app',
   data: {
     classObject: {
       active: true,
       'text-danger': true
     }
   }
 })
 </script>
 </body>
 </html>

此外,我们也可以在这里绑定返回对象的计算属性。这是一个常用且强大的模式:

 new Vue({
   el: '#app',
   data: {
     isActive: true,
     error: {
       value: true,
       type: 'fatal'
     }
   },
   computed: {
     classObject: function () {
       return {
   base: true,
         active: this.isActive && !this.error.value,
         'text-danger': this.error.value && this.error.type === 'fatal',
       }
     }
   }
 })
数组语法

我们可以把一个数组传给 v-bind:class ,实例如下:

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
 <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
 <style>
 .active {
   width: 100px;
   height: 100px;
   background: green;
 }
 .text-danger {
   background: red;
 }
 </style>
 </head>
 <body>
 <div id="app">
   <div v-bind:class="[activeClass, errorClass]"></div>
 </div>
 ​
 <script>
 new Vue({
   el: '#app',
   data: {
     activeClass: 'active',
     errorClass: 'text-danger'
   }
 })
 </script>
 </body>
 </html>

我们还可以使用三元表达式来切换列表中的 class :

 <div v-bind:class="[errorClass ,isActive ? activeClass : '']"></div>
Vue.js style(内联样式)

我们可以在 v-bind:style 直接设置样式:

 <div id="app">
     <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">菜鸟教程</div>
 </div>

以上实例 div style 为:

 <div style="color: green; font-size: 30px;">菜鸟教程</div>

v-bind:style 可以使用数组将多个样式对象应用到一个元素上:

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
 <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
 </head>
 <body>
 <div id="app">
   <div v-bind:style="styleObject">菜鸟教程</div>
 </div>
 ​
 <script>
 new Vue({
   el: '#app',
   data: {
     styleObject: {
       color: 'green',
       fontSize: '30px'
     }
   }
 })
 </script>
 </body>
 </html>

Vue.js 事件处理器

事件监听可以使用 v-on 指令:

 <div id="app">
   <button v-on:click="counter += 1">增加 1</button>
   <p>这个按钮被点击了 {{ counter }} 次。</p>
 </div>
  
 <script>
 new Vue({
   el: '#app',
   data: {
     counter: 0
   }
 })
 </script>

通常情况下,我们需要使用一个方法来调用 JavaScript 方法。

v-on 可以接收一个定义的方法来调用。

 <div id="app">
    <!-- `greet` 是在下面定义的方法名 -->
   <button v-on:click="greet">Greet</button>
 </div>
  
 <script>
 var app = new Vue({
   el: '#app',
   data: {
     name: 'Vue.js'
   },
   // 在 `methods` 对象中定义方法
   methods: {
     greet: function (event) {
       // `this` 在方法里指当前 Vue 实例
       alert('Hello ' + this.name + '!')
       // `event` 是原生 DOM 事件
       if (event) {
           alert(event.target.tagName)
       }
     }
   }
 })
 // 也可以用 JavaScript 直接调用方法
 app.greet() // -> 'Hello Vue.js!'
 </script>

调用method方式可以带参数:

 <div id="app">
   <button v-on:click="say1('hi')">Say hi</button>
   <button v-on:click="say2($event,'what')">Say what</button>
 </div>
  
 <script>
 new Vue({
   el: '#app',
   methods: {
     say1: function (message) {
       alert(message)
     },
     say2: function (e,message) {
       alert(e.target.tagName)
       alert(message)
     }
   }
 })
 </script>
事件修饰符

Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。

Vue.js 通过由点 . 表示的指令后缀来调用修饰符。

  • .stop - 阻止冒泡

  • .prevent - 阻止默认事件

  • .capture - 捕获模式

  • .self - 只监听触发该元素的事件

  • .once - 只触发一次

  • .left - 左键事件

  • .right - 右键事件

  • .middle - 中间滚轮事件

     <!-- 阻止单击事件冒泡 -->
     <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>
     ​
     <!-- click 事件只能点击一次,2.1.4版本新增 -->
     <a v-on:click.once="doThis"></a>
    
    
按键修饰符

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">

全部的按键别名:

  • .enter
  • .tab
  • .delete (捕获 "删除" 和 "退格" 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta

实例

 <p><!-- Alt + C -->
 <input @keyup.alt.67="clear">
 <!-- Ctrl + Click -->
 <div @click.ctrl="doSomething">Do something</div>

Vue.js 表单

这节我们为大家介绍 Vue.js 表单上的应用。

你可以用 v-model 指令在表单控件元素上创建双向数据绑定。

v-model 会根据控件类型自动选取正确的方法来更新元素。

 <div id="app">
   <p>input 元素:</p>
   <input v-model="message" placeholder="编辑我……">
   <p>消息是: {{ message }}</p>
     
   <p>textarea 元素:</p>
   <p style="white-space: pre">{{ message2 }}</p>
   <textarea v-model="message2" placeholder="多行文本输入……"></textarea>
 </div>
  
 <script>
 new Vue({
   el: '#app',
   data: {
     message: 'Runoob',
     message2: '菜鸟教程\r\nhttp://www.runoob.com'
   }
 })
 </script>
复选框

复选框如果是一个为逻辑值,如果是多个则绑定到同一个数组:

 <div id="app">
   <p>单个复选框:</p>
   <input type="checkbox" id="checkbox" v-model="checked">
   <label for="checkbox">{{ checked }}</label>
     
   <p>多个复选框:</p>
   <input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
   <label for="runoob">Runoob</label>
   <input type="checkbox" id="google" value="Google" v-model="checkedNames">
   <label for="google">Google</label>
   <input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
   <label for="taobao">taobao</label>
   <br>
   <span>选择的值为: {{ checkedNames }}</span>
 </div>
  
 <script>
 new Vue({
   el: '#app',
   data: {
     checked : false,
     checkedNames: []
   }
 })
 </script>
单选按钮

以下实例中演示了单选按钮的双向数据绑定:

 <div id="app">
   <input type="radio" id="runoob" value="Runoob" v-model="picked">
   <label for="runoob">Runoob</label>
   <br>
   <input type="radio" id="google" value="Google" v-model="picked">
   <label for="google">Google</label>
   <br>
   <span>选中值为: {{ picked }}</span>
 </div>
  
 <script>
 new Vue({
   el: '#app',
   data: {
     picked : 'Runoob'
   }
 })
 </script>
select 列表

以下实例中演示了下拉列表的双向数据绑定:

 <div id="app">
   <select v-model="selected" name="fruit">
     <option value="">选择一个网站</option>
     <option value="www.runoob.com">Runoob</option>
     <option value="www.google.com">Google</option>
   </select>
  
   <div id="output">
       选择的网站是: {{selected}}
   </div>
 </div>
  
 <script>
 new Vue({
   el: '#app',
   data: {
     selected: '' 
   }
 })
 </script>
修饰符
.lazy

在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:

 <!-- 在 "change" 而不是 "input" 事件中更新 -->
 <input v-model.lazy="msg" >
.number

如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:

 <input v-model.number="age" type="number">
.trim

如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:

 <input v-model.trim="msg">

vue组件传值

props/$emit父子组件传值:

父传子:

  • 父组件:
  <template>
    <div id="app">
      <Home :msg="msg"></Home>
    </div>
  </template>

  <script lang="ts">
  import Vue from 'vue';
  import Home from '@/views/Home';

  export default Vue.extend({
    name: 'App',
    components: {
      Home
    },
    data(){
        return {
            msg:"我是父元素传过来的值"
        }
    }
  });
  </script>
  • 子组件
  <template>
    <div class="home">
      {{msg}}
    </div>
  </template>

  <script>
  export default {
    name: 'Home',
    components: {

    },
    props:{
        msg:String,
    }
  }

子传父:(是通过事件传值来进行具体实现的)

  • 子组件:
  <template>
    <div class="home">
      <button @click="toValue">点击</button>
    </div>
  </template>

  <script>
  export default {
    name: 'Home',
    components: {

    },
    methods:{
        toValue(){
            this.$emit("receive","我是子组件传过来的值");
        }
    }
  }
  </script>
  • 父组件:
  <template>
    <div id="app">
       <p>{{msg}}</p>
      <Home @receive="receive"></Home>
    </div>
  </template>

  <script lang="ts">
  import Vue from 'vue';
  import Home from '@/views/Home';

  export default Vue.extend({
    name: 'App',
    components: {
      Home
    },
    data(){
        return {
            msg:'',
        }
    },
    methods:{
        receive(val){
            this.msg = val;
        }
    }
  });
  </script>

ref与parent/ parent/parent/children父子组件传值:

父传子:

  • 父组件
  <template>
    <div id="app">
      <Home ref="home"></Home>
      <button @click="toValue">点击</button>
    </div>
  </template>

  <script lang="ts">
  import Vue from 'vue';
  import Home from '@/views/Home';

  export default Vue.extend({
    name: 'App',
    components: {
      Home
    },
    data(){
        return {
            msg:'',
        }
    },
    methods:{
       toValue(){
          this.msg = "这是父组件的值";
          this.$refs.home.setMsg(this.msg);
       }
    }
  });
  </script>
  • 子组件:
  <template>
    <div class="home">
      {{msg}}
    </div>
  </template>

  <script>
  export default {
    name: 'Home',
    components: {

    },
    data(){
        return {
            msg:''
        }
    },
    methods:{
        setMsg(val){
            this.msg = val;
        }
    }
  }
  </script>

子传父:

  • 子组件(如果子组件是公共组件,需判断父组件是否具有该方法)
  <template>
    <div class="home">
      <button @click="setMsg">点击</button>
    </div>
  </template>

  <script>
  export default {
    name: 'Home',
    components: {

    },
    data(){
        return {
            msg:'这是子组件的值'
        }
    },
    methods:{
        setMsg(){
            this.$parent.toValue(this.msg);
        }
    }
  }
  </script>
  • 父组件
  <template>
    <div id="app">
      {{msg}}
      <Home></Home>
    </div>
  </template>

  <script lang="ts">
  import Vue from 'vue';
  import Home from '@/views/Home';

  export default Vue.extend({
    name: 'App',
    components: {
      Home
    },
    data(){
        return {
            msg:'',
        }
    },
    methods:{
       toValue(val){
          this.msg = val;
       }
    }
  });
  </script>

attrs/ attrs/attrs/listeners隔代组件传值(爷孙组件参数互传)

爷传孙

  • 爷组件
  <template>
    <div id="app">
      <Home :msg="msg"></Home>
    </div>
  </template>

  <script lang="ts">
  import Vue from 'vue';
  import Home from '@/views/Home';

  export default Vue.extend({
    name: 'App',
    components: {
      Home
    },
    data(){
        return {
            msg:'这是爷组件的值'
        }
    }
  });
  </script>
  • 父组件(父组件的操作最简单,但不做就会传不过去)
  <template>
    <div class="home">
      <Sun v-bind="$attrs"></Sun>
    </div>
  </template>

  <script>
  import Sun from './component/Sun.vue'
  export default {
    name: 'Home',
    components: {
      Sun
    },
  }
  </script>
  • 孙组件
  <template>
    <div class="sun">
      {{msg}}
    </div>
  </template>

  <script>
  export default {
    name: 'Sun',
    props:{
        msg:String,
    }
  }
  </script>

孙传爷:

  • 孙组件
  <template>
    <div class="sun">
      <button @click="toVal">点我</button>
    </div>
  </template>

  <script>
  export default {
    name: 'Sun',
    data(){
        return {
            msg:"这是孙组件的值",
        }
    },
    methods:{
        toVal(){
            this.$emit("setVal",this.msg)
        }
    }
  }
  </script>
  • 父组件
  <template>
    <div class="home">
      <Sun v-on="$listeners"></Sun>
    </div>
  </template>

  <script>
  import Sun from './component/Sun.vue'
  export default {
    name: 'Home',
    components: {
      Sun
    },
  }
  </script>
  • 爷组件
  <template>
    <div id="app">
       <p>{{msg}}</p>
      <Home @setVal="setVal"></Home>
    </div>
  </template>

  <script lang="ts">
  import Vue from 'vue';
  import Home from '@/views/Home';

  export default Vue.extend({
    name: 'App',
    components: {
      Home
    },
    data(){
        return {
            msg:''
        }
    },
    methods:{
        setVal(val){
            this.msg = val;
        }
    }
  });
  </script>

provide/inject隔代组件传值(祖先组件传给其任意后代元素)

提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。如果传入的值是字符串,数字,布尔值等基本类型则会无响应!!!

爷传孙(所有后代组件都能拿到该值,但传动态值必须是个对象!!!)

  • 祖先组件(其实不用写那个事件就能完成传值)
  <template>
    <div id="app">
      <button @click="setVal">点击</button>
      <Home></Home>
    </div>
  </template>

  <script lang="ts">
  import Vue from 'vue';
  import Home from '@/views/Home';

  export default Vue.extend({
    name: 'App',
    components: {
      Home
    },
    provide(){
        return {
            data:this.dataObj
        }
    },
    data(){
        return {
            dataObj:{
                msg:'这是爷组件的值',
                num:1
            }
        }
    },
    methods:{
        setVal(){
            this.dataObj.num++;
        }
    }
  });
  </script>
  • 后代组件(任意一个后代元素通过该写法都能拿到值)
  <template>
    <div class="sun">
      <p>{{txt}}</p>
    </div>
  </template>

  <script>
  export default {
    name: 'Sun',
    inject:['data'],
	computed:{
		txt(){
			return `${this.data.msg}${this.data.num}`;
		}
	}
  }
  </script>

兄弟组件传值——vuex:(不仅仅局限于兄弟组件)

  • 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');
  • store/index.js
  import Vue from 'vue';
  import Vuex from 'vuex';

  Vue.use(Vuex);

  const num = {
      state: {//初始化值
            num:0,
      },
      getters:{//获取值
            num:state => state.num
      },
      mutations: {//设置值
            num:state => state.num++
      },
      actions: {//异步
          num ({ commit }) {
              setTimeout(() => {
                  commit('num')
              }, 1000)
          }
      }
  }
  export default new Vuex.Store({
    modules: {//模块儿
        num:num
    },
  });
  • 任意组件
  <template>
      <div id="app">
        <button @click="setVal">点击</button>
        <Home></Home>
      </div>
  </template>

  <script lang="ts">
    import Vue from 'vue';
    import vuex from 'vuex'
    import Home from '@/views/Home';

    export default Vue.extend({
      name: 'App',
      components: {
        Home
      },
      methods:{
          setVal(){
              this.$store.commit("num");//设置值
              console.log(this.$store.getters.num);//获取值
          }
      }
    });
    </script>
  • 更简单的获取方式:

一般情况下使用会报mapGetters is not defined的错误,先说解决方案吧!

  1.安装:npm isntall --save-dev  babel-preset-stage-3
  2.引入方法改写:import {mapGetters} from 'vuex';
  • 设置值的组件:
<template>
    <div id="app">
      <button @click="setVal">点击</button>
      <Home></Home>
    </div>
</template>

<script lang="ts">
  import Vue from 'vue';
  import vuex from 'vuex'
  import Home from '@/views/Home';

  export default Vue.extend({
    name: 'App',
    components: {
      Home
    },
    methods:{
        setVal(){
            this.$store.commit("num");
        }
    }
  });
  </script>
  • 获取值的组件:
  <template>
      <div class="sun">
          <p>{{num}}</p>
      </div>
  </template>

  <script>
      import {mapGetters} from 'vuex';
      export default {
          name: 'Sun',
          computed: {
              ...mapGetters(["num"])
          }
      }
  </script>

存在的问题:1. 页面刷新数据丢失;2.只在当前用户的浏览器中存在

兄弟组件通信EventBus

调用完之后必须销毁,否则会出现bug!!!

  • src/tools/event-bus.js(建文件)
  import Vue from 'vue'
  export const Bus = new Vue()
  • 事件总线:
  <template>
      <div id="app">
          <button @click="setVal">点击</button>
          <Home></Home>
      </div>
  </template>

  <script lang="ts">
      import Vue from 'vue';
      import {Bus} from '@/tools/event-bus'
      import Home from '@/views/Home';

      export default Vue.extend({
          name: 'App',
          components: {
              Home
          },
          data() {
              return {
                  msg: 0
              }
          },
          methods: {
              setVal() {
                  this.msg++;
                  Bus.$emit("share", this.msg);
              }
          }
      });
  </script>
  • 事件接收:
  <template>
      <div class="sun">
          <p>{{msg}}</p>
      </div>
  </template>

  <script>
      import { Bus } from '@/tools/event-bus'
      export default {
          name: 'Sun',
          data(){
              return {
                  msg:''
              }
          },
          methods:{
              setMsg(){
                  Bus.$on("share",(data)=>{
                      this.msg = data;
                  })
              }
          },
          created() {
              this.setMsg();
          },
          destroyed(){
              Bus.$off("share");
          }
      }
  </script>