本文不是vue的系统性学习,只是基础部分的快速上手(本文以Vue2为例)

Vue2官网

Vue3官网

引入

<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>

声明式渲染

看一个简单的案例

<body>
<div id="app" v-bind:title="title">
    {{message}}
</div>
<script>
    var app = new Vue({
        el: '#app',
        data:{
            message:'hello vue!',
            title:'dzr'
        }
    })
</script>
</body>

使用vue之后我们不再和 HTML 直接交互了,一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 #app) 然后对其进行完全控制

v-bind attribute 被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute

条件指令

这个案例里v-if中flag若为true则显示div内容

<body>
<div id="app">
    <div v-if="flag">hello dzr</div>
</div>
<script>
    var app = new Vue({
        el:"#app",
        data:{
            flag:true
        }
    })
</script>
</body>

如果是v-show则是通过css样式来隐藏

如果频繁隐藏显示建议使用v-show

<div v-show="flag">hello dzr</div>

循环指令

下面是一个乘法表,在控制台可以通过修改app.num来更换乘法表行列数

<body>
<div id="app">
    <table border="1">
        <tr v-for="i in num">
            <td v-for="j in i">{{j}}*{{i}}={{j*i}}</td>
        </tr>
    </table>
</div>
<script>
    var app = new Vue({
        el:"#app",
        data:{
            num:9
        }
    })
</script>
</body>

处理用户输入

事件监听

v-on 指令添加一个事件监听器,通过它调用在 Vue 实例中定义的方法

<body>
<div id="app">
    <div>{{message}}</div>
    <button v-on:click="reverseMessage">翻转消息</button>
</div>
<script>
    var app = new Vue({
        el:"#app",
        data:{
            message:'hello,dzr!'
        },
        methods:{
            reverseMessage(){
                this.message = this.message.split('').reverse().join('')
            }
        }
    })
</script>
</body>

双向绑定

v-model 指令能实现表单输入和应用状态之间的双向绑定

<body>
<div id="app">
    <div>{{message}}</div>
    <input type="text" v-model="message">
</div>
<script>
    var app = new Vue({
        el:"#app",
        data:{
            message:'hello,dzr!'
        }
    })
</script>
</body>

组件

一个组件本质上是一个拥有预定义选项的一个 Vue 实例

<body>
<div id="app">
    <dzr v-bind:name="dzr"></dzr>
</div>
<script>
    Vue.component("dzr",{
        props:['name'],
        template:'<h1>hello,{{name}}!</h1>'
    })
    var app = new Vue({
        el:"#app",
        data:{
            message:'hello,dzr!',
            dzr:"正如"
        }
    })
</script>
</body>

实例

当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中

当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值

值得注意的是只有当实例被创建时就已经存在于 data 中的 property 才是响应式的,即后面创建的不响应

使用 Object.freeze(),这会阻止修改现有的 property,也就是响应系统无法再追踪变化

created 钩子可以用来在一个实例被创建之后执行代码,也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mountedupdateddestroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。

<body>
<div id="app">
    <div>{{a}}</div>
</div>
<script>
    var data = {a:1}
    Object.freeze(data)
    var app = new Vue({
        el:"#app",
        data:data,
        created (){
            console.log("vue create")
        }
    })
    console.log(data.a == app.a)
    data.a = 99
    console.log(app.a)
    console.log("<<<<<<<<<<<<<<<<<<<<<<<")
    console.log(app.$el == document.getElementById("app"))	// => true
    console.log(app.$data == data)	// => true
</script>
</body>

模板

v-once 指令,可以执行一次性地插值,当数据改变时,插值处的内容不会更新

v-html指令,可以输出真正的HTML

v-bind指令,让语法能够作用在 HTML attribute 上

值得注意的是{{ }}中流控制不会生效,请使用三元表达式

<body>
<div id="app">
    <div>{{a}}</div>
    <button v-bind:disabled="!enableBtn" v-on:click="num++">按钮</button>
    <div v-html="a"></div>
    <div>{{num>101?"good":num}}</div>
</div>
<script>
    var app = new Vue({
        el:"#app",
        data:{
            a:"<h1>Hello,DZR</h1>",
            b:null,
            enableBtn:true,
            num:99
        }
    })
</script>
</body>

计算属性

与方法相比,计算属性有缓存,比如下面如果message没有变化,则会调用缓存

下面的计算属性的set方法是当app.reverseMessage发生变化时会调用

<body>
<div id="app">
    <div>{{reverseMessage}}</div>
    <!--    <div>{{reverseMessage()}}</div>-->
</div>
<script>
    var app = new Vue({
        el:"#app",
        data:{
            message:'hello,dzr!'
        },
        computed:{
            reverseMessage:{
                get(){
                    return this.message.split('').reverse().join('')
                },
                set(newValue){
                    console.log("set:"+newValue)
                }
            }
            // reverseMessage(){
            //     return this.message.split('').reverse().join('')
            // }
        },
        // methods:{
        //     reverseMessage(){
        //         return this.message.split('').reverse().join('')
        //     }
        // }
    })
</script>
</body>

侦听器

这里侦听了firstNamelastName,当他们发生变化时会更新fullName,在这里使用watch是为了演示侦听器的用法,实际中一些复杂的异步才会使用watch,否则使用计算属性computed即可

<body>
<div id="app">
    <div>{{fullName}}</div>
</div>
<script>
    var app = new Vue({
        el:"#app",
        data:{
            firstName:'zhang',
            lastName:'san',
            fullName:'zhang san'
        },
        watch:{
            firstName(val){
                this.fullName = val + " " + this.lastName
            },
            lastName(val){
                this.fullName =this.firstName + " " + val
            }
        }
    })
</script>
</body>

Class绑定

动态和静态可以共存,放flagtrue时,mydiv会生效,动态也可以有多个,也可以创建一个对象如下面的classObj

<body>
<div id="app">
    <div v-bind:class="{mydiv:flag,mydiv2:flag}" class="mydiv1">{{msg}}</div>
    <div v-bind:class="classObj" class="mydiv1">{{msg}}</div>
</div>
<script>
    var app = new Vue({
        el:"#app",
        data:{
            msg: "hello,dzr!",
            flag: true,
            classObj:{
                mydiv:true,
                mydiv2:true
            }
        }
    })
</script>
<style>
    .mydiv2{
        border: 1px solid;
    }
    .mydiv1{
        font-size: 30px;
    }
    .mydiv{
        font-weight: bold;
        color: #ff0000;
    }
</style>
</body>

Style绑定

跟上面的差不多

条件渲染

  • 想用v-if切换多个元素可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if,最终的渲染结果将不包含 <template> 元素,另外v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别
  • 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好
  • 不推荐同时使用 v-ifv-for,当 v-ifv-for 一起使用时,v-for 具有比 v-if 更高的优先级

列表渲染

<body>
<div id="app">
  <table border="1px">
    <tr>
      <td>序号</td>
      <td>书名</td>
      <td>作者</td>
    </tr>
    <tr v-for="(book,index) in books" v-bind:key="index">
      <td>{{index+100 }}</td>
      <td>{{book.name}}</td>
      <td>{{book.author}}</td>
    </tr>
  </table>
  <hr>
  <div v-for="(s,p,index) in site" v-bind:key="index">{{s}}--{{p}}--{{index}}</div>
</div>
<script>
  var app = new Vue({
    el:"#app",
    data:{
      books:[
        {
          name:"三国演义",
          author:"罗贯中"
        },{
          name:"红楼梦",
          author:"曹雪芹"
        },{
          name:"水浒传",
          author:"施耐庵"
        },{
          name:"西游记",
          author:"吴承恩"
        },
      ],
      site:{
          author:"dzr",
          url:"zhengru.top",
          server:"Tencent"
      }
    }
  })
</script>
</body>

数组更新检测

变更方法

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

比如上面的例子就可以通过app.books.push({name:"123",author:"456"}) 5来更新数组

替换数组

变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()concat()slice()。它们不会变更原始数组,而总是返回一个新数组

上面的例子可以通过app.books=app.books.concat({name:"456",author:"789"})添加一组数据

从第0个开始删除1个并添加一组数据app.books.splice(0,1,{name:"abc",author:"def"})

Vue.set(app.site,"ip","0.0.0.0")

事件处理

v-on前面已经提到过了,可以在methods里定义方法再去调用

new Vue({
  el: '#example-3',
  methods: {
    say: function (message) {
      alert(message)
    }
  }
})

按键码

为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

表单输入绑定

文本

<input type="text" v-model="message">
<div>{{message}}</div>

多行文本

<textarea v-model="textarea" name="" id="" cols="30" rows="10"></textarea>
<p style="white-space: pre-line;">{{textarea}}</p>

复选框

<input type="checkbox" value="" v-model="favourites">
<input type="checkbox" value="" v-model="favourites">
<input type="checkbox" value="Rap" v-model="favourites">
<input type="checkbox" value="篮球" v-model="favourites">
<div>{{favourites}}</div>

单选按钮

<input type="radio" value="" v-model="gender"><input type="radio" value="" v-model="gender"><div>{{gender}}</div>

选择框

学历:
<select v-model="edu">
    <option value="小学">小学</option>
    <option value="初中">初中</option>
    <option value="高中">高中</option>
</select>
<div>{{edu}}</div>

多选框

<select v-model="favourite2" multiple>
    <option value=""></option>
    <option value=""></option>
    <option value="Rap">Rap</option>
    <option value="篮球">篮球</option>
</select>
<div>{{favourite2}}</div>

修饰符

.lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步

你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步

.number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符

.trim

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符

组件基础

// 定义一个名为dzr的新组件
Vue.component('dzr', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

组件复用

data必须是一个函数

data: function () {
  return {
    count: 0
  }
}

通过Prop向子组件传递数据

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

单个根元素

可以将模板的内容包裹在一个父元素内,来修复这个问题

监听子组件事件

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

使用事件抛出一个值

可以使用 $emit 的第二个参数来提供这个值

<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

插槽

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
      <slot></slot>
    </div>
  `
})

动态组件

在下面的示例中,currentTabComponent 可以包括

  • 已注册组件的名字
  • 一个组件的选项对象
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

到这里简单入了个门,其他的等后续再慢慢补充…

基本环境搭建

安装NodeJS和npm后在cmd中运行

npm install -g vue-cli   # 只需要第一次安装时执行
npm install -g @vue-cli@3.11.0   # 指定版本
vue init webpack my-project  # 使用webpack模板创建一个vue项目
cd my-project #进入到项目目录中
npm install  # 下载依赖(如果在项目创建的最后一步选择了自动执行npm install,则该步骤可以省略)
npm run dev # 启动项目