Webpack 入门教程:http://www.runoob.com/w3cnote/webpack-tutorial.html
官方文档:http://vuejs.org/v2/guide/syntax.html
https://vuejs.org/v2/api/
中文文档: https://cn.vuejs.org/v2/guide/syntax.html
https://cn.vuejs.org/v2/api/
# 全局安装 vue-cli
$ cnpm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 这里需要进行一些配置,默认回车即可
$ cd my-project
$ cnpm install
$ cnpm run dev
DONE Compiled successfully in 4388ms
> Listening at http://localhost:8080
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
</script>
</body>
</html>
Vue.js 目录结构
上一章节中我们使用了 npm 安装项目,我们在 IDE(Eclipse、Atom等) 中打开该目录,结构如下所示:
目录解析
目录/文件 | 说明 |
---|---|
build | 项目构建(webpack)相关代码 |
config | 配置目录,包括端口号等。我们初学可以 使用默认的。 |
node_modules | npm 加载的项目依赖模块 |
src | 这里是我们要开发的目录,基本上要做的事情 都在这个目录里。里面包含了几个目录及文件: - assets: 放置一些图片,如logo等。 - components: 目录里面放了一个组件文件 |
,可以不用。
- App.vue: 项目入口文件,我们也可以
直接将组件写这里,而不使用 components
目录。
- main.js: 项目的核心文件。
|
| static | 静态资源目录,如图片、字体等。 |
| test | 初始测试目录,可删除 |
| .xxxx文件 | 这些是一些配置文件,包括语法配置,
git配置等。 |
| index.html | 首页入口文件,你可以添加一些 meta
信息或统计代码啥的。 |
| package.json | 项目配置文件。 |
| README.md | 项目的说明文档,markdown 格式 |
在前面我们打开 APP.vue 文件,代码如下(解释在注释中):
<!-- 展示模板 -->
<template>
<div id="app">
<img src="./assets/logo.png">
<hello></hello>
<div>
<h1 class="class1" v-bind:class="{ 'class2': use }">site : {{site}}</h1>
<div v-bind:class="[ 'class1' ,use ? 'class2' : '']"></div>
<div v-bind:class="classObject"></div>
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">style</div>
<div v-bind:style="[baseStyles, overridingStyles]">style</div>
<h1>url : {{url}}</h1>
<h1>{{details()}}</h1>
</div>
<div v-html="message"></div>
<br />
{{5+5}}<br />
{{ ok ? 'YES' : 'NO' }}<br />
{{ msg.split('').reverse().join('') }}
<div v-bind:id="'list-' + id">菜鸟教程</div>
<p v-if="seen">现在你看到我了</p>
<pre>
<a v-bind:href="url">菜鸟教程</a>
<a :href="url">v-bind可以缩写,菜鸟教程</a>
</pre>
<form v-on:submit.prevent="onSubmit">
<p>{{ msg }}</p>
<input v-model="msg">
<button v-on:click="doSomething">绑定click事件</button>
<button @click="doSomething">v-on:可以缩写,绑定click事件</button>
<button type="submit">提交</button>
</form>
<br />
<br />
<!-- 在两个大括号中 -->
{{ msg | capitalize | capitalize2 | capitalize3('arg1') }}
<!-- 在 v-bind 指令中 -->
<div v-bind:id="msg | capitalize | capitalize2 | capitalize3('arg1')">绑定id</div>
<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>
<h1 v-show="ok">Hello!</h1>
<ul>
<li v-for="site in sites">
{{ site.name }}
</li>
<li v-for="value in object">
{{ value }}
</li>
<li v-for="(value, key, index) in object">
{{ value }}
</li>
<li v-for="n in 10">
{{ n }}
</li>
</ul>
<p>原始字符串: {{ msg }}</p>
<p>计算后反转字符串: {{ reversedMessage }}</p>
</div>
</template>
<script>
// 导入组件
import Hello from './components/Hello'
export default {
name: 'app',
el: '#app',
watch : {
kilometers:function(val) {
this.kilometers = val;
this.meters = this.kilometers * 1000
},
meters : function (val) {
this.kilometers = val/ 1000;
this.meters = val;
}
},
computed: {
classObject: function () {
return {
class1: true,
class2: this.use,
}
},
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.msg.split('').reverse().join('')
},
siteComputed: { // computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
// getter
get: function () {
return this.object.name + ' ' + this.object.url
},
// setter
set: function (newValue) {
var names = newValue.split(' ');
this.object.name = names[0];
this.object.url = names[names.length - 1];
}
}
},
filters: { // 过滤器
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
},
capitalize2: function (value) { // 过滤器可以串联
if (!value) return ''
value = value.toString();
return value.slice(0, value.length - 1) + value.charAt(value.length - 1).toUpperCase()
},
// 过滤器是 JavaScript 函数,因此可以接受参数:
capitalize3: function (aa, value) {
if (!value) return ''
value = value.toString()
return value + aa;
},
},
components: {
Hello, // 这里是一个子组件
},
data: {
baseStyles: { color: 'red' },
overridingStyles: { fontSize: '14px' },
activeColor: 'red',
fontSize: 14,
kilometers: 0,
meters: 0,
type: 'A',
id: 'id',
msg: 'msg message',
sites: [{ name: 'a' }, { name: 'b' }],
object: {
name: '菜鸟教程',
url: 'http://www.runoob.com',
slogan: '学的不仅是技术,更是梦想!'
},
site: "菜鸟教程",
url: "www.runoob.com", // 绑定响应式更新元素 v-bind:href="url"
alexa: "10000",
use: false, // 绑定class v-bind当use为true时显示class1
ok: true, // 三元表达式控制显示内容,操作字符串或表达式
seen: true,// v-if的语法,操作组件或html元素
message: '<h1>双括号用于输出文本,v-html用于输出html</h1>',
},
methods: {
submit: function() { // v-on:submit.prevent="onSubmit" .prevent是修饰符
// .prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():
this.msg = '提交';
},
doSomething: function(e){
this.msg = Date.now().toString();
e.preventDefault();
e.stopPropagation();
},
details: function() {
return this.site + " - 学的不仅是技术,更是梦想!";
}
},
}
/*
// $watch 是一个实例方法
vm.$watch('kilometers', function (newValue, oldValue) {
// 这个回调将在 vm.kilometers 改变后调用
document.getElementById ("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
});
*/
</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>
数组操作
vm.$set( target, propertyName/index, value )
- 参数:
- {Object | Array} target
- {string | number} propertyName/index
- {any} value
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
// ====================================
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
// =======================================
<h1 v-if="awesome">if</h1>
<h1 v-else-if="type === 'C'">
</h1>
<h1 v-else>else</h1>
// ===============================
<ul id="example-1">
<li
v-for="(item, index) in items"
v-for="item in items"
v-for="item of items"
v-for="(value, name, index) in object"
ref="p" // this.$refs.p = [vt, vt, vt, ...] 如果这样写会变成这样的
:key="item.message">
{{ item.message }}
</li>
</ul>
过滤器 filters
Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。由”管道符”指示。可以通过过滤器对值进行加工处理
{{ message | capitalize }}
<!-- 在 v-bind 指令中 -->
<div v-bind:id="rawId | formatId"></div>
计算属性 computed
computed vs methods
我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
监听属性 watch
我们将为大家介绍 Vue.js 监听属性 watch,我们可以通过 watch 来响应数据的变化。
vm.$watch('kilometers', function (newValue, oldValue) {
// ... newValue 表示新值, oldValue 表示老值
});
修饰符
事件修饰符
Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。
Vue.js通过由点(.)表示的指令后缀来调用修饰符。
.stop
.prevent
.capture
.self
.once
按键修饰符
Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
全部的按键别名:
.enter
.tab
.delete
(捕获 “删除” 和 “退格” 键).esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
实例
表单修饰符
.lazy
在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:
.number
如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:
这通常很有用,因为在 type=”number” 时 HTML 中输入的值也总是会返回字符串类型。
.trim
如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:
表单的双向绑定
<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>
VUE组件注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
全局组件的注册方法
<div id="app">
<runoob></runoob>
<child message="hello!"></child>
<child v-bind:message="parentMsg"></child>
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>
</div>
<script>
// 注册
Vue.component('runoob', {
template: '<h1>自定义组件!</h1>'
});
Vue.component('child', {
// 声明 props
props: ['message'],
// 同样也可以在 vm 实例中像 "this.message" 这样使用
template: '<span>{{ message }}</span>'
});
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
});
// 创建根实例
new Vue({
el: '#app',
data: {
parentMsg: '父组件内容',
sites: [
{ text: 'Runoob' },
{ text: 'Google' },
{ text: 'Taobao' }
],
},
});
</script>
局部组件的组册方法
<div id="app">
<runoob></runoob>
</div>
<script>
var Child = {
template: '<h1>自定义组件!</h1>'
}
// 创建根实例
new Vue({
el: '#app',
components: {
// <runoob> 将只在父模板可用
'runoob': Child
}
})
</script>
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 可以是下面原生构造器:
- String
- Number
- Boolean
- Function
- Object
- Array
type 也可以是一个自定义构造器,使用 instanceof 检测。
VUE组件自定义事件
父组件是使用 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 () { // data 必须是一个函数,data 是一个对象则会影响到其他实例
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>
.sync
感觉这玩意违反单向数据流,数据流向自顶向下
// 父组件
<component value.sync="value" />
// 子组件改变父组件的值
this.$emit('update:title', newValue)
vue-router
this.$router.push({
path: "/urlpath",
query: {
a: 1,
b: 2
},
params: {
id: 1
}
})
this.$route.params