Vue 基本语法

Vue 介绍

什么是Vuejs?

  • 官网
  • Vue 读音 /vjuː/,类似于 view
  • 渐近式框架
  • 高级功能
    • 解耦视图和数据
    • 可复用的组件
    • 前端路由技术
    • 状态管理
    • 虚拟DOM

安装Vue

  • 直接CDN引入
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
npm install vue

简单案例

显示普通信息

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>index</title>
        <script src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <h1>{{message}}</h1>
        </div>
    </body>
    <script>
        // 编成范式:声明式编程
        const app = new Vue({
            el: "#app", // 用于挂载要管理的元素
            data: {     // 定义数据
                message: "Hello Vue"
            }
        })
    </script>
</html>

显示个列表信息

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>index</title>
        <script src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <ul>
                <li v-for="item in movies">
                    {{item}}
                </li>
            </ul>

        </div>
    </body>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                movies: ['流浪地球', '无名之辈', '恶人传', '寄生虫']
            }
        })
    </script>

</html>

实现计数器

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>index</title>
        <script src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <h3>当前计数:{{counter}}</h3>
            <!-- <p><button v-on:click="counter++">+</button></p> -->
            <!-- <p><button v-on:click="counter--">-</button></p> -->
            <button v-on:click="plus">+</button>
            <button @click="reduce">-</button>
        </div>
    </body>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                counter: 0
            },
            methods: {
                plus: function() {
                    this.counter++
                },
                reduce () {
                    this.counter--
                }
            }
        })
    </script>
</html>

MVVM

MVVM框架

MVVM:Model View ViewModel
view层:视图层,在前端通常是DOM层,主要用来展示信息
Model层:数据层,通常都是从后端请求过来的数据
VueModel层:视图模型层,
Data Binding,数据绑定,将Model的改变实时的反应到View中;
DOM Listenter,DOM监听,当DOM发生事件,可以被监听到,并在需要的情况下改变对应的Data

使用到Vue的options

  • el:
    • 类型:string | HTMLElement
    • 作用:决定之后Vue实例管理的一个DOM
  • data:
    • 类型:Object(字典) | Function(组件当中data必须是一个函数)
    • 作用:Vue实例对应的数据对象
  • methods:
    • 类型:{[key: string]: Function()
    • 作用:定义属于Vue的一些方法

生命周期

Vue基本语法

插值操作

  • Mustache
    表示:{{}}
    用法:括号内JS表达式
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
  • v-once
    说明:执行一次性地插值,当数据改变时,插值处的内容不会更新。
    用法:<span v-once>{{ msg }}</span>

  • v-html
    说明:输出真正的HTML,为防止XSS攻击,不要对用户提供的内容使用
    用法:

<p v-html="rawHtml"></p>

data: {
  	rawHtml: "<span style='color: red'>This should be red.</span>"
}
  • v-text
    说明:插入文本,不够灵活,会自动覆盖标签内的值
    用法:<span v-text="msg"></span>

  • v-pre
    说明:不解析{{}}的值
    用法:<span v-pre>{{ msg }}</span>渲染的结果仍是{{msg}}

  • v-cloak
    说明:可以用来隐藏未编译的Mustache标签直到实例准备完成。

    <style>
    [v-cloak]{
      display: none;
    }
    </style>

    <div id="app">
      <h1 v-cloak>{{message}}</h1>
    </div>
    
  <script>
    // 在vue解析之前,div中有一个属性v-cloak
    // 在vue解析之后,会自动删除v-cloak
    setTimeout(function(){
      const app = new Vue({
        el: "#app", 
        data: {     
          message: "Hello Vue",
        }
      });
    }, 3000)
  </script>

v-bind 属性绑定

说明:动态绑定属性
语法糖:
用法:<a v-bind:href="url"> click </a>

v-bind绑定class属性

  • 对象语法
    用法:<div :class="{ 属性名: 变量 }"></div>,变量的值为true或false
<div class="static" :class="{ active: isActive}">
	Hello Vue
</div>

data: {
  isActive: true,
}

绑定的数据对象可以不用在在模板里

<div v-bind:class="classObject"></div>

data: {
  classObject: {
    active: true,
  }
}

还可以把数据对象放到计算属性上

<div :class="classObject"></div>

data: {
  isActive: true,
},
computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
    }
  }
}
  • 数组语法
<div :class="[active, error]"></div>

data: {
  active: 'active',
  error: 'text-danger'
}

可以在数组中使用三元表达式

<div :class="[isActive ? 'active' : '', error]"></div>

在数组中加上引号就是字符串,不加引号就是变量,数组和对象可以混合使用

在组件上的使用
当在一个自定义组件上使用 class 属性时,这些 class 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。

Vue.component('my-component', {
  template: '<p class="foo bar">Hi</p>'
})

<my-component :class="{ active: isActive }"></my-component>

# 结果:
<p class="foo bar active">Hi</p>

v-bind绑定style属性

  • 对象方法
    key:值为属性名称,驼峰式(fontSize)或短横线分隔(font-size引号括起来
    value:值为变量
<div :style="{ color: color, fontSize: fontSize }"></div>
data: {
  color: 'red',
  fontSize: '30px'
}

也可以直接绑定一个样式对象

<div :style="styleObject"></div>

data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}
  • 数组语法
<div :style="[baseStyles, ]"></div>

计算属性

  • 基本使用
    当一个变量改变时另一个变量可以发生改变,或者模板中插值操作的表达式太过复杂时,都可以把变量拿出来放到computed内。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>index</title>
    <script src="../vue.js"></script>
  </head>
  <body>
    <div id="app">
        <h1>{{msg}}</h1>      
        <h1>{{reverseMsg}}</h1>
    </div>
  </body>
  <script>
    const app = new Vue({
      el: "#app", 
      data: {
        msg: "Hello Vue",
      },
      computed: {
        reverseMsg: function () {
          return this.msg.split("").reverse().join('')
        }
      }
    });
  </script>
</html>
  • 和方法比较
    通过方法也能实现相同效果:
<h1>{{reverseMsg()}}</h1>

methods: {
  reverseMsg: function () {
    return this.msg.split('').reverse().join('')
  }
}

不同点:计算属性是基于它们的响应式依赖进行缓存的,只用相关响应式依赖发生改变时它们才会重新求值,这就意味着只要 message 还没有发生改变,多次访问 reversedMsg 计算属性会立即返回之前的计算结果,而不必再次执行函数;而每当触发重新渲染时,对于方法渲染,将总会再次执行函数。

  • 和侦听属性比较
    侦听属性watch,当用数据改变时,调用watch,如下:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>index</title>
    <script src="../vue.js"></script>
  </head>
  <body>
    <div id="app">
        <h1>{{fullname}}</h1>      
    </div>
  </body>
  <script>
    const app = new Vue({
      el: "#app", 
      data: {
        firstName: "Foo",
        lastName: "Bar",
        fullname: "Foo Bar"
      },
      watch: {
        firstName: function(newVal, oldVal){
          this.fullname = newVal + " " + this.lastName
        },
        lastName: function(newVal, oldVal){
          this.fullname = this.firstName + " " + newVal
        }
      }
    });
  </script>
</html>

使用计算属性

      computed: {
        fullname: function () {
          return this.firstName + " " + this.lastName
        }
      }, 

虽然计算属性在大多数情况下更合适,但当需要在数据变化时执行异步或开销较大的操作时,watch方式是最有用的。

  • 计算属性的setter
    计算属性默认只有getter,不过在需要时也提供一个setter:
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newVal) {
      let names = newVal.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

事件监听

指令:v-on
作用:绑定事件监听
语法糖:@
预期:Function | Inline Statement | Object
参数:event
简单示例,点击按钮实现数字加减

    <div id="app">
      <h3>{{count}}</h3>
      <button @click="increment">+</button>
      <button @click="decrement">-</button>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          count: 0
        },
        methods: {
          increment () {
            this.count++
          },
          decrement () {
            this.count--
          },
        }
      });
    </script>

事件监听也可以传参数

  • 当不需要传参数时,模板中可以省略()
  • 模板有(),但是没传参数,方法的参数值为undefined
  • 模板中事件传参数,方法得到相对应的值
  • 当模板中省略(),但是方法内有形参,得到的结果时监听事件
    <div id="app">
      <button @click="btn1">按钮1</button>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        methods: {
          btn1 (event) {
            console.log(event);
          }
        }
      });
    </script>
  • 当方法内既想得到普通参数,又想得到监听事件,使用$event
    <div id="app">
      <button @click="btn(123, "abc", $event)">按钮</button>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        methods: {
          btn (num, chr, event) {
            console.log(num, chr, event);
          }
        }
      });
    </script>

v-on的修饰符:

  • .stop,调用event.stopPropagation(),当父、子标签上都有事件时,阻止事件冒泡,加在子标签上
  • .prevent,调用event.preventDefault(),阻止默认事件
  • .(keyCode | keyAlias),只有当事件是从特定键触发时才能触发回调,如:@keyup.a=funcName
  • .native,监听组件根元素的原生事件
  • .once,只能触发一个回调

条件判断指令

指令:v-if, v-else-if, v-else
使用方式:

   <div id="app">
     <h2 v-if="score>100">S</h2>
     <h2 v-else-if="score>80">A</h2>
     <h2 v-else-if="score>60">B</h2>
     <h2 v-else>C</h2>
   </div>
   <script>
     const app = new Vue({
       el: "#app",
       data: {
         score: 0
       },
     });
   </script>

案例:切换登录方式

<div id="app">
  <span v-if="loginStyle">
    <label for="username">账号</label>
    <input type="text" id="username" placeholder="用户账号">
  </span>
  <span v-else>
    <label for="email">邮箱</label>
    <input type="text" id="email" placeholder="用户邮箱">
  </span>
  <button @click="loginStyle = !loginStyle">切换类型</button>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      loginStyle: true
    }
  })
</script>

问题:容易出现input复用问题,当一个输入框内有用户输入,切换登录方式时,用户输入的内容还在
原因:因为Vue使用虚拟DOM渲染,出于性能考虑,会尽可能地复用已经存在地元素,而不是重新创建新的元素
解决:给每个input加上不同地key属性

  <span v-if="loginStyle">
    <label for="username">账号</label>
    <input type="text" id="username" placeholder="用户账号" key="username">
  </span>
  <span v-else>
    <label for="email">邮箱</label>
    <input type="text" id="email" placeholder="用户邮箱" key="email">
  </span>

类似可以隐藏标签的指令还有v-show

v-show和v-if一样,都是决定标签是否被渲染
不同点时,v-if为false时,标签就根本不会存在;而v-show的实质是样式为display: none,适用于需要频繁切换显示和隐藏的标签

循环指令

指令:v-for
使用:

    <div id="app">
      <ul>
        <li v-for="movie in movies">{{movie}}</li>
      </ul>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          movies: ['无名之辈', "流浪地球", '寄生虫', '魔童降世', "战狼2"]
        },
      });
    </script>

在遍历时可以获得索引值v-for="(movie, index) in movies",如果遍历对象时,也可以获得key、value和index值v-for="value, key, index in object"

官方推荐使用v-for时,使用key属性,但要保证key的唯一性,不建议使用索引值。原因是当数组插入数据时,index发生变化,就不能利用key的特性

为什么使用key属性?这个Vue的虚拟DOM的Diff算法有关。

参考React's diff algorithm
一般来讲,在5个组件数组中插入一个组件,得到新的数组,两个组件数组形成映射关系是非常难的,

默认的,diff算法是把两个数组按顺序形成映射。但是如果你加入key属性,就可以帮助diff快速形成映射。

哪些数组方法是响应式的?

push(); pop(); shift(); unshift(); splice(); sort(); reverse()
用法参考:数组方法的使用
注意:通过索引值修改数组中的元素不是响应式 ,如果要修改元素可以通过splice(),或者使用Vue.set(要修改的对象, 索引值, 修改后的值)

表单绑定

指令:v-model
作用:实现表单元素与数据的双向绑定
基本使用:

    <div id="app">
      <input type="text" v-model="message">
      <h3>{{message}}</h3>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          message: "hello"
        },
      });
    </script>
<!--这里的v-model绑定的就是input的value值-->

相当于:v-bindv-on搭配使用

    <div id="app">
      <input type="text" :value="message" @input="valueChange">
      <h3>{{message}}</h3>
      <!--另外写法-->
      <input type="text" :value="message" @input="message=$event.target.value">
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          message: "hello"
        },
        methods: {
          valueChange (event) {
            this.message = event.target.value;
          }
        }
      });
    </script>

其他使用:

  • radio,单选框,当有 v-model 时,可以省略 name 属性
    <div id="app">
      <input type="radio" value="男" v-model="sex">男
      <input type="radio" value="女" v-model="sex">女
      <h3>性别:{{sex}}</h3>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          sex: "男"  // 默认值
        },
      });
    </script>
  • checkbox,复选框
    <!--单选框-->
    <div id="app">
      <label for="agreement">
        <input type="checkbox" id="agreement" v-model="isAgree">用户协议
      </label>
      <p><button :disabled="!isAgree">Next</button></p>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          isAgree: false
        },
      });
    
    <!--多选框使用-->
    <div id="app">
      <input type="checkbox" value="篮球" v-model="hobby">篮球
      <input type="checkbox" value="足球" v-model="hobby">足球
      <input type="checkbox" value="羽毛球" v-model="hobby">羽毛球
      <h2>{{hobby}}</h2>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          hobby: ['篮球']
        },
      });
    </script>
  • select
    <!--单选-->
    <div id="app">
      <select name="province" id="" v-model="province">
        <option value="安徽">安徽</option>
        <option value="江苏">江苏</option>
        <option value="上海">上海</option>
      </select>
      <h2>{{provice}}</h2>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          province: "上海"
        },
      });
    </script>
    
    <!--多选-->
    <div id="app">
      <select name="province" id="" v-model="provinces" multiple>
        <option value="安徽">安徽</option>
        <option value="江苏">江苏</option>
        <option value="上海">上海</option>
      </select>
      <h2>{{provice}}</h2>
    </div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          provinces: ["上海"]
        },
      });
    </script>   

修饰符:

  • lazy:可以让数据失去焦点或者回车时才会更新
  • number:把输入的内容自动转换成数字类型,和type="number"(只能输入数字)配合使用
  • trim:可以过滤内容左右两边的空格

Vue的options之过滤器

    <div>{{price|showPrice}}</div>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          price: 56.00
        },
        filters: {
          showPrice (price) {
            return "¥" + price.toFixed(2) // 显示小数点后2位
          }
        }
      });
    </script>
posted @ 2020-03-08 19:28  yw_sun  阅读(229)  评论(0)    收藏  举报