• Vuejs基础使用


    快速入门

    引入vue

    <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 Vue!'
      }
    })
    

    生命钩子

    1.jpg

    2.jpg

    样式绑定

    class绑定

    • 对象语法

      根据条件判断是否添加该class

      <div id="app" :class="{fontColor:isClass}">123</div>
      
      .fontColor{
          color: red;
      }
      
      var vm = new Vue({
          el: '#app',
          data: {
              isClass:true
          },
      })
      
    • 数组语法

      传数组以应用一个 class 列表

      <div id="app" :class="[fontClass,divClass]">123</div>
      
      var vm = new Vue({
          el: '#app',
          data: {
              fontClass:'baseFont',
              divClass:'baseDiv'
          },
      })
      
        .baseFont{
            font-size: 40px;
            font-weight: 700;
            color: brown;
        }
        .baseDiv{
            display: block;
             200px;
            height: 200px;
            background-color: blueviolet;
        }
      
    • 三元表达式

      根据条件决定是否添加该class

      <div id="app" :class="[isFont?fontClass:'',divClass]">123</div>
      
      var vm = new Vue({
          el: '#app',
          data: {
              isFont:false,
              fontClass:"baseFont",
              divClass:"baseDiv"
          },
      })
      

      也可以用对象语法写,会更清晰。此时baseFont不是变量,而是类名

      <div id="app" :class="[{baseFont:isFont},divClass]">123</div>
      

    style绑定

    • 对象语法

      与css相似

      <div id="app" :style="{color:baseColor,fontSize:baseSize}">123</div>
      
      var vm = new Vue({
          el: '#app',
          data: {
              baseColor:'red',
              baseSize:'40px'
          },
      })
      

      你也可以在直接绑定到一个样式对象,会更清晰

      <div id="app" :style="baseFont">123</div>
      
      var vm = new Vue({
          el: '#app',
          data: {
              baseFont:{
                 color:'red',
                 fontSize:'40px'
              }
          },
      })
      
    • 数组语法

      将多个样式对象应用到同一个元素上

      <div id="app" :style="[baseFont,basediv]">123</div>
      
      var vm = new Vue({
          el: '#app',
          data: {
              baseFont:{
                 color:'red',
                 fontSize:'40px'
              },
              basediv:{
                  display:'block',
                  '100px',
                  height:'100px',
                  backgroundColor:'green'
              }
          },
      })
      

    条件渲染

    v-if

    • 指令表达式返回 true时才会渲染内容

      <div id="app">
          <h1 v-if="cool">cool~~~</h1>
      </div>
      
      data: {
          cool: true
      },
      
    • 可以与v-else配合,如果不是true将返回v-else的内容

      <div id="app">
          <h1 v-if="cool">cool~~~</h1>
          <h1 v-else>what?</h1>
      </div>
      
    • 多个条件时可以用v-else-if

      <div id="app">
          <h1 v-if="cool===1">cool~~~~</h1>
          <h1 v-else-if="cool===2">what?</h1>
          <h1 v-else="cool===3">I don't know </h1>
      </div>
      
      data: {
          cool: 2
      },
      

    key

    • 一般情况下,Vue会复用已有元素

      <div id="app">
          <template v-if="username">
              Username:<input placeholder="Enter your username">
          </template>
      
          <template v-else>
              Email:<input placeholder="Enter your email address">
          </template>
      
          <br/><input type="button" @click="username=!username" value="change">
      </div>
      
      data: {
          username: true
      },
      

      template可用于包裹元素。在上面例子中,如果你已经输入了内容,由于Vue的复用,切换时内容将不会清空

    • key管理可复用元素,将元素独立开。应用时只需在需要独立的元素上加上不同的key值

      Username:<input placeholder="Enter your username" key="1">
      Email:<input placeholder="Enter your email address" key="2">
      

    v-show

    • v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display

      <h1 v-show="show">Hello!</h1>
      
    • 不支持<template>

    列表渲染

    v-for

    • 一个数组对应一组元素

      <ul id="list">
          <li v-for="animal in animals">
              {{animal.name}}
          </li>
      </ul>
      
      var vm = new Vue({
          el: '#list',
          data: {
              animals:[
                  {name:'狮子'},
                  {name:'黑豹'},
                  {name:'小猪'},
              ]
          },
      })
      

      第二个参数:索引

      <li v-for="(animal,i) in animals">
          {{i}}-{{animal.name}}
      </li>
      
    • 使用对象遍历属性值

      <li v-for="info in lion">
          {{info}}
      </li>
      
      data: {
          lion:{
              name:'king',
              age:3,
              character:'violent'
          }
      },
      

      第二个参数:属性名称

      <li v-for="(info,name) in lion">
          {{name}}:{{info}}
      </li>
      

      第三个参数:索引

      <li v-for="(info,name,i) in lion">
          {{i}}:{{name}}:{{info}}
      </li>
      
    • 维护状态

      key用于跟踪每个节点的身份。

      <li v-for="animal in animals" :key="animal.id">
          {{animal.name}}
      </li>
      
      data: {
      	animals:[
      		{name:'狮子',id:1},
      		{name:'黑豹',id:2},
      		{name:'小猪',id:3},
      	]
      },
      
    • 可以在<template>和组件上使用,在组件是必须加上key

    数组更新

    • push(元素):从数组末尾添加元素
    • pop():从数组中删除最后一个元素
    • shift():从数组中删除第一个元素
    • unshift(元素):从数组开头添加元素
    • splice(开始位置,移除个数,要添加(替换)的元素):对数组进行删除替换添加元素的操作
    • sort():排列
    • reverse():颠倒数组元素的位置

    • filter():返回符合标准的元素,返回新数组。如:arr.filter(item=>item.length>6)

    • concat():合并数组,然后新数组。如:arr1.concat(arr2)

    • slice(开始索引,结束索引):抽取数组,返回新数组。如:arr.slice(2, 4)

    显示过滤/排序后的结果

    • 如果想要在不改变原数组的情况下显示过滤/排序后的结果,可以创建一个计算属性

      <li v-for="n in evenNumbers">{{ n }}</li>
      
      data: {
        numbers: [ 1, 2, 3, 4, 5 ]
      },
      computed: {
          evenNumbers: function () {
              return this.numbers.filter(number=>{
                  return number % 2 === 0
              })
          }
      }
      
    • 如果是嵌套v-for,可以使用方法

      <ul v-for="set in sets">
        <li v-for="n in even(set)">{{ n }}</li>
      </ul>
      
      data: {
        sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
      },
      methods: {
        even: function (numbers) {
          return numbers.filter(number=>{
            return number % 2 === 0
          })
        }
      }
      

      事件处理

    v-on

    v-on 指令监听 DOM 事件,缩写@

    • 简单事件直接写

      <div id="app">
        <button v-on:click="count += 1">Add 1</button>
        <p>按钮被点了 {{ count }} 下</p>
      </div>
      
      var vm = new Vue({
        el: '#app',
        data: {
          count: 0
        }
      })
      
    • 较复杂时在methods定义方法并监听

      <div id="app">
        <button @click="greet">Greet</button>
      </div>
      
      var vm = new Vue({
        el: '#app',
        data: {
          name: '小明'
        },
        methods: {
          greet: function (event) {
            alert('Hello ' + this.name + '!')
            // `event` 是原生 DOM 事件
            if (event) {
              alert(event.target.tagName)
            }
          }
        }
      })
      
    • 内联js语句中调用

      <div id="app">
        <button @click="say('hi')">Say hi</button>
        <button @click="say('what')">Say what</button>
      </div>
      
      new Vue({
        el: '#app',
        methods: {
          say: function (message) {
            alert(message)
          }
        }
      })
      

      如果需要访问原始的 DOM 事件。可以传入 $event

      <button @click="say('hi',$event)">Say hi</button>
      

    事件修饰符

    <!-- 阻止单击事件继续传播 -->
    <a @click.stop="doThis"></a>
    
    <!-- 提交事件不再重载页面 -->
    <form @submit.prevent="onSubmit"></form>
    
    <!-- 修饰符可以串联 -->
    <a @click.stop.prevent="doThat"></a>
    
    <!-- 只有修饰符 -->
    <form @submit.prevent></form>
    
    <!-- 添加事件监听器时使用事件捕获模式 -->
    <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
    <div @click.capture="doThis">...</div>
    
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->
    <div @click.self="doThat">...</div>
    
    <!-- 阻止对元素自身的点击 -->
    <div @click.self.prevent="doThat">...</div>
    

    按键修饰符

    <input v-on:keyup.enter="submit">
    <input v-on:keyup.page-down="onPageDown">
    <!-- keyCode attribute  -->
    <input v-on:keyup.13="submit">
    <!-- 自定义按键修饰符别名 -->
    Vue.config.keyCodes.f1 = 112
    

    系统修饰符

    <!-- Alt + C -->
    <input @keyup.alt.67="clear">
    
    <!-- Ctrl + Click -->
    <div @click.ctrl="doSomething">Do something</div>
    
    • .exact修饰符
      修饰符允许你控制由精确的系统修饰符组合触发的事件

      <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
      <button v-on:click.ctrl="onClick">A</button>
      <!-- 有且只有 Ctrl 被按下的时候才触发 -->
      <button v-on:click.ctrl.exact="onCtrlClick">A</button>
      
    • 鼠标按钮修饰符
      .left.rightmiddle

      表单输入绑定

    v-model

    可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定。v-model 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将 Vue 实例的数据作为数据来源。

    • text 和 textarea 元素使用 value property 和 input 事件;
    • checkbox 和 radio 使用 checked property 和 change 事件;
    • select 字段将 value 作为 prop 并将 change 作为事件。
    #1. 文本
    <input v-model="message" placeholder="edit me">
    <p>Message is: {{ message }}</p>
    
    #2. 多行文本
    <textarea v-model="message"></textarea>
    <p>{{ message }}</p>
    
    #3. 复选框
    <!-- 当选中时,checked=true -->
    <input type="checkbox" id="checkbox" v-model="checked">
    <label for="checkbox">{{ checked }}</label>
    
    <!-- true-value与false-value属性,如下选中时为yes -->
    <input type="checkbox" v-model="toggle"  true-value="yes" false-value="no">
    
    #4. 多个复选框,绑定到同一个数组
    <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>
    <p>Checked names: {{ checkedNames }}</p>
    
    #5. 单选按钮
    <!-- 当选中第一个的时候,picked="one" -->
    <input type="radio" id="one" value="One" v-model="picked">
    <label for="one">One</label>
    <input type="radio" id="two" value="Two" v-model="picked">
    <label for="two">Two</label>
    <p>Picked: {{ picked }}</p>
    
    <!-- v-bind绑定,如下,选中时pick=a -->
    <input type="radio" v-model="pick" v-bind:value="a">
    
    #6. 选择框
    <!-- 当选中A时,selected="A" -->
    <select v-model="selected">
       <option disabled value="">请选择</option>
       <option>A</option>
       <option>B</option>
       <option>C</option>
    </select>
    <p>Selected: {{ selected }}</p>
    
    #7. 选择框多选时绑定到一个数组----selected:[]
    <select v-model="selected" multiple>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
    <p>Selected: {{ selected }}</p>
    
    #8. 选择框v-for动态渲染
    <select v-model="selected">
      <option v-for="option in options" :value="option.value">
        {{ option.text }}
      </option>
    </select>
    <span>Selected: {{ selected }}</span>
    
    #8. 选择框v-for动态渲染
    data:{
        selected:'A',
        options:[
            { text: 'One', value: 'A' },
            { text: 'Two', value: 'B' },
            { text: 'Three', value: 'C' }
        ]
    }
    

    在文本区域插值不会生效

    修饰符

    • .lazy
      在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步。 lazy 修饰符可以转为在 change 事件_之后_进行同步:

      <!-- 在“change”时而非“input”时更新 -->
      <input v-model.lazy="msg">
      
    • .number

      自动将用户的输入值转为数值类型

      <input v-model.number="age" type="number">
      
    • .trim

      自动过滤用户输入的首尾空白字符

      <input v-model.trim="msg">
      

    组件

    • 组件是可复用的 Vue 实例,且带有一个名字
    • 每用一次组件,就会有一个它的新实例被创建
    • data 必须是一个函数
      data: function () {
        return {
          count: 0
        }
      }
      

    1. 注册组件

    • 全局注册

      可以用在任何新创建的 Vue 根实例的模板中。第一个参数是组件名

      Vue.component('my-component-name', {
        // ... options ...
      })
      
    • 局部注册

      即在哪注册在哪用,这样就不会过多的占用内存,首先注册一个局部组件

      var ComponentA={
          props:['title'],
          template:`<h3>{{title}}</h3>`
      }
      

      然后实例的components对象中使用,属性名就是组件名,属性值就是你想传入的组件

      new Vue({
        el: '#app',
        components:{
            'blog-title':ComponentA
        }
      })
      

    注意:推荐使用kebab-case(短横线分割命名)给组件命名,例如该例子中的<blog-title>,否则容易报错:

    image.png

    注意:每个组件必须只有一个根元素,即template里只能有一个根标签

    2. Prop

    #prop大小写

    prop对大小写不敏感,所以可以这样使用:

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

    #prop类型

    一般情况下是以字符串数组形式列出的 prop:

    props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
    

    也可以给每个prop指定值类型。属性名是prop名称,属性值是prop类型

    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object,
      callback: Function,
      contactsPromise: Promise // or any other constructor
    }
    //也可以是Data、Symbol
    

    #传递prop

    一个例子

    Vue.component('blog-post', {
      props: ['title'],	//给组件定义一个属性
      template: '<h3>{{ title }}</h3>'
    })
    
    <blog-post title="My journey with Vue"></blog-post> //传值
    
    • 静态传递

      # 传入字符串
      <blog-post title="My journey with Vue"></blog-post>
      
      #有时候需要用v-bind告诉vue这是一个js表达式而不是字符串
      # 传入布尔值,
      <blog-post :is-published="false"></blog-post>
      # 传入数组
      <blog-post :comment-ids="[234, 266, 273]"></blog-post>
      # 传入对象
      <blog-post :author="{name: 'Veronica',company: 'Veridian Dynamics'}"></blog-post>
      # 传入一个对象所有的属性
      
    • 动态传递

      new Vue({
        el: '#blog',
        data: {
          posts: [
            { id: 1, title: 'My journey with Vue' },
            { id: 2, title: 'Blogging with Vue' },
            { id: 3, title: 'Why Vue is so fun' }
          ]
        }
      })
      
      <blog-post v-for="post in posts" :key="post.id" :title="post.title" ></blog-post>
      

      当需要传递的属性很多时,可以将这些属性成合成一个。在这个例子中,可以把所有post所有的属性如title、content写在一个post 中:

    1. 重构组件

      原本子组件

      Vue.component('blog-post', {
        props: ['title','content'],
        template: `
          <div>
            <h3>{{ title }}</h3>
            <div v-html="content"></div>
          </div>
        `
      })
      

      现在子组件

      Vue.component('blog-post', {
        props: ['post'],
        template: `
          <div>
            <h3>{{ post.title }}</h3>
            <div v-html="post.content"></div>
          </div>
        `
      })
      
    2. 创建实例

      new Vue({
        el: '#blog',
        data: {
          posts: [
            { id: 1, title: 'My journey with Vue',content:'111' },
            { id: 2, title: 'Blogging with Vue',content:'222' },
            { id: 3, title: 'Why Vue is so fun',content:'333'}
          ]
        }
      })
      
    3. 在实例中使用组件

      原本父级

      <blog-post v-for="post in posts" :key="post.id" :title="post.title" :content="post.comtent"></blog-post>
      

      现在父级

      <blog-post v-for="post in posts" :key="post.id" :post="post"></blog-post>
      

    #单项数据流

    父级 prop 的更新会向下流动到子组件中,但是反过来则不行

    #prop验证

    可以为组件的 prop 指定验证要求。

    • 当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
    • prop 会在一个组件实例创建之前进行验证
    Vue.component('my-component', {
      props: {
        //1. 基础的类型检查 (null和undefined会通过任何类型验证)  
        propA: Number,
          
        //2. 多个可能的类型
        propB: [String, Number],
          
        //3. 必填的字符串
        propC: {				 
          type: String,
          required: true
        },
          
        //4. 带有默认值的数字
        propD: {				 
          type: Number,
          default: 100
        },
          
        //5.自定义验证函数。下面例子表示必须匹配下列字符串中的一个
        propF: {				  
          validator: function (value) {
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
      }
    })
    

    3. 自定义事件

    #事件名

    推荐始终使用 kebab-case 的事件名

    this.$emit('my-event')
    
    <my-component @my-event="doSomething"></my-component>
    

    #监听子组件事件

    1. 创建实例

      new Vue({
        el: '#demo',
        data: {
          posts: [/* ... */],
          postFontSize: 1
        }
      })
      
    2. $emit给子组件添加事件

      Vue.component('blog-post', {
        props: ['post'],
        template: `
          //...
            <button @click="$emit('enlarge-text')">Enlarge</button>
           //...
        `
      })
      
    3. v-on监听子组件事件。当子组件触发时,开始响应

      <div id="demo">
        <div :style="{ fontSize: postFontSize + 'em' }">
          <blog-post 
            ...
            @enlarge-text="postFontSize += 0.1"
           ></blog-post>
       </div>
      </div>
      

    $emit可以接收第二个参数

    1. 给子组件事件添加参数

      <button v-on:click="$emit('enlarge-text', 0.1)">Enlarge</button>
      
    2. 父级通过$event获取整个参数值

      <blog-post
        ...
        @enlarge-text="postFontSize += $event"
      ></blog-post>
      

      第二种写法:

      <blog-post
      ...
      @enlarge-text="enlargeText"
      ></blog-post>
      

      传过来的参数值会作为该方法的第一个参数

      methods: {
         enlargeText: function (num) {
           this.postFontSize += num
         }
      }
      

    #自定义事件中的v-model

    • 普通情况下自定义事件

      <input v-model="searchText">
      

      等价于

      <input :value="searchText" @input="searchText = $event.target.value">
      
    • 在组件上自定义事件

      <custom-input v-model="searchText"/>
      

      等价于

      <custom-input :value="searchText" @input="searchText = $event"/>
      

      这时候需要更改子组件,才能让其正常运作。

      Vue.component('custom-input', {
        props: ['value'],
        template: `
          <input
            :value="value"
            @input="$emit('input', $event.target.value)"
          >
        `
      })
      

      解析:这时子组件的input触发时,会抛出$event.target.value,父级会监听到并接收$event.target.value。此时父级的$event实际上就等于子组件抛出的$event.target.value,变化后的searchText的值会绑定在父级的value上,然后通过props传回子组件,子组件接收到这个props值后就绑定在input的value上,这时候就在页面呈现出效果了

    #绑定原生事件

    使用 v-on.native 修饰符:

    <base-input @focus.native="onFocus"></base-input>
    

    注意.native监听的是组件的根元素。如果想监听到子元素,需要用到$listeners对象

    4. 插槽

    #一个例子

    1. 在子组件模板中加上一个插槽<slot></slot>

      Vue.component('alert-box', {
        template: `
          <div>
            <strong>Error!</strong>
            <slot></slot>
          </div>
        `
      })
      
    2. 在父级组件内添加内容后,内容就会自动放进插槽内

      <alert-box>Something bad happened.</alert-box>
      

    注意:如果子的 template 中没有包含一个 slot 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃

    #默认内容

    默认内容会在没有提供内容的时候被渲染。只需要将内容放在slot中:

    //在一个子组件的template中
    <button>
      <slot>Submit</slot>
    </button>
    
    //1. 父级中没有添加任何内容
    <submit-button></submit-button>
    //   渲染后备内容:
    <button>Submit</button>
    
    //2. 父级中有内容
    <submit-button>Save</submit-button>
    //   后备内容会被取代:
    <button>Save</button>
    

    #具名插槽

    当我们需要多个插槽时,具名插槽很有用:

    1. 组件模板中,给slot添加name属性

      //假设这是base-layout组件的模板,需要分别给header、main、footer添加插槽:
      <div class="container">
        <header>
          <slot name="header"></slot>
        </header>
        <main>
          <slot></slot> //这个插槽没有名字,name的值默认为default
        </main>
        <footer>
          <slot name="footer"></slot>
        </footer>
      </div>
      
    2. 父级中,用带有v-slottemplate包裹内容,v-slot指定插槽名称

      <base-layout>
        <template v-slot:header>
          <h1>I am a header</h1>
        </template>
      
        //任何没有按规定包裹的内容都会被视为默认插槽的内容
        <p>A paragraph for the main content.</p>
        <p>And another one.</p>
      
        <template v-slot:footer>
          <p>I am a footer</p>
        </template>
      </base-layout>
      

      v-slot可以缩写:

      <template #header>
         <h1>I am a header</h1>
      </template>
      

    #编译作用域

    插槽的作用域与实例相同。即能访问到实例的数据,而不能访问组件的数据

    //可以访问
    <navigation-link url="/profile">{{ user.name }}</navigation-link>
    //不可以访问
    <navigation-link url="/profile">{{ url }}</navigation-link>
    

    #插槽作用域

    如果想在父级插槽内容中访问到子组件的数据

    1. 在子组件的slot中绑定数据

      Vue.component('user-info', {
          //user作为属性绑定数据。在这里user属性被称为插槽prop
          template: `<span><slot :user="userdata">{{userdata.current}}</slot></span>`,
          data:()=>({
              userdata:{
                  before:'lihua',
                  current:'xiaoming'
              }
          }),
      })
      
    2. v-slot 来定义插槽 prop 的名字。名字也可以是其他

      <user-info v-slot:default="slotProps">
          {{slotProps.user.before}}
      </user-info>
      

      由于指定的插槽是default,所以以上也可以简写成:注意不要与具名插槽混淆

      <user-info v-slot="slotProps">
          {{slotProps.user.before}}
      </user-info>
      

    自 2.6.0 起有所更新。已废弃的使用 slot-scope

    # 动态插槽名

    <base-layout>
      <template v-slot:[dynamicSlotName]>
        ...
      </template>
    </base-layout>
    

    5. 动态组件

    如果在一个多标签界面实现组件切换,可以通过 Vue 的 <component> 元素加一个特殊的 is attribute 来实现::

    <!-- 切换tab值 -->
    <button v-for="tab in tabs" :key="tab" @click="currentTab = tab">{{tab}}</button>
    <!-- 组件会在 `currentTabComponent` 改变时改变 -->
    <component v-bind:is="currentTabComponent"></component>
    
    Vue.component("com1", {
        template: "<div>com1</div>"
    });
    Vue.component("com2", {
        template: "<div>com2</div>"
    });
    Vue.component("com3", {
        template: "<div>com3</div>"
    });
    
    new Vue({
      el: '#app',
      data:{
        currentTab:"com1",
        tabs:["com1", "com2", "com3"]
      },
        computed: {
    		//currentTabComponent可以是已注册组件的名字,或一个组件的选项对象        
            currentTabComponent: function () {
                return this.currentTab
            }
        }
    })
    
    

    过渡和动画

    过渡的类名

    1. [name]-enter:进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。

    2. [name]-enter-active:进入过渡生效时的状态。在元素被插入之前生效,在过渡/动画完成之后移除。用来定义进入过渡的过程时间,延迟和曲线函数。

    3. [name]-enter-to:进入过渡的结束状态。在元素被插入之后下一帧生效 ,在过渡/动画完成之后移除。

    4. [name]-leave:离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。

    5. [name]-leave-active:离开过渡生效时的状态在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。

    6. [name]-leave-to:定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 ,在过渡/动画完成之后移除。

      image.png

    单元素/组件的过渡

    Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡:

    • 条件渲染 (使用 v-if)
    • 条件展示 (使用 v-show)
    • 动态组件
    • 组件根节点

    css过渡例子

    1. transition包裹元素,并命名

      <button @click="show = !show">切换</button>
      <transition name="fade">
          <p v-if="show">hello</p>
      </transition>
      
    2. 定义类

      //进入过渡
      .fade-enter-active {
        transition: all .3s ease;
      }
      //离开过渡
      .fade-leave-active {
        transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
      }
      //开始和结束的状态
      .fade-enter, .fade-leave-to {
        transform: translateX(10px);
        opacity: 0;
      }
      

    css动画例子

    1. transition包裹元素,并命名

      <button @click="show = !show">切换</button>
      <transition name="bounce">
          <p v-if="show">hello</p>
      </transition>
      
    2. 定义类

      //进入动画
      .bounce-enter-active {
        animation: bounce-in .5s;
      }
      //离开动画
      .bounce-leave-active {
        animation: bounce-in .5s reverse;
      }
      
      //定义动画关键帧
      @keyframes bounce-in {
        0% {
          transform: scale(0);
        }
        50% {
          transform: scale(1.5);
        }
        100% {
          transform: scale(1);
        }
      }
      

    多个元素/组件过渡

    多个元素

    <transition>
      <table v-if="items.length > 0"></table>
      <p v-else>Sorry, no items found.</p>
    </transition>
    

    当有相同标签名的元素切换时,需要通过 key 设置唯一的值来标记以让 Vue 区分它们

    <transition>
      <button v-if="isEditing" key="save">Save</button>
      <button v-else key="edit">Edit</button>
    </transition>
    

    多个组件

    不需要使用 key 。相反,需要使用动态组件

    <input type="radio" value="com1" id="1"  v-model="view">com1
    <input type="radio" value="com2" id="2"  v-model="view">com2
    <transition name="fade" mode="out-in">
      <component v-bind:is="view"></component>
    </transition>
    
    new Vue({
      el: '#app',
      data: {
        view: 'com1'
      },
      components: {
        'com1': {template: '<div>Component A</div>'},
        'com2': {template: '<div>Component B</div>'}
      }
    })
    
    .fade-enter-active, .fade-leave-active {
      transition: opacity .3s ease;
    }
    .fade-enter, .fade-leave-to {
      opacity: 0;
    }
    

    过渡模式

    • in-out:新元素先进行过渡,完成之后当前元素过渡离开
    • out-in:当前元素先进行过渡,完成之后新元素过渡进入

    JavaScript 钩子

    • 钩子介绍

      <transition
        v-on:before-enter="beforeEnter"
        v-on:enter="enter"
        v-on:after-enter="afterEnter"
        v-on:enter-cancelled="enterCancelled"
      
        v-on:before-leave="beforeLeave"
        v-on:leave="leave"
        v-on:after-leave="afterLeave"
        v-on:leave-cancelled="leaveCancelled"
      >
        <!-- ... -->
      </transition>
      
      methods: {
        beforeEnter: function (el) {...},
        enter: function (el, done) { //当与 CSS 结合使用时,回调函数 done 是可选的
          // ...
          done()
        },
        afterEnter: function (el) {...},
        enterCancelled: function (el) {...},
      
        // 离开时
        beforeLeave: function (el) {...},
        leave: function (el, done) {// 当与 CSS 结合使用时,回调函数 done 是可选的
          // ...
          done()
        },
        afterLeave: function (el) {...},// leaveCancelled 只用于 v-show 中
        leaveCancelled: function (el) {...}
      }
      
    • 使用Velocity.js的例子

      <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
      <div id="app">
        <button @click="show = !show">
          Toggle
        </button>
        <transition
          v-on:before-enter="beforeEnter"
          v-on:enter="enter"
          v-on:leave="leave"
          v-bind:css="false"
        >
          <p v-if="show">
            Demo
          </p>
        </transition>
      </div>
      
      new Vue({
        el: '#pp
        data: {
          show: false
        },
        methods: {
          beforeEnter: function (el) {
            el.style.opacity = 0
            el.style.transformOrigin = 'left'
          },
          enter: function (el, done) {
            Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
            Velocity(el, { fontSize: '1em' }, { complete: done })
          },
          leave: function (el, done) {
            Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
            Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
            Velocity(el, {
              rotateZ: '45deg',
              translateY: '30px',
              translateX: '30px',
              opacity: 0
            }, { complete: done })
          }
        }
      })
      

    初始渲染的过渡

    可以通过 appear 设置节点在初始渲染的过渡,只渲染一次

    <transition
      appear
      appear-class="enter-class"
      appear-active-class="enter-active-class"
      appear-to-class="enter-to-class"
    >
      <!-- ... -->
    </transition>
    

    自定义 JavaScript 钩子

    <transition
      appear
      v-on:before-appear="customBeforeAppearHook"
      v-on:appear="customAppearHook"
      v-on:after-appear="customAfterAppearHook"
      v-on:appear-cancelled="customAppearCancelledHook"
    >
      <!-- ... -->
    </transition>
    

    列表过渡

    同v-for渲染列表时,使用<transition-group>组件。需要提供key,此时过渡模式不可用。

    不同于 transition,它会以一个真实元素呈现:默认为一个 span。你也可以通过 tag attribute 更换为其他元素。

    <div id="app">
      <!--... -->
      <transition-group name="list" tag="p">
        <span v-for="item in items" :key="item">
          {{ item }}
        </span>
      </transition-group>
    </div>
    

    其他

    混入

    混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。当组件使用混入对象时,所有混入对象的选项将被混入进该组件本身的选项。

    1. 假设要混入一个方法
      const userMixin={
        methods:{
          getInfo(){
            //Fetch API 提供了一个获取资源的接口(包括跨域请求)
            return fetch(`/api/user/${userId}`)
            .then((res)=>res.json())
          }
        }
      }
      
    2. 使用
      import userMixin from './mixins/user'
      
      Vue.component('user-com',{
        mixins:[userMixin],//混入
        //...
        mounted(){
          //这个时候已经可以使用混合进来的方法了
          this.getInfo(this.userId)
          .then((res)=>{...})
        }
      })
      

    当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”

    1. 数据对象同名,合并数据
    var mixin = {
      data: function () {
        return {
          message: 'hello',
          foo: 'abc'
        }
      }
    }
    
    new Vue({
      mixins: [mixin],
      data: function () {
        return {
          message: 'goodbye',
          bar: 'def'
        }
      },
    })
    
    //这时候的data:
    //{ message: "goodbye", foo: "abc", bar: "def" }
    
    1. 钩子函数同名,合并方法
    var mixin = {
      created: function () {
        console.log('混入对象的钩子被调用')
      }
    }
    new Vue({
      mixins: [mixin],
      created: function () {
        console.log('组件钩子被调用')
      }
    })
    
    //这时候调用时:
    // => "混入对象的钩子被调用"
    // => "组件钩子被调用"
    

    值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。

    ** 全局混入**

    Vue.mixin({...})
    

    自定义指令

    注册

    • 全局注册
      Vue.directive('focus', {
        inserted: function (el) {
          el.focus()
        }
      })
      
    • 局部注册
      directives: {
       focus: {
         // 指令的定义
         inserted: function (el) {
           el.focus()
         }
       }
      }
      

    使用:<input v-focus>

    钩子函数

    • bind:只调用一次,指令第一次绑定到元素时调用。
    • inserted:被绑定元素插入父节点时调用
    • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
    • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
    • unbind:只调用一次,指令与元素解绑时调用。

    钩子函数参数

    • el:指令所绑定的元素,可以用来直接操作 DOM。
    • binding:一个对象,包含以下 property:
      • name:指令名,不包括 v- 前缀。
      • value:指令的绑定值,例如:v-my="1 + 1" 中,绑定值为 2
      • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用
      • expression:字符串形式的指令表达式。例如 v-my="1 + 1" 中,表达式为 "1 + 1"。
      • arg:传给指令的参数。例如 v-my:foo 中,参数为 "foo"
      • modifiers:一个包含修饰符的对象。例如:v-my.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
    • vnode:Vue 编译生成的虚拟节点。
    • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用

    插件

    插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:

    1. 添加全局方法或者 property。如:vue-custom-element
    2. 添加全局资源:指令/过滤器/过渡等。如 vue-touch
    3. 通过全局混入来添加一些组件选项。如 vue-router
    4. 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
    5. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router
    //全局使用
    Vue.use(MyPlugin)
    
    //传入选项
    Vue.use(MyPlugin, { someOption: true })
    
    // 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
    var Vue = require('vue')
    var VueRouter = require('vue-router')
    
    // 不要忘了调用此方法
    Vue.use(VueRouter)
    

    过滤器

    注册

    • 全局注册
      //将字母转为大写
      Vue.filter('capitalize', function (value) {
        if (!value) return ''
        value = value.toString()
        return value.charAt(0).toUpperCase() + value.slice(1)
      })
      
    • 局部注册
      //在组件选项中:
      filters: {
        capitalize: function (value) {
          //...
        }
      }
      

    使用

    过滤器可以用在两个地方:

    • 双花括号插值
      {{ message | capitalize }}
      
    • v-bind 表达式
      <div :id="rawId | formatId"></div>
      

    链式调用

    在下面的例子中,首先会调用round过滤器,它返回的结果会传递给formatCost过滤器进行处理:

    {{ productOneCost | round |formatCost}}
    

    参数

    {{ message | filterA('arg1', arg2) }}
    

    其中 message 的值作为第一个参数,普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。

    单文件组件

    全局组件的缺点

    • 全局定义强制要求每个 component 中的命名不得重复
    • 字符串模板缺乏语法高亮,看不清晰
    • 不支持 CSS ,意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
    • 没有构建步骤,限制只能使用 HTML 和 ES5 JavaScript,而不能使用预处理器,如 Pug 和 Babel

    文件扩展名为 .vue 的 单文件组件为以上所有问题提供了解决方法,并且还可以使用 webpack 或 Browserify 等构建工具。以下是一个文件名为Hello.vue的简单实例

    <template>
        <p>Hello!{{msg}}</p>
    </template>
    
    <script>
    export default{
        name:'test',
        props:{
            msg:{
                type:String,
                default:"test msg"
            }
        },
        methods:{}
        data () {
            return {
                name: 'lihua'
            }
        }
    }
    </script>
    
    <style scoped>
    p{color: antiquewhite;}
    </style>
    

    在其他地方中使用

    <template>
        <div id="app">
            <test></test>
        </div>
    </template>
    
    <script>
    //1. 引入组件
    import test form './components/test.vue'
    export default{
        name:'app',
        //2. 注册组件
        components:{
            test
        }
    }
    </script>
    

    render函数

    使用模板并不是唯一能让vue知道应该在页面显示什么内容的方式:还可以使用render函数。当你将一个函数传递给Vue实例的render属性时,该函数会传入一个createElement函数,可以使用它来指定需要在页面上显示的HTML。

    new Vue({
        el:'#app',
        render(createELement){
            return createELement('h1',"hello world!")
        }
    })
    

    createElement接收3个参数:标签名称、包含配置信息的数据对象(诸如HTML特性、属性、事件侦听器以及要绑定的class和style等)和一个子节点或是包含子节点的数组

    标签名称

    标签名称是最简单的,也是唯一一个必需的参数。它可以是一个字符串,或是一个返回字符串的函数。render函数中也可以访问this,所以可以将标签名称设置为data对象的某个属性、prop、计算属性或是任何类似的东西,例如下方代码,这是render函数优于template的一个很大的优势:

    new Vue({
        el:'#app',
        render(createELement){
            return createELement('this.tagName',"hello world!")
        },
        data:{
            tagName:"h1"
        }
    })
    

    数据对象

    数据对象是设置一系列配置属性的地方,这些属性会影响生成的组件或元素。

    例如,对于<custom-button type="submit" v-bind:text="buttonText">。type是传递给组件的一个HTML属性,text是一个组件prop,与变量buttonText绑定。现在使用createElement来实现相同的示例:

    new Vue({
        el:'#app',
        render(createELement){
            return createELement('custom-button',{
                attrs:{
                    type:"submit"
                },
                props:{
                    text:this.buttonText
                }
            })
        },
    })
    

    下面的示例,它列出了所有的选项:

    {
        //html特性
        attrs:{
            type:"submit"
        },
            
        //传递给组件的prop
        props:{
            test:"单击我!"
        },
        
        //DOM属性,比如innerHtml
        domProps:{
            innerHtml:'...'
        },
            
            
        //事件监听器
        on:{
            click:this.handleClick
        },
        
        //当组件是某个组件的子组件时使用,等同于:slot="Slot"
        slot:'Slot',
        
        //用于某个循环产生的数组,等同于key="Key"
        key:"Key",
        
        //与ref="Ref"相同
        ref="Ref",
            
        class:['Aclass',{'Bclass':true}],
        style:{backgroundColor:'red'}
    }
    

    子节点

    用来设置元素的子节点的。它可以是一个数组也可以是一个字符串。如果你不需要设置数据对象,只是需要配置子节点,那么可以将子节点设置为第二个参数,而不是原来的第三个参数。

    <div>
        <button v-on:click="count++">单击增加计数</button>
        <p>你已经单击了{{count}}次</p>
    </div>
    
    render(createELement){
        return createELement('div',[
            createELement('button',{
                on:{
                    click:()=>this.count++
                }
            },
            '单击增加计数'),
            createELement('p','你已经单击了${{this.count}}次')
        ])
    },
    

    JSX

    babel-plugin-transform-vue-jsx插件的帮助下,可以使用JSX来编写render函数createElement函数通常会有个较短的别名,h

    安装了插件之后你可以写成:

    render(){
        return(
        	<div>
            	<button v-on:click="count++">单击增加计数</button>
       		    <p>你已经单击了{{count}}次</p>
            </div>
        )
    }
    

    除了像在模板中那样,可以导入并使用组件——只要将组件的名称设置为标签的名称——还可以像React那样导入组件。如果导入的组件存储在首字母大写的变量中,则不需要在components对象中指定或是使用Vue.component()函数注册,就可以使用该组件。例如:

    import MyComponent from './components/MyComponent.vue'
    new Vue({
        el:'#app',
        render(){
            return(
            	<MyComponent/>
            )
        }
    })
    

    JSX的展开操作符也同样得到支持。可以在属性对象上使用展开操作符,它会与其他已经设置的属性相合并,一起应用到元素上:

    render(){
        const props={
            class:'world',
            href:'...'
        };
        return(
        	<a {...props}>hello</a>
        );
    }
    

    实例与笔记源代码

  • 相关阅读:
    SubtextHTTP 模块
    asp.net控件设计时支持(2)自动格式设置
    新立得字体模糊解决经验
    详解新网银木马清除技巧
    Ubuntu 9.10 29日发布,更新列表已经公布
    小样儿想封我?WebOS 1.2.1再次突破iTunes同步限制
    检测到您尚未安装ALEXA工具条
    在Puppy Linux中安装Firefox
    一步一步教你用ES封装系统(最完整视频教程)
    C# 判断是否为数字
  • 原文地址:https://www.cnblogs.com/sanhuamao/p/13596500.html
Copyright © 2020-2023  润新知