Vue.js

Vue是一套用户构建用户界面的渐进式框架,其核心是允许采用简洁的模板语法来声明式的将数据渲染进DOM。

构建项目

# 安装node.js和npm
$ npm install vue
$ npm install vue-cli -g # 全局安装
$ vue init webpack my-project # 基于webpack模板构建
$ cd my-project
$ npm install # 安装依赖
$ npm run dev

# 运行git clone 项目
$ cd project
$ npm install --save # 保存在package.json的dependencies(生产环境)中, --save-dev 保存在devDependencies(开发环境)
$ npm i <package> -S -D # 安装 -S = --save -D --save-dev
$ npm run dev
$ npm run build # 打包压缩

# cnpm, 是国内的淘宝镜像,支持publish之外的所有命令
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
$ cnpm install -g yarn
$ yarn install # yarn 相比npm速度更快

基础

// <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

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

var app = new Vue({
    el: '#app',
    data: {
        message: 'hello, world'
    }
})

v- 表示Vue提供的特殊特性
v-once // 一次性插值
v-html // 原始html
v-bind // 响应式更新html
v-if // if
v-for // for
v-on // 监听DOM事件
v-on:submit.prevent="onSubmit" // 修饰符
v-model // 在表单元素上创建双向数据绑定

// 定义组件
Vue.component('todo-item', {
    template: '<li>这是一个代办项</li>'
})

// 创建Vue实例
var data = {a: 1, message: 'hello'}
var vm = new Vue({
    data: data
})
// 只有data中的数据是响应式的
Object.freeze(data) // 会阻止修改现有的属性

vm.a = data.a // 数据属性
// 实例属性和方法
vm.$el = document.getElementById('expmple')
vm.$data = data
vm.$watch('a', function (newValue, oldValue)) {
    // 这个回调将在a改变后调动
}

var vm = new Vue({
    el: '#expmple',
    data: data,
    created: function () {
        // 钩子函数,在实例被创建时执行
    },
    methods: { // 方法, 没有缓存
        reverseMessage: function () {
            return this.message.split('').reverse().join()
        }
    },
    computed: { // 计算属性, 只有当message改变时, 才会重新求值, 有缓存
        reverseMessage: function () {
            return this.message.split('').reverse().join()
        },
        fullNmae: {
            // getter
            get: function () {
                return this.fistName + ' ' + this.lastName
            },
            // setter
            set: function (newValue) {
                var names = newValue.split(' ')
                this.firstName = names[0]
                this.lastName = names[name.length - 1]
            }
        }
    },
    watch: { // 侦听属性
        firstName: function (val) {
            this.fullName = val + ' ' + this.lastName
        }
    }
})

// 模板语法
<span>Message: {{ msg }}</span> 文本插值,不能在html上
<span v-once>这个不会改变: {{ msg }}</span>
v-html 使用html
<button v-bind:disabled="isButtonDisabled">Button</button> 数据使用在html上
<p v-if="seen">现在看到我了</p>
<a v-bind:href="url"></a>
<a v-on:click="doSomething"></a>
<from v-on:submit.prevent="onSubmit"></from>

<a v-bind:href="url"></a> 缩写 <a :href="url"></a>
<a v-on:click="doSomething"></a> 缩写 <a @click="doSomething"></a>

// 绑定html class
<div v-bind:class="{ active: isActive }"></div>
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px'}"></div>

// 条件
<div v-if="type === 'A'"></div>
<div v-else_if="type === 'B'"></div>
<div v-else="type === 'C'"></div>

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

// 列表渲染
<li v-for="item in items">
    {{ item.message }}
</li>

<li v-for="(item, index) in items">
<div v-for="item of items"></div> // 迭代器

var explame = new Vue({
    el: '#explame',
    data: {
        items: [
            { message: 'Foo'},
            { message: 'Bar'}
        ]
    }
})

动态添加,触发响应更新
Vue.set(vm.items, indexOfItem, newValue) // 或
vm.$set(vm.items, indexOfItem, newVaule)

// 监听事件
v-on
事件修饰符
v-on:click.stop // 阻止单机事件继续
v-on:submit.prevent="onSubmit" // 提交事件不再重载页面
v-on:click.capture // 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理
v-on:click.self // 即事件不是从内部元素触发的
v-on:click.once // 只会触发一次
v-on:scroll.passive="onScroll" // 滚动事件的默认行为 (即滚动行为) 将会立即触发

按键修饰符
<input v-on:keyup.enter="submit"> // 只有按enter时,才执行

// 表单输入绑定
v-model 对<input> <textarea> <select> 有效

修饰符
v-model.lazy // 在change时更新
v-model.number // 自动输入值转为数值类型
v-model.trim // 过滤用户输入的首尾空白字符

// 组件
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {  // data 必须是一个函数
    return {
      count: 0
    }
  },
  props: ['title'],
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

<div id="components-demo">
  <button-counter title="hello"></button-counter>
</div>

new Vue({ el: '#components-demo' })

通过props向子组件传递数据
通过$emit向父组件发送消息
v-on:click="$emit('enlarge-text', 0.1)"

在组件中使用v-model
Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})
<custom-input v-model="searchText"></custom-input>

组件

Vue.component('my-component-name', { // 全局
    // pass
})

new Vue ({ el: '#app'})

<div id="app">
    <my-component-name></my-component-name>
</div>

var ComponentA = {} // 局部
new Vue ({
    el: '#app',
    components: {
        'component-a': ComponentA
    }
})

基础组件全局注册要在根Vue实例创建之前发生

// Prop
props 用短横写法
props: {
    title: String, // 可以定义类型
    likes: Number
}

Vue.component('blog-post', {
    props: ['post-title'],
    template: '<h3>{{ post-title }}</h3>'
})

<blog-post v-bind:post-title="post.post-title"></blog-post>

props 可以类型检查
inheritAttrs: false // 禁用特性继承

// 插槽内容
<slot name="header"></slot>

// 动态组件
<keep-alive> // 会缓存失活的组件
    component v-bind:is="currentTabComponent"></component> // 切换组件
</keep-alive>

Vue.component( // 异步组件
  'async-webpack-example',
  // 这个 `import` 函数会返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

new Vue({
 data: {
    foo: 1
 }
})

this.$root.foo // 获取根实例
this.$parent.map // 获取父级组件实例
this.$refs.usernameInput // 访问子组件实例
provide: function () { // 依赖注入
  return {
    getMap: this.getMap
  }
}
inject: ['getMap']

过渡

使用transition组件,可以给任何元素和组件添加进入/离开过渡
<div id="demo">
  <button v-on:click="show = !show">
    Toggle
  </button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>

new Vue({
  el: '#demo',
  data: {
    show: true
  }
})

.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

// 配合css动画库
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">

// 数据也可以过渡动画

组合

// 混入
var myMixin = {
    created: function () {
        this.hello()
    },
    methods: {
        hello: function () {
            console.log('hello from mixin')
        }
    }
}

var Component = Vue.extend({
    mixins: [myMixin]
})

var component = new Component() // "hello from mixin"