Vue.js 学习笔记(一、基础知识)

一、Vue.js 安装

1、独立版本 --> Vue.js 的官网上直接下载 vue.min.js并用<script>标签引入。
2、使用 CDN 方法:
Staticfile CDN(国内) : https://cdn.staticfile.org/vue/2.2.2/vue.min.js
unpkg:https://unpkg.com/vue/dist/vue.js, 会保持和 npm 发布的最新的版本一致。
cdnjs : https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js
3、NPM 方法
npm 安装速度较慢,可以使用淘宝的镜像及其命令 cnpm。npm 版本需要大于 3.0,如果低于此版本需要升级它,在用 Vue.js 构建大型应用时推荐使用 NPM 安装。

# 查看版本
$ npm -v
2.3.0

#升级 npm
cnpm install npm -g
 
# 升级或安装 cnpm
npm install cnpm -g
 
# 最新稳定版
$ cnpm install vue

4、命令行工具
Vue.js 提供一个官方命令行工具,可用于快速搭建大型单页应用。

# 全局安装 vue-cli
$ cnpm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 这里需要进行一些配置,默认回车即可
This will install Vue 2.x version of the template.
 
For Vue 1.x use: vue init webpack#1.0 my-project
 
? Project name my-project
? Project description A Vue.js project
? Author runoob <[email protected]>
? Vue build standalone
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Setup unit tests with Karma + Mocha? Yes
? Setup e2e tests with Nightwatch? Yes
 
   vue-cli · Generated "my-project".
 
   To get started:
   
     cd my-project
     npm install
     npm run dev
   
   Documentation can be found at https://vuejs-templates.github.io/webpack

进入项目,安装并运行:

$ cd my-project
$ cnpm install
$ cnpm run dev
 DONE  Compiled successfully in 4388ms
 
> Listening at http://localhost:8080

二、Vue.js 目录结构

在 IDE(Eclipse、Atom等) 中打开该目录,结构如下所示:
在这里插入图片描述
src/APP.vue:

<!-- 展示模板 -->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <hello></hello>
  </div>
</template>
 
<script>
// 导入组件
import Hello from './components/Hello'
 
export default {
  name: 'app',
  components: {
    Hello
  }
}
</script>
<!-- 样式代码 -->
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

三、Vue.js 起步

每个 Vue 应用都需要通过实例化 Vue 来实现。语法如下:

var vm = new Vue({
  // 选项
})

先来看一段代码了解一下Vue构造器需要的内容:

<div id="vue_det">
    <h1>site : {{site}}</h1> <!-- {{ }} 用于输出对象属性和函数返回值。 -->
    <h1>url : {{url}}</h1>
    <h1>{{details()}}</h1>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: '#vue_det', // DOM 元素中的 id
        data: { // 定义属性
            site: "菜鸟教程",
            url: "www.runoob.com",
            alexa: "10000"
        },
        methods: { // 定义的函数,可以通过 return 来返回函数值。
            details: function() {
                return  this.site + " - 学的不仅是技术,更是梦想!";
            }
        }
    })
</script>

Vue 实例被创建时,向 Vue 的响应式系统中加入了其 data 对象中能找到的所有的属性。当这些属性的值发生改变时,html 视图将也会产生相应的变化。如下所示:

<div id="vue_det">
    <h1>site : {{site}}</h1>
    <h1>url : {{url}}</h1>
    <h1>Alexa : {{alexa}}</h1>
</div>
<script type="text/javascript">
// 我们的数据对象
var data = { site: "菜鸟教程", url: "www.runoob.com", alexa: 10000}
var vm = new Vue({
    el: '#vue_det',
    data: data
})
// 它们引用相同的对象!
document.write(vm.site === data.site) // true
document.write("<br>")
// 设置属性也会影响到原始数据
vm.site = "Runoob"
document.write(data.site + "<br>") // Runoob
 
// ……反之亦然
data.alexa = 1234
document.write(vm.alexa) // 1234
</script>

Vue 实例还提供了一些有用的实例和方法,它们都有前缀 $,以便与用户定义的属性区分开来。例如:

<div id="vue_det">
    <h1>site : {{site}}</h1>
    <h1>url : {{url}}</h1>
    <h1>Alexa : {{alexa}}</h1>
</div>
<script type="text/javascript">
// 我们的数据对象
var data = { site: "菜鸟教程", url: "www.runoob.com", alexa: 10000}
var vm = new Vue({
    el: '#vue_det',
    data: data
})
 
document.write(vm.$data === data) // true
document.write("<br>") // true
document.write(vm.$el === document.getElementById('vue_det')) // true
</script>

四、Vue.js 模板语法

1、插值

文本 - 数据绑定最常见的形式就是使用 {{…}}(双大括号)的文本插值。

<div id="app">
  <p>{{ message }}</p>
</div>

HTML - 使用 v-html 指令用于输出 html 代码。

<div id="app">
    <div v-html="message"></div>
</div>
    
<script>
new Vue({
  el: '#app',
  data: {
    message: '<h1>菜鸟教程</h1>'
  }
})
</script>

属性 - HTML 属性中的值应使用 v-bind 指令。

<div id="app">
	<label for="r1">修改颜色</label><input type="checkbox" v-model="class1" id="r1">
 	<br><br>
 	<div v-bind:class="{'class1': class1}">
    	v-bind:class 指令
  	</div>
</div>
    
<script>
new Vue({
    el: '#app',
  	data:{
    	class1: false
  	}
});
</script>

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

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

2、指令

指令 - 带有 v- 前缀的特殊属性,用于在表达式的值改变时,将某些行为应用到 DOM 上。

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

参数 - 参数在指令后以冒号指明。例如, v-bind 指令被用来响应地更新 HTML 属性。

<div id="app">
    <pre><a v-bind:href="url">菜鸟教程</a></pre>
</div>
    
<script>
new Vue({
  el: '#app',
  data: {
    url: 'http://www.runoob.com'
  }
})
</script>

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

<form v-on:submit.prevent="onSubmit"></form>

3、用户输入

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 指令用来在 inputselecttextcheckboxradio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。
按钮的事件我们可以使用 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>

4、过滤器

Vue.js 允许自定义过滤器,被用作一些常见的文本格式化,由"管道符"指示,过滤器函数接受表达式的值作为第一个参数,过滤器可以串联,过滤器是 JavaScript 函数,因此可以接受参数。

<!-- 在两个大括号中 -->
{{ 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 }}

{{ message | filterA('arg1', arg2) }} // message - 第一个参数;字符串 'arg1' 将传给过滤器作为第二个参数, arg2 表达式的值将被求值然后传给过滤器作为第三个参数。

5、缩写

Vue.js 为两个最为常用的指令提供了特别的缩写 --> v-bindv-on

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

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

五、Vue.js 条件与循环

1、条件判断

v-ifv-elsev-else-ifv-show

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

<!-- Handlebars 模板 -->
{{#if ok}}
  <h1>Yes</h1>
{{/if}}

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

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

2、循环语句

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

<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 迭代对象 -->
<div id="app">
  <ul>
    <li v-for="value in object"> {{ value }} </li>
  </ul>
</div>
<script>
	new Vue({ el: '#app', data: { object: { name: '菜鸟教程', 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 循环整数 -->
<div id="app">
  <ul>
    <li v-for="n in 10"> {{ n }} </li>
  </ul>
</div>

六、Vue.js 计算属性

计算属性关键词:computed

<div id="app">
  <p>原始字符串: {{ message }}</p>
  <p>计算后反转字符串: {{ reversedMessage }}</p>
</div>
 
<script>
var vm = new Vue({
  el: '#app',
  data: { message: 'hello world!' },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})
</script>

1、computed vs methods

methods可替换computed,效果上两者一致。
computed - 基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。(性能比较好些)
methods - 重新渲染的时候,函数总会重新调用执行。

methods: {
  reversedMessage2: function () {
    return this.message.split('').reverse().join('')
  }
}

2、computed setter

computed 属性默认只有 getter ,可自定义提供一个 setter

var vm = new Vue({
  el: '#app',
  data: { name: 'Google', url: 'http://www.google.com'  },
  computed: {
    site: {
      // getter
      get: function () { return this.name + ' ' + this.url; },
      // setter
      set: function (newValue) {
        var names = newValue.split(' ');
        this.name = names[0];
        this.url = names[names.length - 1];
      }
    }
  }
})
// 调用 setter, vm.name 和 vm.url 也会被对应更新
vm.site = '菜鸟教程 http://www.runoob.com';
document.write('name: ' + vm.name);
document.write('<br>');
document.write('url: ' + vm.url);

七、Vue.js 监听属性

Vue.js 可以通过 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 = val * 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>

八、Vue.js 样式绑定

1、Vue.js class

Vue.js 可用 v-bind 来设置样式属性,表达式的结果类型除了字符串之外,还可以是对象或数组。

2、class 属性绑定

v-bind:class 设置一个对象,可动态切换 class

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

数组语法 --> 把一个数组传给 v-bind:class

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例</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>

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

<div v-bind:class="[errorClass ,isActive ? activeClass : '']"></div>

3、Vue.js style(内联样式)

v-bind:style 直接设置样式:

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

<script>
new Vue({ el: '#app', data: { activeColor: 'green', fontSize: 30 } })
</script>

也可以直接绑定到一个样式对象,让模板更清晰:

<div id="app">
  <div v-bind:style="styleObject">菜鸟教程</div>
</div>
 
<script>
	new Vue({ el: '#app', data: { styleObject: { color: 'green', fontSize: '30px' } } })
</script>

注意:当 v-bind:style 使用需要特定前缀的 CSS 属性时,如 transformVue.js 会自动侦测并添加相应的前缀。

九、Vue.js 事件处理器

事件监听可以使用 v-on 指令,一般需要使用一个方法来调用 JavaScript 方法,也可以用内联 JavaScript 语句。

<div id="app">
  <button v-on:click="counter += 1">增加 1</button>
  <p>这个按钮被点击了 {{ counter }} 次。</p>
</div>
 
<script>
	new Vue({ el: '#app', data: { counter: 0 } })
</script>
<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) {
      alert('Hello ' + this.name + '!');    // `this` 在方法里指当前 Vue 实例
      if (event) {     // `event` 是原生 DOM 事件
          alert(event.target.tagName)
      }
    }
  }
})
// 也可以用 JavaScript 直接调用方法
app.greet() // -> 'Hello Vue.js!'
</script>
<div id="app">
  <button v-on:click="say('hi')">Say hi</button>
  <button v-on:click="say('what')">Say what</button>
</div>
 
<script>
new Vue({
  el: '#app',
  methods: {
    say: function (message) {
      alert(message)
    }
  }
})
</script>

事件修饰符 --> Vue.jsv-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault()event.stopPropagation()Vue.js通过由点(.)表示的指令后缀来调用修饰符。
.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>
 
<!-- click 事件只能点击一次,2.1.4版本新增 -->
<a v-on:click.once="doThis"></a>

按键修饰符 --> Vue 允许为 v-on 在监听键盘事件时添加按键修饰符, 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 表单

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>

下拉列表的双向数据绑定:

<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-modelinput 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步。
.number --> 如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 numberv-model 来处理输入值。
.trim --> 如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:

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

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

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

十一、Vue.js 组件

Vue.js 组件(Component)可以扩展 HTML 元素,封装可重用的代码。
注册一个全局组件语法格式如下:

Vue.component(tagName, options)

tagName 为组件名,options 为配置选项。注册后可使用以下方式来调用组件:

<tagName></tagName>

全局组件
注册一个简单的全局组件 runoob,并使用它:

<div id="app">
    <runoob></runoob>
</div>
<script>
// 注册
Vue.component('runoob', {
  template: '<h1>自定义组件!</h1>'
})
// 创建根实例
new Vue({ el: '#app' })
</script>

局部组件 – 在实例选项中注册局部组件,该组件只能在该实例中使用:

<div id="app">
    <runoob></runoob>
</div>

<script>
var Child = {
  template: '<h1>自定义组件!</h1>'
}
// 创建根实例
new Vue({
  el: '#app',
  components: {
    // <runoob> 将只在父模板可用
    'runoob': Child
  }
})
</script>

1、Prop

prop --> 父组件用来传递数据的一个自定义属性,父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop"

<div id="app">
    <child message="hello!"></child>
</div>
 
<script>
// 注册
Vue.component('child', { 
  props: ['message'],     // 声明 props
  template: '<span>{{ message }}</span>'     // 同样也可以在 vm 实例中像 "this.message" 这样使用
})
// 创建根实例
new Vue({ el: '#app' })
</script>

动态 Prop – 类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:

<div id="app">
    <div>
      <input v-model="parentMsg">
      <br>
      <child v-bind:message="parentMsg"></child>
    </div>
</div>
 
<script>
// 注册
Vue.component('child', {
  props: ['message'],	// 声明 props
  template: '<span>{{ message }}</span>'	 // 同样也可以在 vm 实例中像 "this.message" 这样使用
})
// 创建根实例
new Vue({  el: '#app',  data: { parentMsg: '父组件内容' } })
</script>

以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:

<div id="app">
    <ol>
    	<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    </ol>
</div>
 
<script>
Vue.component('todo-item', {
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})
new Vue({
  el: '#app',
  data: {
    sites: [
      { text: 'Runoob' },
      { text: 'Google' },
      { text: 'Taobao' }
    ]
  }
})
</script>

注意prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证 – 组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:

Vue.component('example', {
  props: {
    // 基础类型检测 (`null` 意思是任何类型都可以)
    propA: Number,
    // 多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数字,有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})

type 可以是下面原生构造器:
StringNumberBooleanFunctionObjectArray
type 也可以是一个自定义构造器,使用 instanceof 检测。

2、自定义事件

父组件使用 props 给自组件传递数据,若要实现子组件将数据传递回父组件,则需自定义事件!
可使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件

另外,父组件可在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。

<div id="app">
    <div id="counter-event-example">
      <p>{{ total }}</p>
      <button-counter v-on:increment="incrementTotal"></button-counter>
      <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>
</div>
 
<script>
Vue.component('button-counter', {
  template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    incrementHandler: function () {
      this.counter += 1
      this.$emit('increment')
    }
  },
})
new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function () {
      this.total += 1
    }
  }
})
</script>

若想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。如:

<my-component v-on:click.native="doTheThing"></my-component>

十二、Vue.js 自定义指令

除了默认设置的核心指令( v-modelv-show ), Vue 也允许注册自定义指令。
下面注册一个全局指令 v-focus, 该指令的功能是在页面加载时,元素获得焦点:

<div id="app">
    <p>页面载入时,input 元素自动获取焦点:</p>
    <input v-focus>
</div>
 
<script>
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
  // 当绑定元素插入到 DOM 中。
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})
// 创建根实例
new Vue({
  el: '#app'
})
</script>

也可以在实例使用 directives 选项来注册局部指令,这样指令只能在该实例中使用:

<div id="app">
  <p>页面载入时,input 元素自动获取焦点:</p>
  <input v-focus>
</div>
 
<script>
// 创建根实例
new Vue({
  el: '#app',
  directives: {
    // 注册一个局部的自定义指令 v-focus
    focus: {
      // 指令的定义
      inserted: function (el) {
        // 聚焦元素
        el.focus()
      }
    }
  }
})
</script>

1、钩子

钩子函数 --> 指令定义函数提供了几个钩子函数(可选):

  • bind --> 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
  • inserted --> 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
  • update --> 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
  • componentUpdated --> 被绑定元素所在模板完成一次更新周期时调用。
  • unbind --> 只调用一次, 指令与元素解绑时调用。

钩子函数参数 --> 钩子函数的参数有:

  • el --> 指令所绑定的元素,可以用来直接操作 DOM。
  • binding --> 一个对象,包含以下属性:
    name --> 指令名,不包括 v- 前缀。
    value --> 指令的绑定值, 例如: v-my-directive=“1 + 1”, value 的值是 2。
    oldValue --> 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    expression --> 绑定值的表达式或变量名。 例如 v-my-directive=“1 + 1” , expression 的值是 “1 + 1”。
    arg --> 传给指令的参数。例如 v-my-directive:foo, arg 的值是 “foo”。
    modifiers --> 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
  • vnode --> Vue 编译生成的虚拟节点。
  • oldVnode --> 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
<div id="app"  v-runoob:hello.a.b="message"></div>
 
<script>
Vue.directive('runoob', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})
new Vue({
  el: '#app',
  data: {
    message: '菜鸟教程!'
  }
})
</script>

有时候不需要其他钩子函数,可以简写函数,如下格式:

Vue.directive('runoob', function (el, binding) {
  // 设置指令的背景颜色
  el.style.backgroundColor = binding.value.color
})

指令函数可接受所有合法的 JavaScript 表达式,以下实例传入了 JavaScript 对象:

<div id="app">
    <div v-runoob="{ color: 'green', text: '菜鸟教程!' }"></div>
</div>
 
<script>
Vue.directive('runoob', function (el, binding) {
    // 简写方式设置文本及背景颜色
    el.innerHTML = binding.value.text
    el.style.backgroundColor = binding.value.color
})
new Vue({
  el: '#app'
})
</script>

十三、Vue.js 路由

路由 --> 通过不同的 URL 访问不同的内容,实现多视图的单页面 Web应用(single page web application,SPA)。
Vue.js 路由需要载入 vue-router 库
中文文档地址:vue-router文档

1、安装

1、直接下载 / CDN

https://unpkg.com/vue-router/dist/vue-router.js

2、NPM

cnpm install vue-router

2、简单实例

Vue.js + vue-router 可以很简单的实现单页应用。<router-link> 是一个组件,该组件用于设置一个导航链接,切换不同 HTML 内容。 to 属性为目标地址, 即要显示的内容。下面这个实例使用 vue-router,配置组件和路由映射,再告诉 vue-router 在哪里渲染。
HTML代码:

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
 
<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>

JavaScript 代码:

// 0. 如果使用模块化机制编程,导入 Vue 和 VueRouter,要调用 Vue.use(VueRouter)
 
// 1. 定义(路由)组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
 
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]
 
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
  routes // (缩写)相当于 routes: routes
})
 
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
  router
}).$mount('#app')
 
// 现在,应用已经启动了!

点击过的导航链接都会加上样式 class ="router-link-exact-active router-link-active"

3、 相关属性

(1)to --> 表示目标路由的链接。 当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。

<!-- 字符串 -->
<router-link to="home">Home</router-link>
<!-- 渲染结果 -->
<a href="home">Home</a>
 
<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'home'">Home</router-link>
 
<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link :to="'home'">Home</router-link>
 
<!-- 同上 -->
<router-link :to="{ path: 'home' }">Home</router-link>
 
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
 
<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>

(2)replace --> 设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),导航后不会留下 history 记录。

<router-link :to="{ path: '/abc'}" replace></router-link>

(3)append --> 设置 append 属性后,则在当前 (相对) 路径前添加基路径。例如,从 /a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b

<router-link :to="{ path: 'relative/path'}" append></router-link>

(4)tag --> 若想要 <router-link> 渲染成某种标签,如 <li>。 可使用 tag prop 类指定何种标签,同样它还是会监听点击,触发导航。

<router-link to="/foo" tag="li">foo</router-link>
<!-- 渲染结果 -->
<li>foo</li>

(5)active-class --> 设置链接激活时使用的 CSS 类名。可以通过以下代码来替代。

<style>
   ._active{ background-color : red; }
</style>
<p>
   <router-link v-bind:to = "{ path: '/route1'}" active-class = "_active">Router Link 1</router-link>
   <router-link v-bind:to = "{ path: '/route2'}" tag = "span">Router Link 2</router-link>
</p>

注意这里 class 使用 active_class="_active"
(6)exact-active-class --> 配置当链接被精确匹配的时候应该激活的 class。可以通过以下代码来替代。

<p>
   <router-link v-bind:to = "{ path: '/route1'}" exact-active-class = "_active">Router Link 1</router-link>
   <router-link v-bind:to = "{ path: '/route2'}" tag = "span">Router Link 2</router-link>
</p>

(7)event --> 声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。

<router-link v-bind:to = "{ path: '/route1'}" event = "mouseover">Router Link 1</router-link>

以上代码设置了 eventmouseover ,即在鼠标移动到 Router Link 1 上时导航的 HTML 内容会发生改变。

(8)NPM 路由实例 --> 下面演示一个使用 npm 简单的路由实例,开始前,请先下载该实例源代码:
可以在 Github 上下载:https://github.com/chrisvfritz/vue-2.0-simple-routing-example
下载完后,解压该目录,重命名目录为 vue-demovu 并进入该目录,执行以下命令:

# 安装依赖,使用淘宝资源命令 cnpm
cnpm install
 
# 启动应用,地址为 localhost:8080
cnpm run dev

如果需要发布到正式环境可以执行以下命令:

cnpm run build

执行成功后,访问 http://localhost:8080即可看到如下界面:
在这里插入图片描述

十四、Vue.js 过渡 & 动画

1、过渡

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。
Vue 提供了内置的过渡封装组件,该组件用于包裹要实现过渡效果的组件。
语法格式 :

<transition name = "nameoftransition">
   <div></div>
</transition>

可通过以下实例来理解 Vue 的过渡是如何实现的:

<div id = "databinding">
<button v-on:click = "show = !show">点我</button>
<transition name = "fade">
    <p v-show = "show" v-bind:style = "styleobj">动画实例</p>
</transition>
</div>
<script type = "text/javascript">
var vm = new Vue({
el: '#databinding',
    data: {
        show:true,
        styleobj :{
            fontSize:'30px',
            color:'red'
        }
    },
    methods : {
    }
});
</script>

实例中通过点击 “点我” 按钮将变量 show 的值从 true 变为 false。如果为 true 显示子元素 p 标签的内容。
下面这段代码展示了 transition 标签包裹了 p 标签:

<transition name = "fade">
    <p v-show = "show" v-bind:style = "styleobj">动画实例</p>
</transition>

过渡其实就是一个淡入淡出的效果。Vue在元素显示与隐藏的过渡中,提供了 6 个 class 来切换:

  • v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
  • v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
  • v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
  • v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
  • v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
  • v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
    在这里插入图片描述
    对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter
    v-enter-activev-leave-active 可以控制进入/离开过渡的不同的缓和曲线,在后面会有个示例说明。

CSS 过渡 – 通常我们都使用 CSS 过渡来实现效果。

<div id = "databinding">
<button v-on:click = "show = !show">点我</button>
<transition name="slide-fade">
    <p v-if="show">hello</p>
</transition>
</div>
<script type = "text/javascript">
new Vue({
    el: '#databinding',
    data: {
        show: true
    }
})
</script>

CSS 动画 – CSS 动画用法类似 CSS 过渡,但是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。

<div id = "databinding">
<button v-on:click = "show = !show">点我</button>
<transition name="bounce">
    <p v-if="show">这里的山歌十八弯!!!</p>
</transition>
</div>
<script type = "text/javascript">
new Vue({ el: '#databinding', data: { show: true  } })
</script>

自定义过渡的类名 --> 可通过以下特性来自定义过渡类名:
enter-classenter-active-classenter-to-class (2.1.8+)、leave-classleave-active-classleave-to-class (2.1.8+)
自定义过渡的类名优先级高于普通的类名,这样就能很好的与第三方(如:animate.css)的动画库结合使用。

<div id = "databinding">
<button v-on:click = "show = !show">点我</button>
<transition
    name="custom-classes-transition"
    enter-active-class="animated tada"
    leave-active-class="animated bounceOutRight"
>
    <p v-if="show">bong撒嘎啦嘎!!!</p>
</transition>
</div>
<script type = "text/javascript">
new Vue({ el: '#databinding', data: { show: true } })
</script>

同时使用过渡和动画
Vue 为了知道过渡的完成,必须设置相应的事件监听器,可以是 transitionendanimationend ,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别类型并设置监听。
但是,在一些场景中,你需要给同一个元素同时设置两种过渡动效,比如 animation 很快的被触发并完成了,而 transition 效果还没结束。在这种情况中,你就需要使用 type 特性并设置 animationtransition 来明确声明你需要 Vue 监听的类型。

显性的过渡持续时间
在很多情况下,Vue 可以自动得出过渡效果的完成时机。默认情况下,Vue 会等待其在过渡效果的根元素的第一个 transitionendanimationend 事件。然而也可以不这样设定——比如,我们可以拥有一个精心编排的一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。
在这种情况下你可以用 <transition> 组件上的 duration 属性定制一个显性的过渡持续时间 (以毫秒计):

<transition :duration="1000">...</transition>

也可以定制进入和移出的持续时间:

<transition :duration="{ enter: 500, leave: 800 }">...</transition>

2、JavaScript 钩子

可以在属性中声明 JavaScript 钩子:

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"
 
  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
// ...
methods: {
  // --------
  // 进入中
  // --------
 
  beforeEnter: function (el) {
    // ...
  },
  // 此回调函数是可选项的设置
  // 与 CSS 结合时使用
  enter: function (el, done) {
    // ...
    done()
  },
  afterEnter: function (el) {
    // ...
  },
  enterCancelled: function (el) {
    // ...
  },
 
  // --------
  // 离开时
  // --------
 
  beforeLeave: function (el) {
    // ...
  },
  // 此回调函数是可选项的设置
  // 与 CSS 结合时使用
  leave: function (el, done) {
    // ...
    done()
  },
  afterLeave: function (el) {
    // ...
  },
  // leaveCancelled 只用于 v-show 中
  leaveCancelled: function (el) {
    // ...
  }
}

这些钩子函数可以结合 CSS transitions/animations 使用,也可以单独使用。
当只用 JavaScript 过渡的时候,在 enterleave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false"Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
一个使用 Velocity.js 的简单例子:

<div id = "databinding">
<button v-on:click = "show = !show">点我</button>
<transition
    v-on:before-enter="beforeEnter"
    v-on:enter="enter"
    v-on:leave="leave"
    v-bind:css="false"
  >
    <p v-if="show">菜鸟教程 -- 学的不仅是技术,更是梦想!!!</p>
</transition>
</div>
<script type = "text/javascript">
new Vue({
  el: '#databinding',
  data: {
    show: false
  },
  methods: {
    beforeEnter: function (el) {
      el.style.opacity = 0
      el.style.transformOrigin = 'left'
    },
    enter: function (el, done) {
      Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
      Velocity(el, { fontSize: '1em' }, { complete: done })
    },
    leave: function (el, done) {
      Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
      Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
      Velocity(el, {
        rotateZ: '45deg',
        translateY: '30px',
        translateX: '30px',
        opacity: 0
      }, { complete: done })
    }
  }
})
</script>

3、初始渲染的过渡

可以通过 appear 特性设置节点在初始渲染的过渡

<transition appear>
  <!-- ... -->
</transition>

这里默认和进入/离开过渡一样,同样也可以自定义 CSS 类名。

<transition
  appear
  appear-class="custom-appear-class"
  appear-to-class="custom-appear-to-class" (2.1.8+)
  appear-active-class="custom-appear-active-class"
>
  <!-- ... -->
</transition>

自定义 JavaScript 钩子:

<transition
  appear
  v-on:before-appear="customBeforeAppearHook"
  v-on:appear="customAppearHook"
  v-on:after-appear="customAfterAppearHook"
  v-on:appear-cancelled="customAppearCancelledHook"
>
  <!-- ... -->
</transition>

多个元素的过渡
可以设置多个元素的过渡,一般列表与描述:
需要注意的是当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。

<transition>
  <table v-if="items.length > 0">
    <!-- ... -->
  </table>
  <p v-else>抱歉,没有找到您查找的内容。</p>
</transition>

如下实例:

<transition>
  <button v-if="isEditing" key="save">
    Save
  </button>
  <button v-else key="edit">
    Edit
  </button>
</transition>

在一些场景中,也可以通过给同一个元素的 key 特性设置不同的状态来代替 v-ifv-else,上面的例子可以重写为:

<transition>
  <button v-bind:key="isEditing">
    {{ isEditing ? 'Save' : 'Edit' }}
  </button>
</transition>

使用多个 v-if 的多个元素的过渡可以重写为绑定了动态属性的单个元素过渡。例如:

<transition>
  <button v-if="docState === 'saved'" key="saved">
    Edit
  </button>
  <button v-if="docState === 'edited'" key="edited">
    Save
  </button>
  <button v-if="docState === 'editing'" key="editing">
    Cancel
  </button>
</transition>

可以重写为:

<transition>
  <button v-bind:key="docState">
    {{ buttonMessage }}
  </button>
</transition>
 
// ...
computed: {
  buttonMessage: function () {
    switch (this.docState) {
      case 'saved': return 'Edit'
      case 'edited': return 'Save'
      case 'editing': return 'Cancel'
    }
  }
}

十五、Vue.js 混入

混入 (mixins)定义了一部分可复用的方法或者计算属性。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。

var vm = new Vue({ el: '#databinding', data: { }, methods : { }, });
// 定义一个混入对象
var myMixin = {
    created: function () {
        this.startmixin()
    },
    methods: {
        startmixin: function () {
            document.write("欢迎来到混入实例");
        }
    }
};
var Component = Vue.extend({
    mixins: [myMixin]
})
var component = new Component();

1、选项合并

当组件和混入对象含有同名选项时,这些选项将以恰当的方式混合。
比如,数据对象在内部会进行浅合并 (一层属性深度),在和组件的数据发生冲突时以组件数据优先。
以下实例中,Vue 实例与混入对象包含了相同的方法。从输出结果可以看出两个选项合并了。

var mixin = {
    created: function () {
        document.write('混入调用' + '<br>')
    }
}
new Vue({
    mixins: [mixin],
        created: function () {
        document.write('组件调用' + '<br>')
    }
});

如果 methods 选项中有相同的函数名,则 Vue 实例优先级会较高。如下实例,Vue 实例与混入对象的 methods 选项都包含了相同的函数:

var mixin = {
    methods: {
        hellworld: function () {
            document.write('HelloWorld 方法' + '<br>');
        },
        samemethod: function () {
            document.write('Mixin:相同方法名' + '<br>');
        }
    }
};
var vm = new Vue({
    mixins: [mixin],
    methods: {
        start: function () {
            document.write('start 方法' + '<br>');
        },
        samemethod: function () {
            document.write('Main:相同方法名' + '<br>');
        }
    }
});
vm.hellworld();
vm.start();
vm.samemethod();

以上实例,调用了以下三个方法:

vm.hellworld();
vm.start();
vm.samemethod();

2、全局混入

也可以全局注册混入对象。注意使用! 一旦使用全局混入对象,将会影响到 所有 之后创建的 Vue 实例。使用恰当时,可以为自定义对象注入处理逻辑。

// 为自定义的选项 'myOption' 注入一个处理器。
Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})
 
new Vue({ myOption: 'hello!' })
// => "hello!"

谨慎使用全局混入对象,因为会影响到每个单独创建的 Vue 实例 (包括第三方模板)。

十六、Vue.js Ajax(vue-resource)

Vue 要实现异步加载需要使用到 vue-resource 库。

<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>

Get 请求 --> 以下是一个简单的 Get 请求实例,请求地址是一个简单的 txt 文本:

window.onload = function(){
    var vm = new Vue({
        el:'#box',
        data:{
            msg:'Hello World!',
        },
        methods:{
            get:function(){
                //发送get请求
                this.$http.get('/try/ajax/ajax_info.txt').then(function(res){
                    document.write(res.body);    
                },function(){
                    console.log('请求失败处理');
                });
            }
        }
    });
}

如果需要传递数据,可以使用 this.$http.get('get.php',jsonData) 格式,第二个参数 jsonData 就是传到后端的数据。

this.$http.get('get.php',{a:1,b:2}).then(function(res){
    document.write(res.body);    
},function(res){
    console.log(res.status);
});

post 请求 --> post 发送数据到后端,需要第三个参数 {emulateJSON:true}
emulateJSON 的作用: 如果Web服务器无法处理编码为 application/json 的请求,你可以启用 emulateJSON 选项。

window.onload = function(){
    var vm = new Vue({
        el:'#box',
        data:{
            msg:'Hello World!',
        },
        methods:{
            post:function(){
                //发送 post 请求
                this.$http.post('/try/ajax/demo_test_post.php',{name:"嘿嘿嘿",url:"http://www.runoob.com"},{emulateJSON:true}).then(function(res){
                    document.write(res.body);    
                },function(res){
                    console.log(res.status);
                });
            }
        }
    });
}

demo_test_post.php 代码如下:

<?php
$name = isset($_POST['name']) ? htmlspecialchars($_POST['name']) : '';
$city = isset($_POST['url']) ? htmlspecialchars($_POST['url']) : '';
echo '网站名: ' . $name;
echo "\n";
echo 'URL 地址: ' .$city;
?>

语法 & API --> 可以使用全局对象方式 Vue.http 或者在一个 Vue 实例的内部使用 this.$http来发起 HTTP 请求。

// 基于全局Vue对象使用http
Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback);
Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);
 
// 在一个Vue实例内使用$http
this.$http.get('/someUrl', [options]).then(successCallback, errorCallback);
this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);

除了 jsonp 以外,另外 6 种的 API 名称是标准的 HTTP 方法。
options 参数说明:

参数 类型 描述
url string 请求的目标URL
body Object, FormData, string 作为请求体发送的数据
headers Object 作为请求头部发送的头部对象
params Object 作为URL参数的参数对象
method string HTTP方法 (例如GET,POST,…)
timeout number 请求超时(单位:毫秒) (0表示永不超时)
before function(request) 在请求发送之前修改请求的回调函数
progress function(event) 用于处理上传进度的回调函数 ProgressEvent
credentials boolean 是否需要出示用于跨站点请求的凭据
emulateHTTP boolean 是否需要通过设置X-HTTP-Method-Override头部并且以传统POST方式发送PUT,PATCH和DELETE请求。
emulateJSON boolean 设置请求体的类型为application/x-www-form-urlencoded

通过如下属性和方法处理一个请求获取到的响应对象:

属性 类型 描述
url string 响应的URL源
body Object, Blob, string 响应体数据
headers Header 请求头部对象
ok boolean 当HTTP响应码为200到299之间的数值时该值为true
status number HTTP响应吗
statusText string HTTP响应状态
方法 类型 描述
text() 约定值 以字符串方式返回响应体
json() 约定值 以格式化后的json对象方式返回响应体
blob() 约定值 以二进制Blob对象方式返回响应体

十七、Vue.js 响应接口

Vue 可以添加数据动态响应接口。
例如以下实例,通过使用 $watch 属性来实现数据的监听,$watch 必须添加在 Vue 实例之外才能实现正确的响应。
实例中通过点击按钮自动加 1。setTimeout 设置两秒后计算器的值加上 20 。

<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 + '!');
});
setTimeout(
    function(){
        vm.counter = 20;
    },2000
);
</script>

Vue 不允许在已经创建的实例上动态添加新的根级响应式属性。
Vue 不能检测到对象属性的添加或删除,最好的方式就是在初始化实例前声明根级响应式属性,哪怕只是一个空值。
如果需要在运行过程中实现属性的添加或删除,则可以使用全局 VueVue.setVue.delete 方法。
Vue.set --> Vue.set 方法用于设置对象的属性,它可以解决 Vue 无法检测添加属性的限制,语法格式如下:

Vue.set( target, key, value )

参数说明:

  • target: 可以是对象或数组
  • key : 可以是字符串或数字
  • value: 可以是任何类型
<div id = "app">
   <p style = "font-size:25px;">计数器: {{ products.id }}</p>
   <button @click = "products.id++" style = "font-size:25px;">点我</button>
</div>
<script type = "text/javascript">
var myproduct = {"id":1, name:"book", "price":"20.00"};
   var vm = new Vue({
   el: '#app',
   data: {
      counter: 1,
      products: myproduct
   }
});
vm.products.qty = "1";
console.log(vm);
vm.$watch('counter', function(nval, oval) {
   alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!');
});
</script>

在以上实例中,使用以下代码在开始时创建了一个变量 myproduct

var myproduct = {"id":1, name:"book", "price":"20.00"};

该变量在赋值给了 Vue 实例的 data 对象:

 var vm = new Vue({ el: '#app', data: { counter: 1, products: myproduct } });

如果想给 myproduct 数组添加一个或多个属性,可以在 Vue 实例创建后使用以下代码:

vm.products.qty = "1";

在这里插入图片描述
如上图看到的,在产品中添加了数量属性 qty,但是 get/set 方法只可用于 idnameprice 属性,却不能在 qty 属性中使用。
不能通过添加 Vue 对象来实现响应。 Vue 主要在开始时创建所有属性。 如果要实现这个功能,可以通过 Vue.set 来实现:

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

在这里插入图片描述
从控制台输出的结果可以看出 get/set 方法可用于qty 属性。
Vue.delete --> Vue.delete 用于删除动态添加的属性 语法格式:

Vue.delete( target, key )

参数说明:

  • target: 可以是对象或数组
  • key : 可以是字符串或数字
<div id = "app">
   <p style = "font-size:25px;">计数器: {{ products.id }}</p>
   <button @click = "products.id++" style = "font-size:25px;">点我</button>
</div>
<script type = "text/javascript">
var myproduct = {"id":1, name:"book", "price":"20.00"};
var vm = new Vue({
   el: '#app',
   data: {
      counter: 1,
      products: myproduct
   }
});
Vue.delete(myproduct, 'price');
console.log(vm);
vm.$watch('counter', function(nval, oval) {
   alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!');
});
</script>

以上实例中使用 Vue.delete 来删除 price 属性。以下是控制台输出结果:
在这里插入图片描述
从上图输出结果中,可以看到 price 属性已删除,只剩下了 idname 属性,price 属性的 get/set 方法也已删除。

发布了76 篇原创文章 · 获赞 26 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_29326717/article/details/86651937