Vue组件和插槽使用


表单

针对通常元素,好比div,span 、p、 img等,采用的是单向绑定: v-bind 只要把数据绑定到视图中就能够,可是对于表单这种交互比较强的元素或组件,咱们通常可能需求双向绑定,即:用户对视图元素的操做同时更新数据。javascript

v-model 在内部为不一样的输入元素使用不一样的属性和事件来处理数据css

  • text & textarea
  • checkbox & radio
  • select

text 和 textrea

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="text" v-model="v1">
        <textarea name="" id="" v-model="v2" cols="30" rows="10"></textarea>
    </div>

    <script> let app = new Vue({ //el指定id为app的元素 el: "#app", //template替换的是id为app的元素的全部内容 data: { v1:'aaa', v2:'bbbb' }, }) </script>
</body>

</html>

效果图以下


image.pnghtml

checkbox 和radio

checkbox 和 radio 使用checked属性和change事件vue

  • 单选框绑定一个值
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="radio" name="" id="" v-model="v3"value="男">男
        <input type="radio" name="" id="" v-model="v3" value=""><button @click="getData">按钮</button>
    </div>

    <script> let app = new Vue({ //el指定id为app的元素 el: "#app", //template替换的是id为app的元素的全部内容 data: { v1:'aaa', v2:'bbbb', v3:'男' }, methods:{ getData(){ console.log(this.v3); } } }) </script>
</body>

</html>

效果以下
image.pngjava

  • 多选框绑定到一个布尔值或者数组
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="radio" name="" id="" v-model="v3"value="男">男
        <input type="radio" name="" id="" v-model="v3" value=""><button @click="getData">按钮</button>
        <!-- -->
        <hr>
        <!-- 单选 -->
        <input type="checkbox" v-model="v4">赞成
        <hr>
        <!-- 多选 -->
        <input type="checkbox" name="" id="" v-model="v5" value="足球">足球
        <input type="checkbox" name="" id="" v-model="v5" value="篮球">篮球
    </div>

    <script> let app = new Vue({ //el指定id为app的元素 el: "#app", //template替换的是id为app的元素的全部内容 data: { v1:'aaa', v2:'bbbb', v3:'男', v4:true, v5:['足球','音乐'] }, methods:{ getData(){ console.log(this.v3); } } }) </script>
</body>

</html>

效果以下
image.pngweb

select

select字段将value 做为prop并将change做为事件npm

  • 单选绑定到值,多选绑定到数组
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 单选 -->
        <select name="" id="" v-model="v3">
            <option value=""></option>
            <option value=""></option>
        </select>
        <!-- 多选 -->
        <select name="" id="" v-model="v5" multiple>
            <option value="足球">足球</option>
            <option value="音乐">音乐</option>
        </select>
        <button @click="getData">按钮</button>
    </div>

    <script> let app = new Vue({ //el指定id为app的元素 el: "#app", //template替换的是id为app的元素的全部内容 data: { v1:'aaa', v2:'bbbb', v3:'女', v4:true, v5:['足球','音乐'] }, methods:{ getData(){ console.log(this.v3,this.v5); } } }) </script>
</body>

</html>

效果以下
image.png数组

computed与watch

computed

在实际的应用中,咱们会有一些原始数据,同时在应用中又会有一些数据是根据某些原始数据派生出来的一种状况,vue定义一个专门用来处理这种派生的数据的选项, computed缓存

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <label ><input type="radio" v-model="gender" value="">全部</label>
        <label ><input type="radio" v-model="gender" value=""></label>
        <label ><input type="radio" v-model="gender" value=""></label>
        <hr>
        <ul>
            <li v-for="user of showUsers">
                {{user.username}}
            </li>
            
        </ul>
    </div>

    <script> let app = new Vue({ //el指定id为app的元素 el: "#app", //template替换的是id为app的元素的全部内容 data: { gender:"", users:[ {id:1,username:"kay",gender:"男"}, {id:2,username:"rrg",gender:"女"}, {id:3,username:"mmd",gender:"男"} ] }, computed:{ //计算属性,这里的函数并非给咱们直接调用的,而是做为属性的get,set熟属性存在 showUsers(){ return this.gender===''?[...this.users]:this.users.filter(user=>user.gender===this.gender); } } }) </script>
</body>

</html>

效果以下:
网络

在这里插入图片描述
在这里插入图片描述

  • 计算属性相似getter和setter ,当访问某个计算属性的时候,就会调用computed中有的函数,函数的返回值将做为该计算属性的值。
  • 计算属性的值依赖计算函数中依赖的其余响应式数据
  • 计算属性的值能够缓存,若是依赖的其余相应数据没有发生变化,但能够屡次访问该计算属性,的到结果是最近一次变化的产生的值(相对于调用方法的到结果在某些时候性能要好一些)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <button @click="getNow">按钮1</button>
        {{now1}}
    </div>

    <script> let app = new Vue({ //el指定id为app的元素 el: "#app", //template替换的是id为app的元素的全部内容 data: { now1:Date.now() }, computed:{ //计算属性,这里的函数并非给咱们直接调用的,而是做为属性的get,set熟属性添加。 //computed 计算 所依赖的属性值无变化,有时候会缓存。  getNow(){ this.now1=Date.now(); } } }) </script>
</body>

</html>
  • 有时候,这种派生数据既有get需求,也有set需求

案例:全选

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <label ><input type="radio" v-model="gender" value="">全部</label>
        <label ><input type="radio" v-model="gender" value=""></label>
        <label ><input type="radio" v-model="gender" value=""></label>
        <hr>
        <ul>
            <li v-for="user of showUsers">
                 <input type="checkbox" name="" id="" v-model="user.checked">
                {{user.username}}
               
            </li>
            
        </ul>
        <label for="">全选<input type="checkbox" v-model="checkAll"></label>
    </div>

    <script> let app = new Vue({ //el指定id为app的元素 el: "#app", //template替换的是id为app的元素的全部内容 data: { gender:"", users:[ {id:1,username:"kay",gender:"男",checked:false}, {id:2,username:"rrg",gender:"女",checked:false}, {id:3,username:"mmd",gender:"男",checked:false} ] }, computed:{ //计算属性,这里的函数并非给咱们直接调用的,而是做为属性的get,set熟属性添加。 showUsers(){ return this.gender===''?[...this.users]:this.users.filter(user=>user.gender===this.gender); }, checkAll:{ get(){ console.log('get'); return this.users.every(user=>user.checked); }, set(newValue){ console.log(newValue); this.users=this.users.map(user=>{ //返回一个新的对象 return { ...user, checked:newValue } }) } } } }) </script>
</body>

</html>

效果以下

在这里插入图片描述

watch

当派生的数据是经过异步的方式除了的时候,须要用到watch。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>根据关键词进行筛选项目 异步</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
       <input type="text" v-model="keyWord">
        <hr>
        <ul>
            <li v-for="user of showUsers">
                 
                {{user.username}}
               
            </li>
            
        </ul>
        
    </div>

    <script> let app = new Vue({ //el指定id为app的元素 el: "#app", //template替换的是id为app的元素的全部内容 data: { keyWord:"", users:[ {id:1,username:"kay",gender:"男",checked:false}, {id:2,username:"rrg",gender:"女",checked:false}, {id:3,username:"mmd",gender:"男",checked:false} ], showUsers:[] }, watch:{ keyWord(newVal,oldVal){ //模拟网络请求 setTimeout(_=>{ this.showUsers=this.users.filter(user=>user.username.includes(newVal)); },1000); } } }) </script>
</body>

</html>

效果以下
在这里插入图片描述

在这里插入图片描述

  • 多层监听 能够使用字符串 + 点语法 ()
watch:{
  //监听 a下面的子元素b 下面的子元素的c 
 
  
	'a.b.c':function(){
  	//...
  }
}
  • 深度监听 watch只能对当前指定的值进行一层监听,若是须要对对象进行深度监听
watch:{
  //对对象a 进行深度监听
	a:{
  	handler(){
    	console.log('a deep');
    },
    deep:true;
  }

}

组件

组件的注册

在vue中,咱们经过new Vue来建立一个组件,不过一般它是做为整个应用的顶层根组件存在的,咱们还能够经过另外的方式来注册一个更为通用的组件。

Vue.component()

Vue.component('组件名称',{组件选项})

  • 组件名称遵循自定义足迹姓名规范: 全小写。连字符
  • 组件选项与new Vue 选项配置基本一致(也有一些细节的不一样)

全局组件与局部组件

经过Vue.component注册的组件,咱们称为全局组件,由于我能够在任意范围内使用,咱们还能够定义局部组件。

new vue({
...,
  components:{
		'组件名称':{组件选项}
}
})

在一个组件内部经过components选项注册的组件是局部组件,只能在当前components选项所在的组件内部使用。 注意:局部注册的组件只能在当前注册组件中使用,不能在他的子组件中使用。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 使用自定义组件 -->
        <kay-compontent-1></kay-compontent-1>
         <kay-compontent-2></kay-compontent-2>
         <!-- kay-compontent-4 会报错,由于不在kay-compontent-2 组件中使用-->
         <kay-compontent-4></kay-compontent-4>

    </div>

    <script> //注册自定义组件(全局组件) Vue.component('kay-compontent-1',{ template:` <div>kay-compontent-1</div> ` }) Vue.component('kay-compontent-2',{ template:` <div>kay-compontent-2</div> `, //局部组件 ,只能在kay-compontent-2中使用 components:{ 'kay-compontent-4':{ template:` <div>kay-compontent-4</div> ` } } }) //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components:{ 'kay-compontent-3':{ template:` <div>kay-compontent-3</div> ` } }, data: { } }) </script>
</body>

</html>

报错下面以下
image.png

data

在非new Vue的组件中,data必须为函数,函数返回值必须是一个对象,做为组件的最终data

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <h1>{{val}}</h1>
        <!-- 使用自定义组件 -->
        <kay-compontent-1></kay-compontent-1>
         <kay-compontent-2></kay-compontent-2>
         

    </div>

    <script> //注册自定义组件(全局组件) Vue.component('kay-compontent-1',{ //data数据必须定义成函数 在全局组件中,return的值就是这个组件能够用的data数据 data(){ return { exp1: 'kay-1', } }, template:` <div>{{exp1}}</div> ` }) Vue.component('kay-compontent-2',{ template:` <div>kay-compontent-2</div> `, //局部组件 ,只能在kay-compontent-2中使用 components:{ 'kay-compontent-4':{ template:` <div>kay-compontent-4</div> ` } } }) //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components:{ 'kay-compontent-3':{ template:` <div>kay-compontent-3</div> ` } }, data: { val:'kay', } }) </script>
</body>

</html>

效果图以下
image.png

props

组件中内部私有数据存储中组件data中,经过外部传入的数据,则经过props选项接收。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 使用自定义组件 -->
        <kay-circle :r="n1"></kay-circle>
        <hr>
        <kay-circle :r="n2"></kay-circle>
         
    </div>

    <script> //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components:{ 'kay-circle':{ // 从外部的参数r props:['r'], data(){ //能够使用this.r 打印变量r console.log(this.r); return {pi:3.14} }, template:`<div>r:{{r}}->{{pi*r*r}}</div>` } }, //组件内部的数据 放在data中 data: { n1:10, n2:100 } }) </script>
</body>

</html>

效果以下:
image.png
注意点:

  • 若是传入达props值为一个表达式,则必须使用v-bind 若是不绑定,则是普通字符串
  • 组件中的data和props数据均可以经过组件实例进行直接访问
  • data中的key与props中的key不能冲突。(变量名不冲突)

组件的通讯

注意:不要修改props传入的数据 。父组件经过props传入数据到子组件内部,可是子组件内部不要修改外部传入的props,vue提供了一种事件机制通知父级更新,父级中使用子组件的时候监听对应的事件绑定对应的除了函数便可。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件通讯</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <p>父组件:{{quantity}}</p>
        <kay-child :quantity="initQuantity" @increment="appIncrement"></kay-child>
        <kay-child :quantity="initQuantity" @increment="appIncrement"></kay-child>
         
    </div>

    <script> //定义一个对象 子组件所使用 const child={ //外部传入的变量 props:['quantity'], data(){ return { n:this.quantity } }, template:` <div> <p>子组件:{{n}}</p> <button @click="increment">按钮</button> </div> `, methods:{ //此时 increment(){ this.n++; //往父级组件传播事件和参数 this.$emit('increment',this.n); } } }; //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components:{ 'kay-child':child }, //组件内部的数据 放在data中 data: { quantity:0, initQuantity:0 }, methods:{ appIncrement(v){ //v是子组件的传递的参数 console.log(v); this.quantity++; } } }) </script>
</body>

</html>

image.png

$emit()

vue 为每一个组件对象提供了一个内置方法$emit, 它等同于自定义事件中的new Event,trigger等。

this.$emit('自定义事件名称',事件数据)

  • 事件数据就是中触发事件的同时携带传递的数据—event
  • 父级在使用该组件的过程当中,能够经过@事件名称 来注册绑定事件函数
  • 事件函数的第一个参数就是事件数据。

组件双绑的实现

虽然并不推荐在组件内部修改 props ,可是,有的时候确实但愿组件内部状态变化的时候改变 props ,咱们能够经过子组件触发事件,父级监听事件来达到这个目的,不过过程会比较繁琐,vue 提供了一些操做来简化这个过程

v-model

v-model 是vue提供达一个用于实现数据双向绑定的指令,用来简化props到data,data到props的操做流程。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件双绑</title>
    <style> .kay-radio { width: 20px; height: 20px; background-color: #cccccc; } .kay-radio.checked { background-color: #92beee; } .plane { border: 1px solid #000000; width: 300px; } .plane .header { width: 100%; height: 30px; background: #cccccc; } .plane .content { height: 100px; width: 100%; display: none; } .plane.expanded .content { display: block; } </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
       <kay-radio v-model="val"></kay-radio>
       <br><br><br>
        <kay-plane :expanded="val"></kay-plane>
    </div>

    <script> //定义一个对象 子组件所使用 const kayRadio= { model:{ //指定v-model绑定的prop属性 prop:'checked', //指定内部触发的南哥事件会修改指定的prop的值。 event:'check' }, //外部传入的变量 props: ['checked'], data() { return { status:this.checked } }, template: ` <div class="kay-radio" :class="{'checked':status}" @click="changeStatus"> </div> `, methods: { //此时 changeStatus(){ //取反 this.status=!this.status; //传播事件到父组件 this.$emit('check',this.status); } } }; //子组件2 kay-plane 面板组件 const kayPlane={ //外部传递数据 expanded props:['expanded'], template:` <div class="plane" :class="{'expanded': expanded}"> <div class="header"></div> <div class="content"></div> </div> `, } //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components: { 'kay-radio': kayRadio, 'kay-plane':kayPlane }, //组件内部的数据 放在data中 data: { val:true, }, methods: { } }) </script>
</body>

</html>

效果以下

image.png

  • model 选项
    • prop指定要绑定的属性,默认是value
    • event 指定要绑定触发的事件,默认是input事件

.sync (处理多个prop外部绑定数据)

经过v-model 来进行双向绑定,会给状态维护带来必定的问题,由于修改比较隐蔽,同时只能处理一个prop的绑定,咱们还能够经过另一种方式来达到这个目的。

update:[prop]

这里事件名称要使用update加上prop名称的格式

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件双绑</title>
    <style> .kay-radio { width: 50px; height: 50px; border: 5px solid #000000; background-color: #ffffff; } .kay-radio.checked { border-color: green; } .kay-radio.disabled { background-color: #cccccc; } </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
      <p>val1:{{val1}}</p>
      <p>val2:{{val2}}</p>
      <hr>
      <kay-radio :checked.sync="val1" :disabled.sync="val2"></kay-radio>
    </div>

    <script> //定义一个对象 子组件所使用 const kayRadio= { //外部传入的变量 checked disabled props: ['checked','disabled'], data() { return { status:this.checked, dis:this.disabled } }, template: ` <div class="kay-radio" :class="{'checked':status,'disabled':dis}" @click="changeDis" @mouseover="setChecked" @mouseout="removeChecked"> </div> `, methods: { setChecked(){ this.status=true; this.$emit('update:checked',this.status); }, removeChecked(){ this.status=false; this.$emit('update:checked',this.status); }, //disabled changeDis(){ this.dis=!this.dis; this.$emit('update:disabled',this.dis); } } }; //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components: { 'kay-radio': kayRadio, }, //组件内部的数据 放在data中 data: { val1:false, val2:false, }, methods: { } }) </script>
</body>

</html>

效果以下

image.png

插槽

默认状况下,组件模版解析后会替换整个组件内容,若是咱们想在组件引用被包含的内容,能够经过vue提供的内置组件slot来获取。

具名插槽

使用内置组件template与v-slot指令进行配置,用来命名插槽,在组件模版中,经过 <slot name="插槽名字"> 来使用。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件双绑</title>
    <style> .dialog { position: fixed; left: 50%; top: 30%; transform: translateX(-50%) translateY(-50%) ; border-radius: 2px; box-shadow: 0 1px 3px rgba(0,0,0,.3); box-sizing: border-box; background: #fff; width: 30%; } .dialog_header { padding: 20px 20px 0; text-align: left; } .dialog_title { font-size: 16px; font-weight: 700; color: #1f2d3d; } .dialog_content { padding: 30px 20px; color: #48576a; font-size: 14px; text-align: left; } .dialog_close_btn { position: absolute; right: 10px; top: 5px; } .dialog_close_btn:before { content: 'x'; color: #999; font-size: 20px; cursor: pointer; } </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <kay-dialog>
            <!-- -->
            <template v-slot:title>
                <h1>这是标题</h1>
            </template>
            <!-- 默认写default -->
            <template v-slot:default>
                <p>这是内容</p>
            </template>
        </kay-dialog>
    </div>

    <script> //定义一个对象 子组件所使用 const Dialog={ props:['title'], template:` <div class="dialog"> <i class="dialog_close_btn"></i> <div class="dialog_header"> <slot name="title"></slot> </div> <div class="dialog_content"> <slot></slot> </div> </div> `, }; //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components: { 'kay-dialog': Dialog, }, //组件内部的数据 放在data中 }) </script>
</body>

</html>

效果以下
image.png

做用域插槽

组件内部与组件包含的内容属于不一样的做用域(被包含的内容是组件父级下的做用域)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件双绑</title>
    <style> .dialog { position: fixed; left: 50%; top: 30%; transform: translateX(-50%) translateY(-50%); border-radius: 2px; box-shadow: 0 1px 3px rgba(0, 0, 0, .3); box-sizing: border-box; background: #fff; width: 30%; } .dialog_header { padding: 20px 20px 0; text-align: left; } .dialog_title { font-size: 16px; font-weight: 700; color: #1f2d3d; } .dialog_content { padding: 30px 20px; color: #48576a; font-size: 14px; text-align: left; } .dialog_close_btn { position: absolute; right: 10px; top: 5px; } .dialog_close_btn:before { content: 'x'; color: #999; font-size: 20px; cursor: pointer; } </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <kay-dialog>
            <!-- -->
            <template v-slot:title>
                <h1>用户列表-{{title}}</h1>
            </template>
            <!-- 默认写default -->
            <template v-slot:default="data">
                <p>用户的姓名:{{data.user.username}}</p>
            </template>
        </kay-dialog>
    </div>

    <script> //定义一个对象 子组件所使用 const Dialog = { props: ['title'], data(){ return { users: [ {id: 1, username: '1', gender: '男',checked:false}, {id: 2, username: '2', gender: '男',checked:false}, {id: 3, username: '3', gender: '男',checked:false}, {id: 4, username: '4', gender: '男',checked:false}, {id: 5, username: '5', gender: '女',checked:false}, {id: 6, username: '6', gender: '女',checked:false} ] } }, template: ` <div class="dialog"> <i class="dialog_close_btn"></i> <div class="dialog_header"> <slot name="title"></slot> </div> <div class="dialog_content"> <slot v-for="user of users" :user="user"></slot> </div> </div> `, }; //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components: { 'kay-dialog': Dialog, }, //组件内部的数据 放在data中 data:{ title:'kay' } }) </script>
</body>

</html>

效果以下

在这里插入图片描述

props验证

组件的props就是组件的参数,为了确保传入的数据在可控的合理范围内容,咱们须要对传入的props的值类型进行必要的验证。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>props验证</title>
    <style> .dialog { position: fixed; left: 50%; top: 30%; transform: translateX(-50%) translateY(-50%); border-radius: 2px; box-shadow: 0 1px 3px rgba(0, 0, 0, .3); box-sizing: border-box; background: #fff; width: 30%; } .dialog_header { padding: 20px 20px 0; text-align: left; } .dialog_title { font-size: 16px; font-weight: 700; color: #1f2d3d; } .dialog_content { padding: 30px 20px; color: #48576a; font-size: 14px; text-align: left; } .dialog_close_btn { position: absolute; right: 10px; top: 5px; } .dialog_close_btn:before { content: 'x'; color: #999; font-size: 20px; cursor: pointer; } </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 传入的n为字符串abc 会报错 -->
        <kay-component :n="abc"></kay-component> 
    </div>

    <script> //子组件 const kayComponent={ props:{ // 要求n是number n:Number }, template:`<div>{{n*10}}</div>` } //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components: { 'kay-component':kayComponent }, //组件内部的数据 放在data中 data: { title: 'kay' } }) </script>
</body>

</html>

效果以下:
image.png
其余的验证以下

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

非prop特性

一个非prop特性是指传向一个组件,可是该组件并无相应prop定义的特性,这些props会被自动天添加到组件的根元素上。

替换/合并已有的特性

默认状况下,非 prop 特性的属性会覆盖组件根元素上同名的内容,可是针对 style 和 class 有特殊的处理,它们会合并(同名样式仍是会覆盖)

禁用特性继承

若是你不但愿组件的根元素继承特性,你能够在组件的选项中设置 inheritAttrs: false,咱们能够经过组件的 this.$attrs 来获取这些属性

注意 inheritAttrs: false 选项不会影响 styleclass 的绑定

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>doc</title>
    <style> </style>
    <!-- 经过script的方式引入vue -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 传入的n为字符串abc 会报错 -->
        <kay-component style="background:red" :n="1" id="kay1" val="test"></kay-component>
    </div>

    <script> //子组件 const kayComponent = { // 禁止继承 inheritAttrs:false, // id style 没有定义在props上,可是会自动会添加到组件的根元素。 data(){ console.log(this.$attrs); return{}; }, props:['n'], template: `<div style="height:200px;" id="kay2">{{n}}</div>` } //根组件 let app = new Vue({ //el指定id为app的元素 el: "#app", //注册自定义组件(局部组件) components: { 'kay-component': kayComponent, }, //组件内部的数据 放在data中 data: { title: 'kay' } }) </script>
</body>

</html>

效果以下
image.png