VUE(修饰符+自定义指令directive+组件Component+组件交互+自定义事件+插槽slot)

表单修饰符

.lazy

在默认情况下,使用 v-model 使 input标签中的内容与data中的属性双向绑定,值实时同步。但添加 lazy 修饰符后,从而让数据在 失去焦点 或者 回车 时才会更新同步

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

lazy修饰符可以避免value内容没有打完就执行后续的change方法

.number

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

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

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

.trim

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

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

事件修饰符

为了方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。vue提供了方法修饰符

.stop

阻止单击事件继续以冒泡顺序(从里层到外层)传播

举例:

<a v-on:click="do1">
	<a v-on:click="do2">
		<a v-on:click="do3">a>  
	a>
a>
<a v-on:click="do1">
	<a v-on:click.stop="do2">  
		<a v-on:click="do3">a>  
	a>
a>

.prevent

阻止默认事件,只是执行自己命名的函数,使用的并不多

举例:

<form v-on:submit.prevent="alert('hello')">form>  

.capture

即是给元素添加一个监听器,当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。
没加capture修饰符的就遵从冒泡顺序。


<a v-on:click.capture="do1">
	<a v-on:click="do2">
    	<a v-on:click.capture="do3">
        	<a v-on:click="do4">a>  
       a>
	a>
a>

.self

点击当前元素自身时才触发事件
可以理解为跳过冒泡事件和捕获事件

<a v-on:click="do1">
	<a v-on:click.self="do2">   
    	<a v-on:click="do3">a>   
       
	a>
a>

.once

多次点击事件将只会触发事件一次

修饰符注意点

1、 修饰符可以串联

<a v-on:click.stop.prevent="doThat">a>

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


自定义指令

Vue除了提供了默认内置的指令外,还允许开发人员根据实际情况自定义指令,它的作用价值在于当开发人员在某些场景下需要对普通DOM元素进行操作的时候。

注册全局指令

Vue.directive( id, [definition] )

第一个参数为自定义指令名称(指令名称不需要加 v- 前缀,默认是自动加上前缀的,使用指令的时候一定要加上前缀)
第二个参数可以是对象数据,也可以是一个函数。

<div id="app">
    <input type="text" v-focus>
div>
<script>
    Vue.directive("focus", {
        inserted: function(el){// 当被绑定的元素插入到 DOM 中时……
            el.focus();// 聚焦元素
        }
    })
    new Vue({
        el: "#app"
    })
script>

注册局部指令

在实例化对象中也接受一个 directives 的选项:

new Vue({
	el: "#app",
    directives: {
		focus: {
    	// 指令的定义
	    	inserted: function (el) {
      			el.focus()
    		}
  		}
	}
})

上述例子实现了在页面加载完成之后自动聚焦到输入框的功能。其中 inserted 是自定义指令的钩子函数

钩子函数

待更新


组件

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。由于组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
VUE(修饰符+自定义指令directive+组件Component+组件交互+自定义事件+插槽slot)_第1张图片

全局组件

全局组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中,甚至各个全局组件 在各自内部 也都可以相互使用

全局组件的注册:

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

组件命名注意点:

你给予组件的名字可能依赖于你打算拿它来做什么,强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符),这会帮助你避免和当前以及未来的 HTML 元素相冲突。

组件data注意点:

当我们定义这个 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象data: { count: 0 }取而代之的是:一个组件的 data 选项必须是一个函数,从而每个实例可以维护一份独立的拷贝:

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

全局组件的使用:

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

<div id="components-demo">
	<button-counter>button-counter>
    <button-counter>button-counter>
    <button-counter>button-counter>
div>

每个组件都会各自独立维护它的data。每用一次组件,就会有一个它的新实例被创建
它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中

局部组件

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

局部组件的注册:

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

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }

局部组件的使用:

在根实例的 components 选项中定义你想要使用的组件:

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

对于 components 对象中的每个 property 来说,其 property名就是 自定义组件 的名字,其 property值就是这个组件的对象。

注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentAComponentB 中可用,则你需要这样写:

var ComponentA = { /* ... */ }

var ComponentB = {
  components: {
    'component-a': ComponentA
  },
}

组件交互Prop (父 -> 子)

prop 是你可以在组件上注册的一些 自定义 属性。当一个值传递给一个 prop属性 的时候,它就变成了那个组件实例的一个 property。一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop

使用举例:

在根实例中有一个数组,存着一些数据,同时需要在blog-post组件中使用这些数据,那么就可以在blog-post组件中添加一个props属性

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

{{ title }}

'
}) new Vue({ el: '#blog-post-demo', data: { blogs: [ { 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="blog in blogs"  :key="blog.id"  :title="blog.title">blog-post>

页面效果:
VUE(修饰符+自定义指令directive+组件Component+组件交互+自定义事件+插槽slot)_第2张图片

prop 命名注意点

HTML 中的 attribute 名是大小写不敏感的,prop 名最好是kebab-case (短横线分隔命名) 方式命名。ps : 如果使用字符串模板就可以使用驼峰命名,为了不搞混还是统一使用 kebab-case 方式命名

指定prop的类型

上述的举例中以字符串数组形式列出了 prop ,但通常我们希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:

基础的类型检查:

Vue.component('my-component', {
	props: {
  		title: String,
  		likes: Number,
  		isPublished: Boolean,
  		commentIds: Array,
  		author: Object,
  		callback: Function
	}
}

进阶的类型检查:

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
      }
    }
  }
})

这为你的组件提供了类型文档。如果有一个需求没有被满足,在它们遇到错误的类型时,Vue 就会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。

传递静态或动态 Prop

像这样给 prop 传入一个静态的值:

<blog-post title="My journey with Vue">blog-post>

同时 prop 可以通过 v-bind 进行动态赋值:


<blog-post v-bind:title="blog.title">blog-post>


<blog-post v-bind:title="blog.title + 'by' + blog.author.name">blog-post>

在上述两个示例中,传入的值都是字符串类型的,但实际上 任何 类型的值都可以传给一个 prop

传入一个数字


<blog-post v-bind:likes="42">blog-post>


<blog-post v-bind:likes="post.likes">blog-post>

传入一个布尔值


<blog-post is-published>blog-post>


<blog-post v-bind:is-published="false">blog-post>


<blog-post v-bind:is-published="post.isPublished">blog-post>

传入一个数组


<blog-post v-bind:comment-ids="[234, 266, 273]">blog-post>


<blog-post v-bind:comment-ids="post.commentIds">blog-post>

传入一个对象

对于一个给定的对象 post

post: {
  id: 1,
  title: 'My Journey with Vue'
}

<blog-post
  v-bind:author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
>blog-post>


<blog-post v-bind:="post">blog-post>


<blog-post v-bind:id="post.id" v-bind:title="post.title" >blog-post>

单向数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。因为这导致你的应用的数据流向难以理解

以下是两种常见的试图变更一个 prop 的情形:

1、这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 用作其初始值:

props: ['initialCounter'],
data: function () {
  return {
    counter: this.initialCounter
  }
}

2、这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

注意 在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中变更这个对象或数组本身将会 影响 到父组件的状态。

自定义事件/监听子组件事件 (子 -> 父)

有时子组件的一些功能可能要求和父级组件进行沟通,例如:触发事件让父组件做出响应,或者还想传数据给父组件。Vue 实例提供了一个自定义事件的系统来解决这个问题。父级组件可以像处理 native DOM 事件一样通过 v-on 监听子组件实例的任意事件:

举例:

我们想用一个放大字号按钮改变全局的文章的字号大小

定义一个根实例:

new Vue({
  	el: '#blog-posts-events-demo',
  	data: {
   		posts: [/* ... */],
    	postFontSize: 1 //这个 property 来控制全局字号大小
  	}
})

定义一个子组件:
提供三个功能:1、标题显示。 2、放大字体按钮。3、显示内容

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

{{ post.title }}

`
})

子组件可以通过调用内建的 $emit 方法并传入事件名称(enlarge-text)来触发一个父组件事件

html部分:

父组件监听对应子组件传入的事件名称,子组件提示触发时,父组件反馈响应(字号属性+0.1)

<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
    <blog-post
      v-for="post in posts"
      v-bind:key="post.id"
      v-bind:post="post"
      v-on:enlarge-text="postFontSize += 0.1"
    >blog-post>
  div>
div>

这还不够!!!有的时候我们需要传值给父组件,我们把上面的例子进行扩展。

举例

我们想让子组件的button来决定到底放大多少字号而不是按一下放大一点,那么这个时候就需要传一个明确的值给父组件

这其实比想象中简单,只需为$emit添加第二个参数即可

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

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

<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event">
blog-post>

很多时候父组件的响应是一个function(onEnlargeText)

<blog-post
  ...
  v-on:enlarge-text="onEnlargeText">
blog-post>

那么这个值将会作为第一个参数enlargeAmount(参数名自定义)传入这个方法:

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

在更复杂的情况下,我们应该考虑使用专门的状态管理模式Vuex

插槽slot

默认插槽

有时为一个插槽设置具体的默认内容是很有用的,它只会在没有提供内容的时候被渲染。例如在一个 组件中,我们可能希望这个 内绝大多数情况下都渲染默认文本,我们可以将默认文本放在 标签内:

template:`
	<button type="submit">
  		<slot>我是一个默认内容slot>
	button>
`

在父组件中不添加任何内容地使用这个组件:

<submit-button>submit-button>

默认内容会被渲染:

<button type="submit">
  	我是一个默认内容
button>

但若为组件提供了内容:

<submit-button>用户自定义内容submit-button>

则这个提供的内容将会被渲染从而取代默认内容:

<button type="submit">
  	用户自定义内容
button>

具名插槽

很多时候我们需要多个插槽,对于一个带有如下模板的 组件:

template:`
	<div class="container">
  		<header>
  			<slot>slot>
    		
  		header>
  		
  		<main>
  			<slot>slot>
    		
  		main>
  		
  		<footer>
  			<slot>slot>
    		
  		footer>
div>
`

对于这样的情况, 元素有一个特殊的 attribute—name,不带 name 的 会带有隐含的名字“default”

template:`
	<div class="container">
  		<header>
    		<slot name="header">slot>
  		header>
  		
  		<main>
    		<slot>slot>
  		main>
  		
  		<footer>
    		<slot name="footer">slot>
  		footer>
	div>
`

在向具名插槽提供内容的时候,我们可以在一个 元素上使用 v-slot 指令,并以 v-slot (#为其缩写)的参数的形式提供其名称:
注意:slot指令已被弃用,尽量在teplate标签上使用v-slot指令

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page titleh1>
  template>

  <p>A paragraph for the main content.p>
  <p>And another one.p>

  <template #footer>     
    <p>Here's some contact infop>
  template>
base-layout>

现在