从小白开始学vue学习笔记(二)——事件篇

目录

 

一、事件处理

1、监听事件

2、事件处理方法

3、内联处理器种的方法

4、事件修饰符

默认冒泡

5、按键修饰符

(1)按键符

(2)系统修饰符

(3).exact修饰符

(4)鼠标按钮修饰符

6、为什么在HTML中监听事件

二、表单输入绑定

1、基础用法

2、文本

3、多行文本

4、复选框

5、单选按钮

6、选择框

7、值绑定

(1)复选框

(2)单选按钮

(3)选择框的选项

8、修饰符

(1).lazy

(2).number

(3).trim

9、在组件上使用v-model

三、组件基础

1、基本示例

2、组件的复用

(1)data必须是一个函数

3、组件的组织

4、通过prop向子组件传递数据

5、单个根元素

6、监听子组件事件

vm.$emit( eventName, […args] )

 7、使用事件抛出一个值

 8、在组件上使用v-model

9、通过插槽分发内容

10、动态组件

11、解析DOM模板时的注意事项


一、事件处理

1、监听事件

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

示例:

The button above has been clicked {{ counter }} times.

var example1 = new Vue({
  el: '#example-1',
  data: {
    counter: 0
  }
})

结果:

 

2、事件处理方法

然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。

示例:

var example2 = new Vue({
  el: '#example-2',
  data: {
    name: 'Vue.js'
  },
  // 在 `methods` 对象中定义方法
  methods: {
    greet: function (event) {
      // `this` 在方法里指向当前 Vue 实例
      alert('Hello ' + this.name + '!')
      // `event` 是原生 DOM 事件
      if (event) {
        alert(event.target.tagName)
      }
    }
  }
})

// 也可以用 JavaScript 直接调用方法
example2.greet() // => 'Hello Vue.js!'

直接调用example2.greet() ----->只弹出hello vue.js 不弹出 button-->结果 button

 

3、内联处理器种的方法

除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:

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

有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法:

// ...
methods: {
  warn: function (message, event) {
    // 现在我们可以访问原生事件对象
    if (event) event.preventDefault()
    alert(message)
  }
}

$event是原始的DOM对象

从小白开始学vue学习笔记(二)——事件篇_第1张图片

 

preventDefault() 方法阻止元素发生默认的行为(例如,当点击提交按钮时阻止对表单的提交)。

语法

event.preventDefault()
参数 描述
event 必需。规定阻止哪个事件的默认动作。这个 event 参数来自事件绑定函数。

 

4、事件修饰符

默认冒泡

默认情况下,js的事件会向上冒泡,如:以下三个div元素:

当我们点击里层的div,会触发外层的div事件

let vm = new Vue({
    el: "#app",
    data: {
    },
    methods: {
        catchSon() {
            console.log('我还小,别抓我啊...');
        },
        catchFather() {
            console.log('我上有老,下有小,各位官爷,手下留情啊...');
        },
        catchGrandfather() {
            console.log('你们这些兔崽子,敢动我这把老骨头试下!');
        }
    }
})

vue提供了事件修饰符,可以修改默认的事件触发机制:

  • .stop 阻止冒泡

  • .prevent 阻止默认事件

  • .capture 添加事件侦听器时使用事件捕获模式

  • .self 只当事件在该元素本身(比如不是子元素)触发时触发回调

  • .once 事件只触发一次

 

在事件处理程序中调用 event.preventDefault() event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive




...
...

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

2.1.4 新增


不像其它只能对原生的 DOM 事件起作用的修饰符.once 修饰符还能被用到自定义的组件事件上。如果你还没有阅读关于组件的文档,现在大可不必担心。

2.3.0 新增

Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符。

滚动事件的默认行为 (即滚动行为) 将会立即触发
而不会等待 `onScroll` 完成
这其中包含 `event.preventDefault()` 的情况




...

这个 .passive 修饰符尤其能够提升移动端的性能。

不要把 .passive.prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你想阻止事件的默认行为。

 

5、按键修饰符

在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:


你可以直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符。

在上述示例中,处理函数只会在 $event.key 等于 PageDown 时被调用。

(1)按键符

keyCode 的事件用法已经被废弃了并可能不会被最新的浏览器支持。

使用 keyCode 特性也是允许的:

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

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

有一些按键 (.esc 以及所有的方向键) 在 IE9 中有不同的 key 值, 如果你想支持 IE9,这些内置的别名应该是首选。

你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名:

// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112

 

(2)系统修饰符

2.1.0 新增

可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器

  • .ctrl
  • .alt
  • .shift
  • .meta

注意:在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。

例如:@表示 v-on:





Do something

请注意修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCodekeyup.17

 

(3).exact修饰符

2.5.0 新增

.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。








 

(4)鼠标按钮修饰符

2.2.0 新增

  • .left
  • .right
  • .middle

这些修饰符会限制处理函数仅响应特定的鼠标按钮。

 

6、为什么在HTML中监听事件

你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。

  1. 关注点分离原则,也叫正交原则,HTML CSS JS 分离 互不影响 分在几个文件里写用link相互关联
  2. 状态转移:js不去修改css 的样式(.style.color='red'),只修改css中的状态(addClass('active'))。

但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:

  1. 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。

  2. 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。

  3. 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。

 

二、表单输入绑定

1、基础用法

你可以用 v-model 指令在表单

从小白开始学vue学习笔记(二)——事件篇_第3张图片

在文本区域插值 () 并不会生效,应用 v-model 来代替。

从小白开始学vue学习笔记(二)——事件篇_第4张图片

 

4、复选框

单个复选框,绑定到布尔值:


var example = new Vue({
    el: "#example",
    data: {
        checked: false
    }
})

多个复选框,绑定到同一个数组:


Checked names: {{ checkedNames }}
new Vue({
  el: '#example-3',
  data: {
    checkedNames: []
  }
})

 

5、单选按钮



Picked: {{ picked }}
new Vue({
  el: '#example-4',
  data: {
    picked: ''
  }
})

 

6、选择框

单选时:

Selected: {{ selected }}
new Vue({
  el: '...',
  data: {
    selected: ''
  }
})

 

如果 v-model 表达式的初始值未能匹配任何选项,
Selected: {{ selected }}

new Vue({
  el: '#example-6',
  data: {
    selected: []
  }
})

 

v-for 渲染的动态选项:


Selected: {{ selected }}
new Vue({
  el: '...',
  data: {
    selected: 'A',
    options: [
      { text: 'One', value: 'A' },
      { text: 'Two', value: 'B' },
      { text: 'Three', value: 'C' }
    ]
  }
})

 

7、值绑定

等价于

value="a"是显示在文本框里的内容,加入了v-model以后双向绑定了将替换掉这个value

类似百度搜索的输入框输入后实时搜索的功能,发现使用输入法 (如中文、日文、韩文等) 的时候,v-model不会在输入法组合文字过程中得到更新,打开官方文档查找后发现文档中已经提到了这种情况。官方推荐直接使用input事件来处理。可以向下面这样写:


 

对于单选按钮,复选框及选择框的选项,v-model 绑定的值通常是静态字符串 (对于复选框也可以是布尔值):








但是有时我们可能想把值绑定到 Vue 实例的一个动态属性上,这时可以用 v-bind 实现,并且这个属性的值可以不是字符串

 

(1)复选框

// 当选中时
vm.toggle === 'yes'
// 当没有选中时
vm.toggle === 'no'

这里的 true-valuefalse-value 特性并不会影响输入控件的 value 特性因为浏览器在提交表单时并不会包含未被选中的复选框。如果要确保表单中这两个值中的一个能够被提交,(比如“yes”或“no”),请换用单选按钮。

 

(2)单选按钮

// 当选中时
vm.pick === vm.a

 

(3)选择框的选项

// 当选中时
typeof vm.selected // => 'object'
vm.selected.number // => 123

 

8、修饰符

(1).lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步:(输入结束后点击别的地方失去焦点才同步)


(2).number

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

这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

添加.number

 

(3).trim

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

 

9、在组件上使用v-model

如果你还不熟悉 Vue 的组件,可以暂且跳过这里。

HTML 原生的输入元素类型并不总能满足需求。幸好,Vue 的组件系统允许你创建具有完全自定义行为且可复用的输入组件。这些输入组件甚至可以和 v-model 一起使用!要了解更多,请参阅组件指南中的自定义输入组件。

 

三、组件基础

1、基本示例

这里有一个 Vue 组件的示例:

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: ''
})

组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

new Vue({ el: '#components-demo' })

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项

 

2、组件的复用

你可以将组件进行任意次数的复用

注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。

 

(1)data必须是一个函数

当我们定义这个 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:

data: {
  count: 0
}

取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝

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

如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到其它所有实例

可实际上会报错:

从小白开始学vue学习笔记(二)——事件篇_第5张图片

 

3、组件的组织

通常一个应用会以一棵嵌套的组件树的形式来组织:

从小白开始学vue学习笔记(二)——事件篇_第6张图片

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的

Vue.component('my-component-name', {
  // ... options ...
})

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

到目前为止,关于组件注册你需要了解的就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把组件注册读完。

 

4、通过prop向子组件传递数据

早些时候,我们提到了创建一个博文组件的事情。问题是如果你不能向这个组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的。这也正是 prop 的由来。

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:

Vue.component('blog-post', {
  props: ['title'],
  template: '

{{ title }}

' })

一个组件默认可以拥有任意数量的 prop任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。

一个 prop 被注册之后,你就可以像这样把数据作为一个自定义特性传递进来:



Vue.component('blog-post', {
    props: ['title'],
    template: '

{{ title }}

' }) new Vue({ el: '#example', data: { // posts: [ // { id: 1, title: 'My journey with Vue' }, // { id: 2, title: 'Blogging with Vue' }, // { id: 3, title: 'why Vue is so fun' } // ] } })

然而在一个典型的应用中,你可能在 data 里有一个博文的数组:

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'My journey with Vue' },
      { id: 2, title: 'Blogging with Vue' },
      { id: 3, title: 'Why Vue is so fun' }
    ]
  }
})

并想要为每篇博文渲染一个组件:

如上所示,你会发现我们可以使用 v-bind 来动态传递 prop。这在你一开始不清楚要渲染的具体内容,比如从一个 API 获取博文列表的时候,是非常有用的。

到目前为止,关于 prop 你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把 prop 读完。

 

5、单个根元素

当构建一个 组件时,你的模板最终会包含的东西远不止一个标题:

{{ title }}

最最起码,你会包含这篇博文的正文:

{{ title }}

********************v-html的用法:*************************

{{message}}
export default { data () { return { message: "这里可以包含html标签" } } }

 

然而如果你在模板中尝试这样写,Vue 会显示一个错误,并解释道 every component must have a single root element (每个组件必须只有一个根元素)

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

{{ title }}

看起来当组件变得越来越复杂的时候,我们的博文不只需要标题和内容,还需要发布日期、评论等等。为每个相关的信息定义一个 prop 会变得很麻烦:

所以是时候重构一下这个 组件了,让它变成接受一个单独的 post prop

Vue.component('blog-post', {
  props: ['post'],
  template: `
    

{{ post.title }}

` })

*****************使用是反引号不是单引号**********************

ES6 模板字符串(Template String)是增强版的字符串,用反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量

 

******************也可以使用折行转义字符*********************

var htmlSTring = "
\ This is a string.\
";

上述的这个和一些接下来的示例使用了 JavaScript 的模板字符串来让多行的模板更易读。它们在 IE 下并没有被支持,所以如果你需要在不 (经过 Babel 或 TypeScript 之类的工具) 编译的情况下支持 IE,请使用折行转义字符取而代之。

现在,不论何时为 post 对象添加一个新的属性,它都会自动地在 内可用。

 

6、监听子组件事件

在我们开发 组件时,它的一些功能可能要求我们和父级组件进行沟通。例如我们可能会引入一个辅助功能来放大博文的字号,同时让页面的其它部分保持默认的字号。

在其父组件中,我们可以通过添加一个 postFontSize 数据属性来支持这个功能:

new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  }
})

它可以在模板中用来控制所有博文的字号:

现在我们在每篇博文正文之前添加一个按钮来放大字号:

Vue.component('blog-post', {
  props: ['post'],
  template: `
    

{{ post.title }}

` })

问题是这个按钮不会做任何事:

当点击这个按钮时,我们需要告诉父级组件放大所有博文的文本。幸好 Vue 实例提供了一个自定义事件的系统来解决这个问题。父级组件可以像处理 native DOM 事件一样通过 v-on 监听子组件实例的任意事件:

同时子组件可以通过调用内建的 $emit 方法 并传入事件名称来触发一个事件:

有了这个 v-on:enlarge-text="postFontSize += 0.1" 监听器,父级组件就会接收该事件并更新 postFontSize 的值。

一放大每个都会放大,怎么才能让他只放大自己?

vm.$emit( eventName, […args] )

  • 参数

    • {string} eventName
    • [...args]

    触发当前实例上的事件。附加参数都会传给监听器回调。

  • 示例:

    只配合一个事件名使用 $emit

    Vue.component('welcome-button', {
      template: `
        
      `
    })
    new Vue({
      el: '#emit-example-simple',
      methods: {
        sayHi: function () {
          alert('Hi!')
        }
      }
    })

 

7、使用事件抛出一个值

有的时候用一个事件来抛出一个特定的值是非常有用的。例如我们可能想让 组件决定它的文本要放大多少。这时可以使用 $emit 的第二个参数来提供这个值:

然后当在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值:

或者,

如果这个事件处理函数是一个方法:

那么这个值将会作为第一个参数传入这个方法:

methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

 

8、在组件上使用v-model

自定义事件也可以用于创建支持 v-model 的自定义输入组件。记住:

等价于:

当用在组件上时,v-model 则会这样:

为了让它正常工作,这个组件内的 必须:

  • 将其 value 特性绑定到一个名叫 value 的 prop 上
  • 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出

写成代码之后是这样的:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    
  `
})

现在 v-model 就应该可以在这个组件上完美地工作起来了:

到目前为止,关于组件自定义事件你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把自定义事件读完。

 

9、通过插槽分发内容

和 HTML 元素一样,我们经常需要向一个组件传递内容,像这样:


  Something bad happened.

可能会渲染出这样的东西:

幸好,Vue 自定义的 元素让这变得非常简单:

Vue.component('alert-box', {
  template: `
    
Error!
` })

如你所见,我们只要在需要的地方加入插槽就行了——就这么简单!

到目前为止,关于插槽你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把插槽读完。

***插槽内容****

  一句话:插槽内可以是任意内容。

 

10、动态组件

有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:

上述内容可以通过 Vue 的 元素加一个特殊的 is 特性来实现:


在上述示例中,currentTabComponent 可以包括

  • 已注册组件的名字,或
  • 一个组件的选项对象

css

        .tab-button {
            padding: 6px 10px;
            border-top-left-radius: 3px;
            border-top-right-radius: 3px;
            border: 1px solid #ccc;
            cursor: pointer;
            background: #f0f0f0;
            margin-bottom: -1px;
            margin-right: -1px;
        }
        
        .tab-button:hover {
            background: #e0e0e0;
        }
        
        .tab-button.active {
            background: #e0e0e0;
        }
        
        .tab {
            border: 1px solid #ccc;
            padding: 10px;
        }

你可以在这里查阅并体验完整的代码,

Vue.component('tab-home', {
    template: '
Home component
' }) Vue.component('tab-posts', { template: '
Posts component
' }) Vue.component('tab-archive', { template: '
Archive component
' }) new Vue({ el: '#dynamic-component-demo', data: { currentTab: 'Home', tabs: ['Home', 'Posts', 'Archive'] }, computed: { currentTabComponent: function() { return 'tab-' + this.currentTab.toLowerCase() } } })

或在这个版本了解绑定组件选项对象,而不是已注册组件名的示例。

var tabs = [{
        name: 'Home',
        component: {
            template: '
Home component
' } }, { name: 'Posts', component: { template: '
Posts component
' } }, { name: 'Archive', component: { template: '
Archive component
', } } ] new Vue({ el: '#dynamic-component-demo', data: { tabs: tabs, currentTab: tabs[0] } })

到目前为止,关于动态组件你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把动态和异步组件读完。

 

11、解析DOM模板时的注意事项

有些 HTML 元素,诸如

      ,只能出现在其它某些特定的元素内部。

      这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

      这个自定义组件 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:

      需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在

      • 字符串 (例如:template: '...')
      • 单文件组件 (.vue)

你可能感兴趣的:(框架,vue)