Vue 基础

1 demo

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="./vue.global.js"></script>
</head>
<body>
<div id="hello-vue" class="demo">
    {{ message }}
</div>

<script>
    const HelloVueApp = {
        data() {
            return {
                message: 'Hello Vue!!'
            }
        }
    }

    Vue.createApp(HelloVueApp).mount('#hello-vue')
</script>
</body>
</html>
  • createApp 的参数是根组件(HelloVueApp),在挂载应用时,该组件是渲染的起点。一个应用需要被挂载到一个 DOM 元素中,以上代码使用 mount(’#hello-vue’) 将 Vue 应用 HelloVueApp 挂载到 <div id=“hello-vue”></div> 中。

  • data 选项是一个函数。Vue 在创建新组件实例的过程中调用此函数。它应该返回一个对象,然后 Vue 会通过响应性系统将其包裹起来,并以 $data 的形式存储在组件实例中。

    const app = Vue.createApp({
      data() {
        return { count: 4 }
      }
    })
    
    const vm = app.mount('#app')
    
    document.write(vm.$data.count) // => 4
    document.write("<br>")
    document.write(vm.count)       // => 4
    document.write("<br>")
    // 修改 vm.count 的值也会更新 $data.count
    vm.count = 5
    document.write(vm.$data.count) // => 5
    document.write("<br>")
    // 反之亦然
    vm.$data.count = 6
    document.write(vm.count) // => 6
    

2 Vue 安装

  1. 独立版本

    vue.global.js 地址

    我们可以在 Vue.js 的官网上直接下载最新版本, 并用 <script> 标签引入。

  2. 使用 CDN 方法

    Staticfile CDN(国内):

    <script src="https://cdn.staticfile.org/vue/3.0.5/vue.global.js"></script>
    

    unpkg(推荐):

    <script src="https://unpkg.com/vue@next"></script>
    

    cdnjs:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.5/vue.global.js"></script>
    
  3. NPM 方法

    vue init webpack project_name
    
  4. Vite(推荐)

    npm init @vitejs/app project_name
    

3 模板语法

Vue 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统。

3.1 文本插值

数据绑定最常见的形式就是使用 {{…}}(双大括号)的文本插值:

<div id="hello-vue">
  {{ message.split('').reverse().join('') }}
</div>

注:Vue.js 提供了完全的 JavaScript 表达式支持。表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析。限制:每个绑定都只能包含单个表达式。

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

<span v-once>这个将不会改变: {{ message }}</span>

3.2 v-html

<div id="example1" class="demo">
    <p>使用双大括号的文本插值: {{ rawHtml }}</p>
    <p>使用 v-html 指令: <span v-html="rawHtml"></span></p>
</div>
 
<script>
const RenderHtmlApp = {
  data() {
    return {
      rawHtml: '<span style="color: red">这里会显示红色!</span>'
    }
  }
}
 
Vue.createApp(RenderHtmlApp).mount('#example1')
</script>

3.3 v-bind

HTML 属性中的值应使用 v-bind 指令。

<div v-bind:id="dynamicId"></div>

对于布尔属性,常规值为 true 或 false,如果属性值为 null 或 undefined,则该属性不会显示出来。

<button v-bind:disabled="isButtonDisabled">按钮</button>

以上代码中如果 isButtonDisabled 的值是 null 或 undefined,则 disabled 属性甚至不会被包含在渲染出来的 <button> 元素中。

以下实例中,如果 use 为 true 使用 class1 类的样式,否则不使用该类:

<div v-bind:class="{'class1': use}">
    v-bind:class 指令
</div>

以下实例中,href 是参数,告知 v-bind 指令将该元素的 href 属性与表达式 url 的值绑定。

<div id="app">
    <p><a v-bind:href="url">菜鸟教程</a></p>
</div>

3.4 v-on

v-on 指令用于监听 DOM 事件:

<!-- 完整语法 -->
<a v-on:click="doSomething"> ... </a>

<!-- 缩写 -->
<a @click="doSomething"> ... </a>

<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>

按钮的事件我们可以使用 v-on 监听事件,并对用户的输入进行响应。以下实例在用户点击按钮后对字符串进行反转操作:

<div id="app">
    <p>{{ message }}</p>
    <button v-on:click="reverseMessage">反转字符串</button>
</div>
    
<script>
const app = {
  data() {
    return {
      message: 'Runoob!'
    }
  },
  methods: {
    reverseMessage() {
      this.message = this.message.split('').reverse().join('')
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>

3.5 修饰符

修饰符是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():

<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

<!-- Alt + C -->
<input @keyup.alt.67="clear">

3.6 用户输入

v-model 指令用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。

在 input 输入框中我们可以使用 v-model 指令来实现双向数据绑定:

<div id="app">
    <p>{{ message }}</p>
    <input v-model="message">
</div>
 
<script>
const app = {
  data() {
    return {
      message: 'Runoob!'
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>

3.7 缩写

<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- v-bind 缩写 -->
<a :href="url"></a>

<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- v-on 缩写 -->
<a @click="doSomething"></a>

4 条件语句

4.1 v-if:

<div id="app">
    <p v-if="seen">现在你看到我了</p>
</div>

因为 v-if 是一个指令,所以必须将它添加到一个元素上。如果是多个元素,可以包裹在 <template> 元素上,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。

<div id="app">
    <template v-if="seen">
        <h1>网站</h1>
        <p>Google</p>
        <p>Runoob</p>
        <p>Taobao</p>
    </template>
</div>

4.2 v-else-if:

<div id="app">
    <div v-if="type === 'A'">
         A
    </div>
    <div v-else-if="type === 'B'">
      B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
    </div>
</div>
    
<script>
const app = {
  data() {
    return {
      type: "C" 
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>

4.3 v-show:

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

4.4 v-if 与 v-show 比较:

  • 相同点:v-if与v-show都可以动态控制dom元素显示隐藏

  • 不同点:v-if显示隐藏是将dom元素整个添加或删除,而v-show隐藏则是为该元素添加css–display:none,dom元素还在

  • 如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好

5 循环语句

5.1 v-for 迭代列表:

<ul>
  <template v-for="(site, index) in sites">
    <li>{{ site }}</li>
    <li>{{ index }}</li>
  </template>
</ul>

注:关于template标签:

<div id="app">
    <!--此处的template标签中的内容显示并且在dom中不存在template标签-->
    <template>
        <div>我是template</div>
        <div>我是template</div>
    </template>
</div>
<!--此处的template标签中的内容在页面中不显示,但是在dom结构存在该标签及内部结构-->
<template id="tem">
    <div id="div1">我是template</div>
    <div>我是template</div>
</template>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
    });
</script>

5.2 v-for 迭代对象:

<div id="app">
  <ul>
    <li v-for="(value, key, index) in object">
     {{ index }}. {{ key }} : {{ value }}
    </li>
  </ul>
</div>

5.3 v-for 迭代整数:

<div id="app">
  <ul>
    <li v-for="n in 10">
     {{ n }}
    </li>
  </ul>
</div>

5.4 显示过滤/排序后的结果:

<div id="app">
  <ul>
    <li v-for="n in evenNumbers">{{ n }}</li>
  </ul>
</div>
 
<script>
const app = {
    data() {
        return {
            numbers: [ 1, 2, 3, 4, 5 ]
	     }
    },
    computed: {
        evenNumbers() {
            return this.numbers.filter(number => number % 2 === 0)
        }
    }
}
 
Vue.createApp(app).mount('#app')
</script>

5.5 v-for/v-if 联合使用给 select 设置默认值:

<div id="app">
   <select @change="changeVal($event)" v-model="selOption">
      <template v-for="(site,index) in sites" :site="site" :index="index" :key="site.id">
         <!-- 索引为 1 的设为默认值,索引值从0 开始-->
         <option v-if = "index == 1" :value="site.name" selected>{{site.name}}</option>
         <option v-else :value="site.name">{{site.name}}</option>
      </template>
   </select>
   <div>您选中了:{{selOption}}</div>
</div>
 
<script>
const app = {
    data() {
        return {
            selOption: "Runoob",
            sites: [
                  {id:1,name:"Google"},
                  {id:2,name:"Runoob"},
                  {id:3,name:"Taobao"},
            ]
         }
        
    },
    methods:{
        changeVal:function(event){
            this.selOption = event.target.value;
        }
    }
}
 
Vue.createApp(app).mount('#app')
</script>

5.6 在自定义组件上使用 v-for:

在自定义组件上,你可以像在任何普通元素上一样使用 v-for:

<my-component v-for="item in items" :key="item.id"></my-component>

然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要使用 props:

<my-component
  v-for="(item, index) in items"
  :item="item"
  :index="index"
  :key="item.id"
></my-component>

不自动将 item 注入到组件里的原因是,这会使得组件与 v-for 的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。

下面是一个简单的 todo 列表的完整例子:

<div id="todo-list-example">
  <form v-on:submit.prevent="addNewTodo">
    <label for="new-todo">添加 todo</label>
    <input
      v-model="newTodoText"
      id="new-todo"
      placeholder="例如:明天早上跑步"
    />
    <button>添加</button>
  </form>
  <ul>
    <todo-item
      v-for="(todo, index) in todos"
      :key="todo.id"
      :title="todo.title"
      @remove="todos.splice(index, 1)"
    ></todo-item>
  </ul>
</div>
 
<script>
const app = Vue.createApp({
  data() {
    return {
      newTodoText: '',
      todos: [
        {
          id: 1,
          title: '看电影'
        },
        {
          id: 2,
          title: '吃饭'
        },
        {
          id: 3,
          title: '上 RUNOOB 学习'
        }
      ],
      nextTodoId: 4
    }
  },
  methods: {
    addNewTodo() {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})

app.component('todo-item', {
  template: `
    <li>
      {{ title }}
      <button @click="$emit('remove')">删除</button>
    </li>
  `,
  props: ['title'],
  emits: ['remove']
})

app.mount('#todo-list-example')
</script>

6 组件

6.1 全局组件

下面的实例中我们的组件都是通过 component 全局注册的。全局注册的组件可以在随后创建的 app 实例模板中使用,也包括根实例组件树中的所有子组件的模板中。

注册一个全局组件语法格式如下:

const app = Vue.createApp({...})

app.component('my-component-name', {
  /* ... */
})

my-component-name 为组件名,/* … */ 部分为配置选项。注册后,我们可以使用以下方式来调用组件:

<my-component-name></my-component-name>

一个简单的 Vue 组件的实例:

<div id="app">
    <button-counter></button-counter>
</div>

<script>
// 创建一个Vue 应用
const app = Vue.createApp({})

// 定义一个名为 button-counter 的新全局组件
app.component('button-counter', {
  data() {
    return {
      count: 0
    }
  },
  template: `
    <button @click="count++">
      点了 {{ count }} 次!
    </button>`
})
app.mount('#app')
</script>

6.2 局部组件

全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。

在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:

const ComponentA = {
  /* ... */
}
const ComponentB = {
  /* ... */
}

然后在 components 选项中定义你想要使用的组件:

const app = Vue.createApp({
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字(component-a、component-b),其属性值就是这个组件的选项对象(ComponentA、ComponentB)。

我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:

<div id="app">
    <runoob-a></runoob-a>
</div>
<script>
 
var runoobA = {
  template: '<h1>自定义组件!</h1>'
}
 
const app = Vue.createApp({
  components: {
    'runoob-a': runoobA
  }
})
 
app.mount('#app')
</script>

6.3 props

父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 “prop”:

<div id="app">
  <site-name title="Google"></site-namet>
  <site-name title="Runoob"></site-namet>
  <site-name title="Taobao"></site-name>
</div>
 
<script>
const app = Vue.createApp({})
 
app.component('site-name', {
  props: ['title'],
  template: `<h4>{{ title }}</h4>`
})
 
app.mount('#app')
</script>

6.4 动态props

类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:

<div id="app">
  <site-info
    v-for="site in sites"
    :id="site.id"
    :title="site.title"
  ></site-info>
</div>
 
<script>
const Site = {
  data() {
    return {
      sites: [
        { id: 1, title: 'Google' },
        { id: 2, title: 'Runoob' },
        { id: 3, title: 'Taobao' }
      ]
    }
  }
}
 
const app = Vue.createApp(Site)
 
app.component('site-info', {
  props: ['id','title'],
  template: `<h4>{{ id }} - {{ title }}</h4>`
})
 
app.mount('#app')
</script>

6.5 props验证

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

7 计算属性

<div id="app">
  <p>原始字符串: {{ message }}</p>
  <p>使用 computed 计算后反转字符串: {{ reversedMessage }}</p>
  <p>使用 methods 计算后反转字符串: {{ reversedMessage2() }}</p>
</div>
    
<script>
const app = {
  data() {
    return {
      message: 'RUNOOB!!'
    }
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  },
  methods: {
    reversedMessage2: function () {
      return this.message.split('').reverse().join('')
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>
  • 上述实例中声明了一个计算属性 reversedMessage 。提供的函数将用作属性 vm.reversedMessage 的 getter 。

  • vm.reversedMessage 依赖于 vm.message,在 vm.message 发生改变时,vm.reversedMessage 也会更新。

  • 我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。可以说使用 computed 性能会更好,但是如果你不希望缓存,你可以使用 methods 属性。

8 监听属性

8.1 watch

我们可以通过监听属性 watch 来响应数据的变化。

<div id = "app">
    千米 : <input type = "text" v-model = "kilometers">
    米 : <input type = "text" v-model = "meters">
</div>
<p id="info"></p>    
<script>
const app = {
  data() {
    return {
      kilometers : 0,
      meters:0
    }
  },
  watch : {
	  kilometers:function(val) {
		  this.kilometers = val;
		  this.meters = this.kilometers * 1000
	  },
	  meters : function (val) {
		  this.kilometers = val/ 1000;
		  this.meters = val;
	  }
  }
}
vm = Vue.createApp(app).mount('#app')
vm.$watch('kilometers', function (newValue, oldValue) {
    // 这个回调将在 vm.kilometers 改变后调用
    document.getElementById ("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
})
</script>

以上代码中我们创建了两个输入框,data 属性中, kilometers 和 meters 初始值都为 0。watch 对象创建了 data 对象的两个监控方法: kilometers 和 meters。

当我们在输入框输入数据时,watch 会实时监听数据变化并改变自身的值。

8.2 异步加载中使用 watch

<div id="watch-example">
  <p>
    输入一个问题,以 ? 号结尾输出答案:
    <input v-model="question" />
  </p>
  <p>{{ answer }}</p>
</div>  
<script>
const watchExampleVM = Vue.createApp({
   data() {
      return {
         question: '',
         answer: '每个问题结尾需要输入 ? 号。'
      }
   },
   watch: {
      // 每当问题改变时,此功能将运行,以 ? 号结尾
      question(newQuestion, oldQuestion) {
         if (newQuestion.indexOf('?') > -1) {
            this.getAnswer()
         }
      }
   },
   methods: {
      getAnswer() {
         this.answer = '加载中...'
         axios
            .get('https://yesno.wtf/api')
            .then(response => {
            this.answer = response.data.answer
         })
            .catch(error => {
            this.answer = '错误! 无法访问 API。 ' + error
         })
      }
   }
}).mount('#watch-example')
</script>

9 样式绑定

我们可以为 v-bind:class 设置一个对象,从而动态的切换 class:

<div class="static" :class="{ 'active' : isActive, 'text-danger' : hasError }">
</div>

我们也可以在这里绑定一个返回对象的计算属性。这是一个常用且强大的模式:

<div id="app">
    <div class="static" :class="classObject"></div>
</div>

<script>
const app = {
   data() {
      return {
         isActive: true,
         error: null
      }
   },
   computed: {
      classObject() {
         return {
            active: this.isActive && !this.error,
            'text-danger': this.error && this.error.type === 'fatal'
         }
      }
   }
}

Vue.createApp(app).mount('#app')
</script>

数组语法:

<div id="app">
    <div class="static" :class="[isActive ? activeClass : '', errorClass]"></div>
</div>

<script>
const app = {
    data() {
        return {
            isActive: false,
			activeClass: 'active',
			errorClass: 'text-danger'
        }
    }
}

Vue.createApp(app).mount('#app')
</script>

组件上使用 class 属性:

当你在带有单个根元素的自定义组件上使用 class 属性时,这些 class 将被添加到该元素中。此元素上的现有 class 将不会被覆盖。

<div id="app">
    <runoob class="classC classD"></runoob>
</div>
 
<script>
// 创建一个Vue 应用
const app = Vue.createApp({})
 
// 定义一个名为 runoob的新全局组件
app.component('runoob', {
    template: '<h1 class="classA classB">I like runoob!</h1>'
})
 
app.mount('#app')
</script>

以上实例 div class 渲染结果为:

<h1 class="classA classB classC classD">I like runoob!</h1>

10 事件处理

<div id="app">
  <button @click="say('hi')">Say hi</button>
  <button @click="say('what')">Say what</button>
</div>
 
<script>
const app = {
  data() {
   
  },
  methods: {
    say(message) {
      alert(message)
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>

事件处理程序中可以有多个方法,这些方法由逗号运算符分隔:

<div id="app">
  <!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
  <button @click="one($event), two($event)">
  点我
  </button>
</div>
 
<script>
const app = {
  data() {
  },
  methods: {
    one(event) {
      alert("第一个事件处理器逻辑...")
    },
    two(event) {
      alert("第二个事件处理器逻辑...")
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>

11 表单

v-model 会根据控件类型自动选取正确的方法来更新元素。

v-model 会忽略所有表单元素的 value、checked、selected 属性的初始值,使用的是 data 选项中声明初始值。

v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • text 和 textarea 元素使用 value 属性和 input 事件
  • checkbox 和 radio 使用 checked 属性和 change 事件
  • select 字段将 value 作为属性并将 change 作为事件

11.1 text textarea

<div id="app">
  <p>input 元素:</p>
  <input v-model="message" placeholder="编辑我……">
  <p>input 表单消息是: {{ message }}</p>
    
  <p>textarea 元素:</p>
  <textarea v-model="message2" placeholder="多行文本输入……"></textarea>
  <p>textarea 表单消息是:</p>
  <p style="white-space: pre">{{ message2 }}</p>
  
</div>

<script>
const app = {
  data() {
    return {
      message: '',
	  message2: '菜鸟教程\r\nhttps://www.runoob.com'
    }
  }
}

Vue.createApp(app).mount('#app')
</script>

11.2 checkbox

<div id="app">
  <p>单个复选框:</p>
  <input type="checkbox" id="checkbox" v-model="checked">
  <label for="checkbox">{{ checked }}</label>
    
  <p>多个复选框:</p>
  <input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
  <label for="runoob">Runoob</label>
  <input type="checkbox" id="google" value="Google" v-model="checkedNames">
  <label for="google">Google</label>
  <input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
  <label for="taobao">taobao</label>
  <br>
  <span>选择的值为: {{ checkedNames }}</span>
</div>

<script>
const app = {
  data() {
    return {
      checked : false,
      checkedNames: []
    }
  }
}

Vue.createApp(app).mount('#app')
</script>

11.3 单选按钮

<div id="app">
  <input type="radio" id="runoob" value="Runoob" v-model="picked">
  <label for="runoob">Runoob</label>
  <br>
  <input type="radio" id="google" value="Google" v-model="picked">
  <label for="google">Google</label>
  <br>
  <span>选中值为: {{ picked }}</span>
</div>

<script>
const app = {
  data() {
    return {
      picked : 'Runoob'
    }
  }
}

Vue.createApp(app).mount('#app')
</script>

11.4 select 列表

<div id="app">
  <select v-model="selected" name="fruit">
    <option value="">选择一个网站</option>
    <option value="www.runoob.com">Runoob</option>
    <option value="www.google.com">Google</option>
  </select>
 
  <div id="output">
      选择的网站是: {{selected}}
  </div>
</div>

<script>
const app = {
  data() {
    return {
      selected: '' 
    }
  }
}

Vue.createApp(app).mount('#app')
</script>

多选时会绑定到一个数组:

<div id="app">
  <select v-model="selected" name="fruit" multiple>
    <option value="www.runoob.com">Runoob</option>
    <option value="www.google.com">Google</option>
    <option value="www.taobao.com">Taobao</option>
  </select>
 
  <div id="output">
      选择的网站是: {{selected}}
  </div>
</div>
 
<script>
const app = {
  data() {
    return {
      selected: []
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>

11.5 值绑定

有时我们可能想把值绑定到当前活动实例的一个动态属性上,这时可以用 v-bind 实现,此外,使用 v-bind 可以将输入值绑定到非字符串。

<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
// 选中时
vm.toggle === 'yes'
// 取消选中 
vm.toggle === 'no'

<input type="radio" v-model="pick" v-bind:value="a" />
// 当选中时
vm.pick === vm.a

<select v-model="selected">
  <!-- 内联对象字面量 -->
  <option :value="{ number: 123 }">123</option>
</select>
// 当被选中时
typeof vm.selected // => 'object'
vm.selected.number // => 123

11.6 修饰符

.lazy

在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:

<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

.number

如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:

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

这通常很有用,因为在 type=“number” 时 HTML 中输入的值也总是会返回字符串类型。

.trim

如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:

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

12 路由

Vue 路由允许我们通过不同的 URL 访问不同的内容。

通过 Vue 可以实现多视图的单页 Web 应用(single page web application,SPA)。

12.1 CDN

<script src="https://unpkg.com/vue-router@4"></script>

12.2 简单实例

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!--使用 router-link 组件进行导航 -->
    <!--通过传递 `to` 来指定链接 -->
    <!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签-->
    <router-link to="/">Go to Home</router-link><br />
    <router-link to="/about">Go to About</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>

<script>
// 1. 定义路由组件.
// 也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }
 
// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]
 
// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = VueRouter.createRouter({
  // 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
  history: VueRouter.createWebHashHistory(),
  routes, // `routes: routes` 的缩写
})
 
// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router)
 
app.mount('#app')
 
// 现在,应用已经启动了!
</script>

我们没有使用常规的 a 标签,而是使用一个自定义组件 router-link 来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。

12.3 <router-link> 相关属性

to:

表示目标路由的链接。 当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。

<!-- 字符串 -->
<router-link to="home">Home</router-link>
<!-- 渲染结果 -->
<a href="home">Home</a>

<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'home'">Home</router-link>

<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link :to="'home'">Home</router-link>

<!-- 同上 -->
<router-link :to="{ path: 'home' }">Home</router-link>

<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>

replace:

设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),导航后不会留下 history 记录。

<router-link :to="{ path: '/abc'}" replace></router-link>

append:

设置 append 属性后,则在当前 (相对) 路径前添加其路径。例如,我们从 /a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b

<router-link :to="{ path: 'relative/path'}" append></router-link>

event:

声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。

<router-link v-bind:to = "{ path: '/route1'}" event = "mouseover">Router Link 1</router-link>

以上代码设置了 event 为 mouseover ,及在鼠标移动到 Router Link 1 上时导航的 HTML 内容会发生改变。

13 Ajax(axios)

Vue 版本推荐使用 axios 来完成 ajax 请求。

Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。

13.1 CDN

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>

13.2 使用方法

Vue.axios.get(api).then((response) => {
  console.log(response.data)
})

this.axios.get(api).then((response) => {
  console.log(response.data)
})

this.$http.get(api).then((response) => {
  console.log(response.data)
})

13.3 GET 方法

<div id="app">
  <h1>网站列表</h1>
  <div
    v-for="site in info"
  >
    {{ site.name }}
  </div>
</div>

<script>
const app = {
  data() {
    return {
      info: 'Ajax 测试!!'
    }
  },
  mounted () {
    axios
      .get('https://www.runoob.com/try/ajax/json_demo.json')
      .then(response => (this.info = response.data.sites))
      .catch(function (error) { // 请求失败处理
        console.log(error);
      });
  }
}

Vue.createApp(app).mount('#app')
</script>

GET 方法传递参数:

// 直接在 URL 上添加参数 ID=12345
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
 
// 也可以通过 params 设置参数:
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

13.4 POST 方法

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

<script>
const app = {
  data() {
    return {
      info: null
    }
  },
  mounted () {
    axios
      .post('https://www.runoob.com/try/ajax/demo_axios_post.php')
      .then(response => (this.info = response))
      .catch(function (error) { // 请求失败处理
        console.log(error);
      });
  }
}

Vue.createApp(app).mount('#app')
</script>

POST 方法传递参数:

axios.post('/user', {
    firstName: 'Fred',        // 参数 firstName
    lastName: 'Flintstone'    // 参数 lastName
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

13.5 执行多个并发请求

function getUserAccount() {
  return axios.get('/user/12345');
}
 
function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求现在都执行完成
  }));
pt>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值