# Vue简介及基本用法

# Vue.js

Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue的核心库只关注视图层

# Vue.js的特点

  • 虚拟DOM
    基于虚拟DOM,通过预处理操作将页面的更新先全部反映在JS对象(虚拟DOM)上,通过Diff算法操作内存中的JS对象进行批量的更新,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。
  • 双向数据绑定
    将视图层的DOM和模型层的javascript对象进行双向绑定。让开发者不再操作DOM对象,只需关注数据层。
  • 组件化
    通过组件化的方式,将模块抽取为组件模块,实现页面复用。

# Vue开发方式

# 直接script引入

纯浏览器渲染,通过script标签引入的方式,可以快速的适配旧项目的开发。

//index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content='width=device-width,initial-scale=1.0'>
    <meta http-equiv="X-UA-Compatible" content='ie=edge'>
    <title>index</title> 
</head>
<body>
<div id="app">
    {{message}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>    
<script>
new Vue({
    el:'#app',
    data: {
        message:'hello,vue!'
    }
})
</script>
</body>
</html>

# 快速原型开发

安装@vue/cli-service-global依赖,即可基于单个.vue文件进行快速原型的开发。

npm i @vue/cli-service-global -g
// index.vue
<template>
    <div>
        {{message}}
    </div>
</template>
<script>
    export default {
        data(){
            return{
                message:'hello,vue'
            }
        }
    }
</script>
<style scoped>

</style>

然后通过vue serve index.vue方式快速打开,默认会启动localhost:8080,打开即可浏览。

# 命令行CLI开发

Vue提供了一个官方的CLI,为单页面应用 (SPA) 快速搭建繁杂的脚手架。

通过安装vue-cli3并新增项目即可。

npm i @vue/cli -g

新建项目,并选择default方式新建即可。

vue create vue-demo

然后进入vue-demo项目并运行npm run serve,打开项目。

# 项目结构

.
├── public   // 静态资源
|   ├── favicon.ico     
|   └── index.html  
├── package.json // 依赖包配置说明
├── babel.config.js  // babel配置
├── README.md     // 文档说明
├── src         // 源码
     └── assets
            └── logo.png
     └── components  
     |    └── HelloWorld.vue
     └── main.js        
     └── App.vue             

# Vue基本语法

.vue是vue单文件组件,一个文件就是一个组件,由template,script和style三个标签构成,分别对应html, js和css的内容。

# 模板语法

使用{{}}的形式,将DOM和Vue实例的数据进行绑定,实现数据绑定。
其中,实现HTML节点上的属性绑定值需要v-bind指令的形式,可缩写为:attribute的形式。

<template>
    <div>
        <img alt="Vue logo" :src="logo"> //:src绑定节点属性
         {{msg}} //绑定数据
    </div>
</template>
<script>
export default {
    data() {
          return{
              logo: require('./assets/logo.png'),
              msg: 'hello vue'
          }
      },
}
</script>

# 计算属性和监听器

  • 计算属性:computed

通过模板语法的方式可以进行简单的运算和数据绑定,如果需要处理复杂的逻辑,则需要计算属性computed。
其中,通过computed属性实现复杂的逻辑计算时,是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
而通过表达式调用方法来实现逻辑计算则虽然能达到相同效果,则会在每触发重新渲染都会调用方法重新执行函数。

<template>
    <div>
    {{reversedMsg}}
    {{now()}}
    </div>
</template>
export default {
    computed: {
          // 计算属性的 getter
          reversedMsg() {
              // `this` 指向 vm 实例
              return this.msg.split('').reverse().join('')
          }
      },
      methods:{
          now() {
              return new Date().getTime()
          },
      }
}
  • 监听器:watch

当需要在数据变化时执行异步或开销较大的操作时,则可通过watch属性来监听。

//App.vue
<Wat :test="'watch'"/>

// src/components/Watch.vue
export default {
    props: {
        test: {
            default: '',
            type:String
        }
    },
    watch: {
         test(newVal,oldVal){
             console.log(newVal)
             console.log(oldVal)
             this.childTest = newVal
         }
    ,
    data() {
        return {
            childTest: this.test
        }
    }
}

# Class与Style绑定

  • class

通过:class现在绑定class属性,其中可以接受字符串,对象和数组类型。

//其输出class="static active",等同于<div class='static' :class="classObject">
<template>
    <div  class="static"
            :class="{ active: isActive, 'text-danger': hasError }">
        :class
     </div>
</template>
<script>
export default{
    data(){
        return{
            active:true,
            hasError:false,
            classObject: {
                active: true,
                'text-danger': false
            }
        }
    }
}
</script>

:style

通过:style的方式绑定内联样式,其中,CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名。

//其中:style绑定方式等价于:style="[baseStyles,fontStyle]" 和 :style="styleObject"
<template>
    <div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
        内联样式
     </div>
</template>
<script>
export default{
    data() {
          return{
              activeColor: 'yellow',
              fontSize: 20,
              styleObject: {
                  color: 'yellow',
                  fontSize: '20px'
              },
              baseStyles: {
                  color: 'yellow',
              },
              fontStyle: {
                  fontSize: '20px'
              }
          }
}
</script>

# 条件渲染

  • v-if

v-if指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
其中,可使用v-elsev-else-if指令实现条件判断。

<div v-if="show">v-if:true</div>
  • v-show

v-show指令展示结果上和v-if类似,不同的是v-show不管初始条件是否为true还是false, 元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
而v-if则是条件为true才会真正的渲染,为false时则会销毁。
所以,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地 切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

//v-show为false时,css样式默认为display:none
<div v-show="!show">show</div>

# 列表渲染

  • v-for

v-for指令可以用于渲染一个列表,通过item in items形式,item为被迭代的列表元素的别名, items为列表。
其中,列表可接受数组和对象类型,当数组类型时,可接受item和index参数,其中item为数组元素的别名, index为当前项的索引;当列表为对象类型时,可接受value,name和index参数,其value为对象的键值, name为当前项的键名,index为当前项的索引。
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变, Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。 所以,为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供 一个唯一 key 属性。

<template>
    <div v-for="(value, name, index) in object" :key="name">
        {{ index }}. {{ name }}: {{ value }}
    </div>
</template>
<script>
export default{
    data(){
        return{
            object: {
               title: 'hello vue',
               author: 'aaron',
               publishedAt: '2020'
            }
        }
    }
}
</script>

另外,Vue官方不推荐同一元素上使用v-if和v-for,当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。
还需要注意的一点,Vue中不能监听到数组的如下情况的变动:
当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
对应对象属性的添加或删除,也是监听不到,所以这种情况下,需要通过vm.$set的方式实现属性的监听。

export default{
    methods: {
        addAttr(){
            this.$set(this.object,'updateTime',new Date().getDate())
        }
    }
}

# 事件处理

  • v-on
    v-on指令监听DOM事件,可以通过@简写方式实现。
<template>
    <button @click="addCount">点击加1:{{count}}</button>
</template>
<script>
export default{
    data(){
        return{
            count:1      
        }
    },
    methods:{
        addCount() {
            this.count +=1
        }
    }
}
</script>

其中,对应事件处理中需要由阻止默认行为,阻止实现冒泡等要求,Vue为v-on提供了事件装饰符
@click.stop:阻止冒泡
@click.prevent:阻止默认行为
@click.self:只当在 event.target 是当前元素自身时触发处理函数 @click.once:只触发一次
@keyup.enter:键盘回车事件
...

# 表单输入绑定

  • v-model

v-model指令可以实现在表单input、textarea 及 select 元素上创建双向数据绑定。 它会根据控件类型自动选取正确的方法来更新元素。

其中,可通过修饰符,.lazy实现输入框值change事件时才同步数据而非input事件时触发; .number实现Vue默认调用parseFloat解析字符串;trim去除输入的首尾空白字符。

v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
text 和 textarea 元素使用 value 属性和 input 事件;
checkbox 和 radio 使用 checked 属性和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。

<template>
    文本:<input v-model.lazy="value">
      多行文本:<textarea v-model="value" placeholder="add multiple lines"></textarea>
      <p>value:{{value}}</p>
      复选框:
      <div>
        <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
        <label for="jack">Jack</label>
        <input type="checkbox" id="john" value="John" v-model="checkedNames">
        <label for="john">John</label>
        <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
        <label for="mike">Mike</label>
        <br>
        <span>Checked names: {{ checkedNames }}</span>
      </div>
      单选框:
      <div>
        <input type="radio" id="one" value="One" v-model="picked">
        <label for="one">One</label>
        <br>
        <input type="radio" id="two" value="Two" v-model="picked">
        <label for="two">Two</label>
        <br>
        <span>Picked: {{ picked }}</span>
      </div>
      选择框:
      <select v-model="selected">
        <option v-for="option in options" :value="option.value" :key="option.value">
          {{ option.text }}
        </option>
      </select>
      <span>Selected: {{ selected }}</span>
</template>
<script>
export default{
    data(){
        return{
            value:'',
            checkedNames:[],
            picked: '',
            selected: 'A',
            options: [
                { text: 'One', value: 'A' },
                { text: 'Two', value: 'B' },
                { text: 'Three', value: 'C' }
             ]
        }
    }
}
</script>

项目源码对应地址:https://github.com/PCAaron/blogCode/tree/master/vue/vue-demo

# 推荐阅读

Vue视频教材:https://learning.dcloud.io/#/?vid=0

Vue:https://cn.vuejs.org/

Vue-CLI:https://cli.vuejs.org/zh/guide/cli-service.html

风格指南:https://cn.vuejs.org/v2/style-guide/