注意:以下所有示例基于vue 2.x、Vuex 2.x、
vm.$mount()-挂载
<body>
<div id="a">
</div>
</body>
<script>
var A = Vue.extend({
template: '<p>123</p>'
});
/*// 自动挂载
new A({
el: '#a'
});*/
var a = new A();
a.$mount('#a')// 手动挂载
</script>
组件示例(component):
a. 不使用template标签
<body>
<div id="a">
<aaa m="a++" bgcolor="red"></aaa>
<aaa m="b--" bgcolor="blue"></aaa>
</div>
</body>
<script>
Vue.component('aaa', {
template: '<div><p>{{ m }}</p><p @click="add" :style="style">点这里-> a:{{a}} b:{{b}}</p></div>',
data: function() {
return {
a: 0,
b: 0,
style: {
fontSize: '30px',
background: this.bgcolor
}
}
},
props: ['m', 'bgcolor'],
methods: {
add: function() {
this.a++;
this.b--;
}
}
});
new Vue({
el: '#a'
})
</script>
b. 使用template标签
<body>
<div id="a">
<aaa m="a++" bgcolor="red"></aaa>
<aaa m="b--" bgcolor="blue"></aaa>
</div>
<template id="b">
<div>
<p>{{ m }}</p>
<p @click="add" :style="style">点这里-> a:{{a}} b:{{b}}</p>
</div>
</template>
</body>
<script>
Vue.component('aaa', {
template: '#b',
data: function() {
return {
a: 0,
b: 0,
style: {
fontSize: '30px',
background: this.bgcolor
}
}
},
props: ['m', 'bgcolor'],
methods: {
add: function() {
this.a++;
this.b--;
}
}
});
new Vue({
el: '#a'
})
</script>
c. 局部注册
<body>
<div id="a">
<my-b></my-b>
<my-c></my-c>
<my-d></my-d>
</div>
<template id="b">
<p>bbb</p>
</template>
</body>
<script>
var myD = Vue.component('myD', {
template: '<p>ddd</p>'
});
new Vue({
el: '#a',
components: {
'myB': {
template: '#b'
},
'myC': {
template: '<p>ccc</p>'
},
'myD': myD
}
});
</script>
d. 动态组件
<body>
<div id="a">
<button @click="change">{{ cur }}</button>
<component :is="cur"></component>
</div>
<template id="b">
<p>bbb</p>
</template>
</body>
<script>
new Vue({
el: '#a',
data: {
cur: {// 直接绑定到组件对象上
template: '<p>aaa</p>'
}
},
methods: {
change: function() {
this.cur = this.cur=='myB'?'myC':'myB';
}
},
components: {// 多个组件使用同一挂载点,动态切换
'myB': {
template: '#b'
},
'myC': {
template: '<p>ccc</p>'
}
}
});
</script>
e. 父子组件通信
<body>
<div id="a">
父:<input v-model="msg" />
<aaa :msg="msg" @notick="notickEvent"></aaa>
</div>
<template id="b">
<div>
子:<input v-model="msgChild" />
</div>
</template>
</body>
<script>
// 子组件
Vue.component('aaa', {
template: '#b',
props: ['msg'],// 使子组件接受到父组件的msg属性
data: function() {
return {
msgChild: ''// 子组件msg的替代品(vue2中禁止子组件直接改变父组件状态,只能通过替代)
}
},
watch: {
msg: function(newVal, oldVal) {
this.msgChild = newVal;
},
msgChild: function(newVal, oldVal) {
this.$emit('notick', newVal);// 子组件msgChild改变时,触发notick事件
}
}
})
// 父组件
new Vue({
el: '#a',
data: {
msg: ''
},
methods: {
notickEvent: function(val) {
this.msg = val;
}
}
})
</script>
f. 兄弟组件通信
<body>
<div id="a">
<aaa></aaa>
<bbb></bbb>
</div>
<template id="b">
<button @click="add">点击:{{ num }}</button>
</template>
</body>
<script>
var bus = new Vue();// 简单场景下可以使用bus
// 子组件aaa
Vue.component('aaa', {
template: '#b',
data: function() {
return {
num: 0
}
},
methods: {
add: function() {
bus.$emit('addEvent', ++this.num);
}
},
mounted: function() {
var This = this;
bus.$on('addEvent', function(val) {
This.num = val;
})
}
})
// 子组件bbb
Vue.component('bbb', {
template: '#b',
data: function() {
return {
num: 0
}
},
methods: {
add: function() {
bus.$emit('addEvent', ++this.num);
}
},
mounted: function() {
var This = this;
bus.$on('addEvent', function(val) {
This.num = val;
})
}
})
new Vue({
el: '#a'
})
</script>
g. 异步组件
<body>
<div id="a">
<component :is='btn'></component>
<button @click="change">{{ btn }}</button>
</div>
</body>
<script>
new Vue({
el: '#a',
data: {
btn: 'aA'
},
methods: {
change: function() {
this.btn = this.btn=='aA'?'bB':'aA';
}
},
components: {
aA: function(resolve) {
setTimeout(function() {
resolve({
template: '<p>{{ btn }}</p>',
data: function() {
return {
btn: this.$root.btn
}
}
});
}, 1000);
},
bB: {
template: '<p>bb...</p>'
}
}
});
</script>
计算示例(computed):
<body>
<div id="a">
<p>{{ intro }}</p>
<input type="text" v-model="name">
<input type="text" v-model="age">
</div>
<script>
new Vue({
el: '#a',
data: {
name: 'hvb',
age: 20
},
computed: {
intro: function() {
return this.name +':'+ this.age;
}
}
});
</script>
</body>
自定义指令实现"点击按钮使文本框获取焦点"示例(directive):
<body>
<div id="a">
<input v-focus="isFocus" />
<button @click="change">点击切换输入框选中状态</button>
</div>
</body>
<script>
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 被绑定元素插入父节点时调用
inserted: function (el, binding) {
if(binding.value) {
el.focus();
}else {
el.blur();
}
},
// 被绑定元素所在模板完成一次更新周期时调用
componentUpdated: function (el, binding) {
if(binding.value) {
el.focus();
}else {
el.blur();
}
}
})
new Vue({
el: '#a',
data: {
isFocus: true
},
methods: {
change: function(e) {
this.isFocus = !this.isFocus;
}
}
})
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<script src="vue.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
body, html {
width: 100%;
height: 100%;
}
.line {
text-decoration: line-through;
}
</style>
</head>
<body>
<div id="a">
<aaa :list="tasks"></aaa><!-- 注意:list的冒号 -->
<hr>
<aaa :list="[{a: 'a', b: 'b', line: true}, {a: 'aa', b: 'bb', line: false}]"></aaa><!-- 组件复用 -->
</div>
<template id="b">
<div>
<input v-model="dd" @keyup.enter="cc" type="text" placeholder="enter添加">
<p v-show="remain">剩余{{ remain }}条未完成</p>
<div v-for="(key, index) in list">
<span @click="aa(key)" :class="{line: key.line}">{{ key.a }}---{{ key.b }}</span>
<strong @click="bb(index)">×</strong>
</div>
</div>
</template>
</body>
<script>
Vue.component('aaa', {
template: '#b',
data: function() {
return {
dd: ''
}
},
watch: {
list: {
handler: function(keys) {
console.log(keys);
},
deep: true//keys中的每个值变化都会触发handler
}
},
props: ['list'],
methods: {
aa: function(key) {
key.line = !key.line;
console.log(2);
},
bb: function(index) {
this.list.splice(index, 1);
},
cc: function() {
this.list.push({
a: this.dd,
b: '无',
line: false
});
this.dd = '';
}
},
computed: {
remain: function() {
return this.list.filter(function(a) {
return !a.line;
}).length;
}
}
});
new Vue({
el: '#a',
data: {
tasks: [
{a: 1, b: 2, line: true},
{a: 11, b: 22, line: false},
{a: 111, b: 222, line: false}
]
},
methods: {
aa: function(key) {
key.line = !key.line;
console.log(1);
}
}
});
</script>
</html>
使用jquery调用接口数据:
<body>
<div id="a">
<p>{{ list }}</p>
</div>
</body>
<script>
new Vue({
el: '#a',
data: {
list: ''
},
created: function() {
var This = this;
$.ajax({
url: 'http://v3.faqrobot.org/servlet/AQ?s=p&sysNum=14464304598886414&&sourceId=0×tamp=1473514741278&dataType=json',
dataType: 'jsonp',
success: function(data) {
This.list = data.webConfig.helloWord;
}
});
},
});
</script>
使用vue-resource调用接口数据:(Vue2推荐使用axios代替vue-resource)
<body>
<div id="a">
<p v-show="a">加载中...</p>
<p>{{ list }}</p>
</div>
</body>
<script>
Vue.http.interceptors.push(function(request, next) {
this.a = !this.a;
next(function(response) {
this.a = !this.a;
return response;
});
});
new Vue({
el: '#a',
data: {
a: false,
list: ''
},
created: function() {
this.$http.jsonp('http://v3.faqrobot.org/servlet/AQ?s=p&sysNum=14464304598886414&&sourceId=0×tamp=1473514741278&dataType=json').then(function(data) {
this.list = data.body.webConfig.helloWord;
});
},
});
</script>
slot示例:
<body>
<div id="a">
<my-b>
<p>匿名slot1</p>
<p>匿名slot2</p>
<p slot="a">具名slot1</p>
<my-c></my-c>
</my-b>
</div>
<template id="b">
<slot></slot>
<slot></slot>
<slot name="a"></slot>
<p>bbb</p>
</template>
<template id="c">
<p>ccc</p>
</template>
</body>
<script>
Vue.component('myB', {
template: '#b'
});
Vue.component('myC', {
template: '#c'
});
p = new Vue({
el: '#a'
});
</script>
activate示例:<body>
<div id="a">
<component :is='btn'></component>
<button @click="change">{{ btn }}</button>
</div>
</body>
<script>
new Vue({
el: '#a',
data: {
btn: 'aA'
},
methods: {
change: function() {
this.btn = this.btn=='aA'?'bB':'aA';
}
},
components: {
aA: {
template: '<p>aa</p>',
activate: function(done) {// 加载前的回调
setTimeout(function() {
console.log(2);
done();
}, 1000);
console.log(1);
},
},
bB: {
template: '<p>bb</p>',
ready: function() {// 作用等同于ready
console.log(3)
}
},
}
});
</script>
vuex示例:
a. 简单计数
<body>
<div id="a">
<p>{{ num }}</p>
<button @click="add">add</button>
<button @click="reduce">reduce</button>
</div>
</body>
<script>
var store = new Vuex.Store({
state: {
num: 0
},
mutations: {
add: function(state) {
state.num++;
},
reduce: function(state) {
state.num--
}
}
})
new Vue({
el: '#a',
computed: {
num: function() {
return store.state.num;
}
},
methods: {
add: function() {
store.commit('add');
},
reduce: function() {
store.commit('reduce');
},
}
})
</script>
b. 子组件获取Vuex状态
<body>
<div id="a">
父:<span>{{ num }}</span>
<aaa></aaa>
</div>
</body>
<script>
var store = new Vuex.Store({
state: {
num: 0
}
})
new Vue({
el: '#a',
store: store,// 把store实例注入所有的子组件
computed: {
num: function() {
return this.$store.state.num;// 使用this.$store即可引用
}
},
components: {// 子组件
'aaa': {
template: '<div>子:<span>{{ num }}</span></div>',
computed: {
num: function() {
return this.$store.state.num;// 使用this.$store即可引用
}
}
}
}
})
</script>
c. 拓展状态Getters
<body>
<div id="a">
<p @click="change">转换后:{{ num }},长度:{{ len }},点击换一换</p>
</div>
</body>
<script>
var store = new Vuex.Store({
state: {// 原状态
num: 'abc'
},
getters: {// 通过原状态拓展出来的状态 (state变化时,getters也会变化,state永远是主动方)
numUpper: function(state) {// 转大写
return state.num.toUpperCase();
},
numUpperLen: function(state, getters) {// 转大写后的字符长度(直接传getters参数可引用拓展状态中的其他状态)
return getters.numUpper.length;
}
},
mutations: {
change: function(state) {
state.num = 'defhi';
}
}
})
new Vue({
el: '#a',
computed: {
num: function() {
return store.getters.numUpper;
},
len: function() {
return store.getters.numUpperLen;
}
},
methods: {
change: function() {
store.commit('change');
}
}
})
</script>
<body>
<div id="a">
<p @click="add1">Time Travel状态正常{{ num }}</p>
<p @click="add2">Time Travel状态不正常{{ num }}</p>
</div>
</body>
<script>
var store = new Vuex.Store({
state: {
num: 0
},
mutations: {
add1: function(state) {
return state.num++;
},
add2: function(state) {
setTimeout(function() {// mutations中进行异步调用,导致vue devtools记录不到此状态,Time Travel时状态不对
return state.num++;
}, 1000);
}
},
actions: {
add1: function(context) {
setTimeout(function() {// actions中进行异步调用,vue devtools正确记录此状态,Time Travel时状态也正常
context.commit('add1');
}, 1000);
}
}
})
new Vue({
el: '#a',
computed: {
num: function() {
return store.state.num;
}
},
methods: {
add1: function() {
return store.dispatch('add1');
},
add2: function() {
return store.commit('add2');
},
}
})
</script>
e. actions中使用Promise
<body>
<div id="a">
<p @click="add">{{ num }}</p>
</div>
</body>
<script>
var store = new Vuex.Store({
state: {
num: 0
},
mutations: {
add: function(state) {
return state.num++;
}
},
actions: {
add: function(context) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
context.commit('add');
console.log(1)
resolve();
}, 1000);
})
}
}
})
new Vue({
el: '#a',
computed: {
num: function() {
return store.state.num;
}
},
methods: {
add: function() {
return store.dispatch('add').then(function() {// 不使用Promise打印2 1,使用Promise打印1 2
console.log(2);
});
}
}
})
</script>
f. 模块Modules和根节点状态rootState
<body>
<div id="a">
<p @click="add">{{ num }}</p>
</div>
</body>
<script>
var moduleA = {
state: {
num: 0// moduleA节点状态
},
mutations: {
['a.add']: function(state) {// a.add为命名空间
return state.num++;
}
},
actions: {
['a.add']: function(context) {
context.rootState.num++;// 根节点状态改变
return context.commit('a.add');// moduleA节点状态改变
}
}
}
var store = new Vuex.Store({
state: {
num: 0// 根节点状态
},
modules: {
modA: moduleA
}
})
new Vue({
el: '#a',
computed: {
num: function() {
return store.state.num + store.state.modA.num;// 根节点和moduleA节点状态叠加
}
},
methods: {
add: function() {
return store.dispatch('a.add');// 触发a.add
}
}
})
</script>
directive示例:(请注意和vue示例的数据交互使用的是
vnode.context,
待更新)
export default {
data() {
return {
SC_outer_style: {
},
SC_inner_style: {
height: '50px',
background: 'red'
}
}
},
computed: {
SC_outer_style() {
return {
}
}
},
mounted() {
},
methods: {
init() {
}
},
directives: {
handle: {
inserted: function(el, binding, vnode) {
if(Tool.getStyle(el, 'position') == 'static') {
vnode.context.SC_outer_style = {
position: 'relative'
}
}
},
}
}
}
vue-router示例:
a. 简单的单页应用
<body>
<div id="app">
<a v-link="{path: '/home'}">home</a>
<a v-link="{path: '/about'}">about</a>
<router-view></router-view>
</div>
</body>
<script>
window.onload = function() {
var Home = Vue.extend({
template: '<p>home content</p>'
});
var About = Vue.extend({
template: '<p>about content</p>'
});
var App = Vue.extend();
var router = new VueRouter();
router.map({
'/home': {component: Home},
'/about': {component: About}
});
router.redirect({// 首先展示此页面
'/': '/about'
})
router.start(App, '#app');
}
</script>
b.
嵌套路由
<body>
<div id="app">
<a v-link="{path: '/home'}">home</a>
<a v-link="{path: '/about'}">about</a>
<router-view></router-view>
</div>
<template id="home">
<p>home-content</p>
<a v-link="{path: '/home/new'}">new</a>
<a v-link="{path: '/home/old'}">old</a>
<router-view></router-view>
</template>
<template id="new">
<p>new-content</p>
</template>
<template id="old">
<p>old-content</p>
</template>
<template id="about">
<p>about-content</p>
</template>
</body>
<script>
window.onload = function() {
var Home = Vue.extend({
template: '#home'
});
var New = Vue.extend({
template: '#new'
});
var Old = Vue.extend({
template: '#old'
});
var About = Vue.extend({
template: '#about'
});
var App = Vue.extend();
var router = new VueRouter();
router.map({
'/home': {
component: Home,
subRoutes: {// 子路由
'/new': {component: New},
'/old': {component: Old}
}
},
'/about': {
component: About
}
});
router.redirect({// 首先展示此页面
'/': 'about'
})
router.start(App, '#app');
}
</script>
b. 路由进阶
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
<style>
* {
margin: 0;
padding: 0;
}
.v-link-active {/* 处于当前页面的含有 v-link 属性的元素自动加上 v-link-active 的 class */
background: red;
}
.customClass {/* 自定义选中时的 class */
background: blue;
}
</style>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
</head>
<body>
<div id="app">
<a v-link="{path: '/home', activeClass: 'customClass'}">home</a>
<a v-link="{path: '/about'}">about</a>
<router-view></router-view>
</div>
<template id="home">
<p @click="say">home-content(点击输出 route 对象)</p>
<p>route 对象:{{ $route | json }}</p>
<a v-link="{path: '/home/new'}">new</a>
<a v-link="{path: '/home/old'}">old</a>
<router-view></router-view>
</template>
<template id="new">
<p>new-content</p>
</template>
<template id="old">
<p>old-content</p>
</template>
<template id="about">
<p>about-content</p>
</template>
</body>
<script>
window.onload = function() {
var Home = Vue.extend({
template: '#home',
methods: {
say: function() {
console.log(this.$route)
}
},
route: {
data: function(transition) {// 此组件链接改变时的钩子
console.log(transition.from.path?'从'+ transition.from.path +'到'+ transition.to.path:'初始化');
transition.next({
currentPath: '/about'
})
}
}
});
var New = Vue.extend({
template: '#new'
});
var Old = Vue.extend({
template: '#old'
});
var About = Vue.extend({
template: '#about'
});
var App = Vue.extend({
data: function() {
return {
}
}
});
var router = new VueRouter();
router.map({// 映射路由
'/home': {
component: Home,
subRoutes: {// 子路由
'/new': {component: New},
'/old': {component: Old}
}
},
'/about': {
component: About
}
});
router.redirect({// 首先展示此页面
'/': 'about'
});
router.beforeEach(function() {// 全局钩子
console.log('切换前');
});
router.afterEach(function() {// 全局钩子
console.log('切换后');
});
router.start(App, '#app');
}
</script>
</html>
编写插件示例:(配合es6语法,待更新)
a. 自调用
myPlugin.js:
import Vue from 'vue';
;(function () {
var MyPlugin = {};
MyPlugin.install = function (Vue, options) {
Vue.directive('mySex', {
inserted(el, binding) {
console.log(binding.value)
}
})
Vue.prototype.$sex = options.sex;
Vue.prototype.$say = function() {
console.log(this.$sex)
};
};
Vue.use(MyPlugin, {sex: 'male'});// 这里调用后,引用该文件无需再调用
})();
main.js:
import Vue from 'vue';
import MyPlugin from 'js/myPlugin.js';
myPlugin.js:
import Vue from 'vue';
export default {
install(Vue, options) {
Vue.directive('mySex', {
inserted(el, binding) {
console.log(binding.value)
}
})
Vue.prototype.$sex = 'female';
Vue.prototype.$say = function() {
console.log(this.$sex)
};
}
}
main.js:
import Vue from 'vue';
import MyPlugin from 'js/myPlugin.js';
Vue.use(MyPlugin, {sex: 'male'});// 这里需要调用一次
c. 自定义组件(也是一种插件方式)
myPlugin.vue:
<template>
<div class="sexClass" @click="say"><slot name="ctn">{{ sex }}</slot></div>
</template>
<script>
import Vue from 'vue';
export default {
data: function() {
return {
sex: 'male'
}
},
methods: {
say: function() {
console.log(this.sex);
}
}
}
</script>
<style>
.sexClass {
background: red;
}
</style>
main.js:
import Vue from 'vue';
import MyPlugin from 'components/myPlugin.vue';
new Vue({
el: '#app',
components: {
'my-plugin': MyPlugin
}
})
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>demo</title>
</head>
<body>
<div id="app">
<my-plugin><div slot="ctn"><button>点击这里</button></div></my-plugin><!-- 在这里使用组件 -->
</div>
</body>
</html>