美文网首页Vue.js开发技巧Vue技术前端开发那些事儿
【vue】8.0 指令、过滤器、传送门teleport、ren

【vue】8.0 指令、过滤器、传送门teleport、ren

作者: bobokaka | 来源:发表于2021-06-01 09:40 被阅读0次
    自定义指令directives

    对底层dom进行操作的封装,目前封装一个自定义指令,作用是:谁用这个指令就会变成对应的颜色。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
        <div id="box">
          <!-- v-if="isShow" -->
          <div v-hello="'red'">11111111</div>
    
          <div v-hello="'yellow'">22222222</div>
    
          <div v-hello="color">333333333333333</div>
        </div>  
    
        <script type="text/javascript">
          
        // Vue.compoennt("aa",{}) 
          // directive指令 - dom 操作
          // 
          Vue.directive("hello",{
            //指令的生命周期-第一次插入节点调用
              inserted(el,binding,vnode){
                // vnode ,vdom, virtual node,  虚拟节点 虚拟dom
                console.log("此时dom节点创建",vnode)
                el.style.backgroundColor = binding.value;
              },
    
              update(el,binding){
                console.log("此时绑定的状态改变时会执行")
                el.style.backgroundColor = binding.value;
              }
          })
    
          var vm = new Vue({
            el:"#box",
            data:{
              title:"1111111111111111",
              color:'blue'
            },
            // directives
          })
           
        </script>
    </body>
    </html>
    

    bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
    componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
    unbind:卸载的时候会执行。

    指令钩子函数会被传入以下参数:
    inserted(el,bind,newVnode,oldVnode)

    • el:指令所绑定的元素,可以用来直接操作 DOM。
    • binding:一个对象,包含以下 property:
      • name:指令名,不包括 v- 前缀。
      • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
      • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
      • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
      • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
      • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
    • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
    • oldVnode:上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。
    指令函数的简写
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
        <div id="box">
          <!-- v-if="isShow" -->
          <div v-hello="'red'">11111111</div>
    
          <div v-hello="'yellow'">22222222</div>
    
          <div v-hello="color">333333333333333</div>
        </div>  
    
        <script type="text/javascript">
          
        // Vue.compoennt("aa",{}) 
          // directive指令 - dom 操作
          // 
          Vue.directive("hello",function(el,binding,vnode){
            el.style.backgroundColor = binding.value
          })
    
          var vm = new Vue({
            el:"#box",
            data:{
              title:"1111111111111111",
              color:'red'
            },
            // directives
          })
           
        </script>
    </body>
    </html>
    

    再举一个例子:

    <script>
      // 自定义指令 directive
    
      const app = Vue.createApp({
        data() {
          return {
            distance: 110
          }
        },
        template: `
          <div>
            <div v-pos:right="distance" class="header">
              <input />
            </div>
          </div>
        `
      });
    
      app.directive('pos', (el, binding) => {
        el.style[binding.arg] = (binding.value + 'px');
      })
    
      const vm = app.mount('#root');
    </script>
    

    也可以如下编写:


    image.png
    指令轮播
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    
    <link rel="stylesheet" href="lib/swiper/css/swiper.css">
    <script src="lib/swiper/js/swiper.js"></script>
    <script type="text/javascript" src="lib/vue.js"></script>
    
    <style>
      .swiper-container {
          width: 600px;
          height: 300px;
      }  
    </style>
    </head>
    <body>
      <div id="box">
        <div class="swiper-container">
            <div class="swiper-wrapper">
                <div class="swiper-slide" v-for="data,index in list" v-swipe="index">
                  {{data}}
                </div>
            </div>
            <!-- 如果需要分页器 -->
            <div class="swiper-pagination"></div>
            
            <!-- 如果需要导航按钮 -->
            <!-- <div class="swiper-button-prev"></div> -->
            <!-- <div class="swiper-button-next"></div> -->
            
            <!-- 如果需要滚动条 -->
            <!-- <div class="swiper-scrollbar"></div> -->
        </div>
    
      </div>
    
        <script type="text/javascript">
        
          Vue.directive("swipe",{
            inserted(el,binding,vnode){
              console.log(binding.value);
    
              if(binding.value === vnode.context.list.length-1){
                var mySwiper = new Swiper ('.swiper-container', {
                    // direction: 'vertical', // 垂直切换选项
                      // 如果需要分页器
                    pagination: {
                      el: '.swiper-pagination',
                    }
                })
              }
            }
          })
    
    
          new Vue({
            el:"#box",
            data:{
              list:[]
            },
    
            mounted(){
    
              setTimeout(() => {
                this.list = ["111","2222","3333"];
    
                console.log("节点创建完了????","没有,异步渲染")
                
    
    
              }, 2000)
            },
    
            updated(){
              // console.log("节点创建完了????","更新阶段渲染")
              // var mySwiper = new Swiper ('.swiper-container', {
              //     // direction: 'vertical', // 垂直切换选项
              //       // 如果需要分页器
              //     pagination: {
              //       el: '.swiper-pagination',
              //     }
              // })
            }
          })
     </script>
    </body>
    </html>
    
    轮播-nextTick

    直接解决(避免)了swiper初始化过早的问题。并且防止了多次反复执行指令勾子函数更新的问题。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    
    <link rel="stylesheet" href="lib/swiper/css/swiper.css">
    <script src="lib/swiper/js/swiper.js"></script>
    <script type="text/javascript" src="lib/vue.js"></script>
    
    <style>
      .swiper-container {
          width: 600px;
          height: 300px;
      }  
    </style>
    </head>
    <body>
      <div id="box">
        <div class="swiper-container">
            <div class="swiper-wrapper">
                <div class="swiper-slide" v-for="data,index in list">
                  {{data}}
                </div>
            </div>
            <!-- 如果需要分页器 -->
            <div class="swiper-pagination"></div>
    
        </div>
    
      </div>
    
        <script type="text/javascript">
          
    
    
    
          new Vue({
            el:"#box",
            data:{
              list:[]
            },
    
            mounted(){
    
              setTimeout(() => {
                this.list = ["111","2222","3333"];
    
                // 黑魔法
                this.$nextTick(()=>{
                  console.log("我待会才会执行")
                  
                  var mySwiper = new Swiper ('.swiper-container', {
                      // direction: 'vertical', // 垂直切换选项
                        // 如果需要分页器
                      pagination: {
                        el: '.swiper-pagination',
                      }
                  })
                })
                console.log("节点创建完了????","没有,异步渲染")
              }, 2000)
            },
    
            updated(){
              console.log("updated");
            }
          })
         
        </script>
    </body>
    </html>
    
    过滤器

    Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。

    首选准备一个加载数据json文件。

    {
        "coming": [],
        "movieIds": [248172, 1218727, 346629, 1228776, 1239544, 672279, 1211727, 1230152, 1211412, 672379, 1205909, 1234116,
            883196, 1243904, 1207260, 1263355, 1239281, 476263, 1212492, 1217701, 1237437, 1162868, 346765, 1229702,
            1239844, 337896, 1216383, 507792, 1167831, 1206939, 248123, 245881, 1206415
        ],
        "stid": "576591972453269000",
        "stids": [{
            "movieId": 248172,
            "stid": "576591972453269000_a248172_c0"
        }, {
            "movieId": 1218727,
            "stid": "576591972453269000_a1218727_c1"
        }, {
            "movieId": 346629,
            "stid": "576591972453269000_a346629_c2"
        }, {
            "movieId": 1228776,
            "stid": "576591972453269000_a1228776_c3"
        }, {
            "movieId": 1239544,
            "stid": "576591972453269000_a1239544_c4"
        }, {
            "movieId": 672279,
            "stid": "576591972453269000_a672279_c5"
        }, {
            "movieId": 1211727,
            "stid": "576591972453269000_a1211727_c6"
        }, {
            "movieId": 1230152,
            "stid": "576591972453269000_a1230152_c7"
        }, {
            "movieId": 1211412,
            "stid": "576591972453269000_a1211412_c8"
        }, {
            "movieId": 672379,
            "stid": "576591972453269000_a672379_c9"
        }, {
            "movieId": 1205909,
            "stid": "576591972453269000_a1205909_c10"
        }, {
            "movieId": 1234116,
            "stid": "576591972453269000_a1234116_c11"
        }],
        "total": 33,
        "movieList": [{
            "id": 248172,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "v3d imax",
            "nm": "复仇者联盟4:终局之战",
            "preShow": false,
            "sc": 9.1,
            "globalReleased": true,
            "wish": 1849927,
            "star":"王麻子",
            "rt": "2019-04-24",
            "showInfo": "今天107家影院放映3177场",
            "showst": 3,
            "wishst": 0
        }, {
            "id": 1218727,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "",
            "nm": "何以为家",
            "preShow": false,
            "sc": 0,
            "globalReleased": false,
            "wish": 94818,
            "star":"王麻子",
            "rt": "2019-04-29",
            "showInfo": "2019-04-29 下周一上映",
            "showst": 4,
            "wishst": 0
        }, {
            "id": 346629,
            "haspromotionTag": false,
            "img":"http://w.h/xxxxxx",
            "version": "v3d imax",
            "nm": "大侦探皮卡丘",
            "preShow": false,
            "sc": 0,
            "globalReleased": false,
            "wish": 181370,
            "star":"王麻子",
            "rt": "2019-05-10",
            "showInfo": "2019-05-10上映",
            "showst": 4,
            "wishst": 0
        }, {
            "id": 1228776,
            "haspromotionTag": false,
            "img":"http://w.h/xxxxxx",
            "version": "",
            "nm": "下一任:前任",
            "preShow": false,
            "sc": 0,
            "globalReleased": false,
            "wish": 284385,
            "star":"王麻子",
            "rt": "2019-05-01",
            "showInfo": "2019-05-01 下周三上映",
            "showst": 4,
            "wishst": 0
        }, {
            "id": 1239544,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "",
            "nm": "调音师",
            "preShow": false,
            "sc": 9.1,
            "globalReleased": true,
            "wish": 14608,
            "star":"王麻子",
            "rt": "2019-04-03",
            "showInfo": "今天60家影院放映155场",
            "showst": 3,
            "wishst": 0
        }, {
            "id": 672279,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "",
            "nm": "雪暴",
            "preShow": false,
            "sc": 0,
            "globalReleased": false,
            "wish": 24301,
            "star":"王麻子",
            "rt": "2019-04-30",
            "showInfo": "2019-04-30 下周二上映",
            "showst": 4,
            "wishst": 0
        }, {
            "id": 1211727,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "",
            "nm": "反贪风暴4",
            "preShow": false,
            "sc": 9.1,
            "globalReleased": true,
            "wish": 161080,
            "star":"王麻子",
            "rt": "2019-04-04",
            "showInfo": "今天55家影院放映129场",
            "showst": 3,
            "wishst": 0
        }, {
            "id": 1230152,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "",
            "nm": "撞死了一只羊",
            "preShow": false,
            "sc": 8,
            "globalReleased": true,
            "wish": 8422,
            "star":"王麻子",
            "rt": "2019-04-26",
            "showInfo": "今天38家影院放映81场",
            "showst": 3,
            "wishst": 0
        }, {
            "id": 1211412,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "v3d",
            "nm": "神奇乐园历险记",
            "preShow": false,
            "sc": 8.8,
            "globalReleased": true,
            "wish": 4779,
            "star":"王麻子",
            "rt": "2019-04-19",
            "showInfo": "今天39家影院放映63场",
            "showst": 3,
            "wishst": 0
        }, {
            "id": 672379,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "v3d",
            "nm": "悟空奇遇记",
            "preShow": false,
            "sc": 0,
            "globalReleased": false,
            "wish": 11472,
            "star":"王麻子",
            "rt": "2019-05-01",
            "showInfo": "2019-05-01 下周三上映",
            "showst": 4,
            "wishst": 0
        }, {
            "id": 1205909,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "",
            "nm": "祈祷落幕时",
            "preShow": false,
            "sc": 9,
            "globalReleased": true,
            "wish": 11057,
            "star":"王麻子",
            "rt": "2019-04-12",
            "showInfo": "今天16家影院放映40场",
            "showst": 3,
            "wishst": 0
        }, {
            "id": 1234116,
            "haspromotionTag": false,
            "img":"http://128.180/xxxxxx",
            "version": "",
            "nm": "猫公主苏菲",
            "preShow": false,
            "sc": 0,
            "globalReleased": false,
            "wish": 6533,
            "star":"王麻子",
            "rt": "2019-05-01",
            "showInfo": "2019-05-01 下周三上映",
            "showst": 4,
            "wishst": 0
        }]
    }  
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    <style>
    
    </style>
    
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
    
        <!-- <h1 class="animated hinge infinite">1111111111111</h1> -->
    
        <div id="box">
           <ul>
             <li v-for="data in datalist">
                {{data.nm}}
               <!--  <img :src="handlePath(data.img)"/> -->
               <img :src="data.img | kerwinpath"/>
    
               {{ data.img | kerwinpath }}
             </li>
           </ul>
        </div>
    
        <script>
    
          //过滤器 ---- 数据格式化
          Vue.filter("kerwinpath",function(path){
            return path.replace('w.h','128.180')
          })    
    
    
          var vm = new Vue({
            el:"#box",
            data:{
              isShow:true,
              datalist:[]
            },
    
            mounted(){
              axios.get("test.json").then(res=>{
                console.log(res.data);
                this.datalist = res.data.movieList
              })
            },
    
            methods:{
              handlePath(path){
                console.log(path);
                return path.replace('w.h','128.180');
              }
            }
          })
        </script>
    </body>
    </html>
    

    过滤器其实就是一种函数写法,把第一个参数写到|符号前面,如果还有其他参数,就写到函数名的后面。只不过这个函数方法必须写到filers中。

    过滤器函数总接收表达式的值 (之前的操作链的结果) 作为第一个参数。在上述例子中,capitalize 过滤器函数将会收到 message 的值作为第一个参数。

    过滤器可以串联:

    {{ message | filterA | filterB }}
    在这个例子中,filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递到 filterB 中。
    相当于:
    function filterB (function filterA (message ))
    过滤器是 JavaScript 函数,因此可以接收参数:

    {{ message | filterA('arg1', arg2) }}
    这里,filterA 被定义为接收三个参数的过滤器函数。其中 message 的值作为第一个参数,普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。
    相当于:
    function filterA(message ,'arg1',arg2)

    传送门Teleport

    如下例子,比如想点击按钮给页面增加一个蒙层。

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>lesson 30</title>
            <style>
                .area {
                    position: absolute;
                    left: 50%;
                    top: 50%;
                    transform: translate(-50%, -50%);
                    width: 200px;
                    height: 300px;
                    background: green;
                }
    
                .mask {
                    position: absolute;
                    left: 0;
                    right: 0;
                    top: 0;
                    bottom: 0;
                    background: #000;
                    opacity: 0.5;
                    color: #fff;
                    font-size: 100px;
                }
            </style>
            <script src="https://unpkg.com/vue@next"></script>
        </head>
        <body>
            <div id="root"></div>
        </body>
        <script>
            // teleport 传送门
            const app = Vue.createApp({
                data() {
                    return {
                        show: false,
                    }
                },
                methods: {
                    handleBtnClick() {
                        this.show = !this.show;
                    }
                },
                template: `
          <div class="area">
            <button @click="handleBtnClick">按钮</button>
              <div class="mask" v-show="show"></div>
          </div>
        `
            });
    
            const vm = app.mount('#root');
        </script>
    </html>
    
    

    点击按钮出现如下情况:

    image.png
    因为在css样式mask中,absolute绝对定位是相对父元素的,所以遮罩和上下左右移动都不会超出area标签的范围。如果想要在组件内实现全遮罩的效果,这时候就需要用到传送门Teleport:
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>lesson 30</title>
      <style>
        .area {
          position: absolute;
          left: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
          width: 200px;
          height: 300px;
          background: green;
        }
        .mask {
          position: absolute;
          left: 0;
          right: 0;
          top: 0;
          bottom: 0;
          background: #000;
          opacity: 0.5;
          color: #fff;
          font-size: 100px;
        }
      </style>
      <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
      <div id="root"></div>
      <div id="hello"></div>
    </body>
    <script>
      // teleport 传送门
      const app = Vue.createApp({
        data() {
          return {
            show: false,
            message: 'hello'
          }
        },
        methods: {
          handleBtnClick() {
            this.show = !this.show;
          }
        },
        template: `
          <div class="area">
            <button @click="handleBtnClick">按钮</button>
            <teleport to="#hello">
              <div class="mask" v-show="show">{{message}}</div>
            </teleport>
          </div>
        `
      });
    
      const vm = app.mount('#root');
    </script>
    </html>
    
    

    效果如下:


    image.png

    render函数

    如下代码:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>lesson 31</title>
            <script src="https://unpkg.com/vue@next"></script>
        </head>
        <body>
            <div id="root"></div>
        </body>
        <script>
            // render function
            // template -> render -> h -> 虚拟DOM(JS对象)-> 真实 DOM -> 展示到页面上
            const app = Vue.createApp({
                template: `
          <my-title :level="2">
            hello dell
          </my-title>
        `
            });
    
            app.component('my-title', {
                props: ['level'],
                template: `
                <h1 v-if="level===1"><slot/></h1>
                <h2 v-if="level===2"><slot/></h2>
                <h3 v-if="level===3"><slot/></h3>
                <h4 v-if="level===4"><slot/></h4>
                `
            })
    
            const vm = app.mount('#root');
        </script>
    </html>
    
    

    如何把如上代码写得更加优雅,修改组件代码:

    render function
    template -> render -> h -> 虚拟DOM(JS对象)-> 真实 DOM -> 展示到页面上

      app.component('my-title', {
        props: ['level'],
        render() {
          //创建一个vue的h函数
          const { h } = Vue;
          //这是一个虚拟DOM。返回一个h函数的返回值,传递的第一个参数是标签名,第二个参数为标签的自定义或者自带的属性和属性值,第三个参数为具体标签内的内容。
          //这里通过`  this.$slot `获得各式各样的插槽,这里我们没有具体指向,想使用默认插槽,语法就是` this.$slots.default()`。
          //这里第三个参数可以写成一个数组,相当于往下无限地嵌套的js对象。
          return h('h' + this.level, {}, [
            this.$slots.default(),
            h('h4', {}, 'dell')
          ])
        }
      })
    

    我们在组件中写的template 都会被编译成render。

    插件

    我们都知道vue有很多第三方插件,那么插件的基本原理是什么?
    mixin可以对代码进行很好的封装,但是使用插件的功能,能进行更好的封装。
    比如定义一个myPlugin的插件:
    一定要定义一个install方法,这是插件走的一个必备逻辑。

      const myPlugin = {
        //支持2个参数:app:根实例,有这个可扩展任何想要的实例。
            //options:额外的参数会传到options中
        install(app, options) {
          })
    

    使用插件:

      // plugin 插件, 也是把通用性的功能封装起来
      const myPlugin = {
        //支持2个参数:app,跟实例,有这个可扩展任何想要的实例。
            //options:额外的参数会传到options中
        install(app, options) {
          })
          })
        }
      }
    
      const app = Vue.createApp({
        template: `
          <my-title />
        `
      });
    
      app.component('my-title', {
      
        template: `<div>hello world</div>`
      })
    
      app.use(myPlugin, { name: 'dell'});
    

    既然得到app的实例,那么可以进行很多操作,比如设置全局变量:

      // plugin 插件, 也是把通用性的功能封装起来
      const myPlugin = {
        //支持2个参数:app,跟实例,有这个可扩展任何想要的实例。
            //options:额外的参数会传到options中
        install(app, options) {
           app.provide('name', 'Dell Lee');
          })
          })
        }
      }
    
      const app = Vue.createApp({
        template: `
          <my-title />
        `
    
      });
    
      app.component('my-title', {
          inject: ['name'],
        template: `<div>{{name}}</div>`
      })
    
      app.use(myPlugin, { name: 'dell'});
    

    也可以扩展自定义指令:

      // plugin 插件, 也是把通用性的功能封装起来
      const myPlugin = {
        //支持2个参数:app,跟实例,有这个可扩展任何想要的实例。
            //options:额外的参数会传到options中
        install(app, options) {
           app.provide('name', 'Dell Lee');
          })
          app.directive('focus', {
            mounted(el) {
              el.focus();
            }
          })
          })
        }
      }
    
      const app = Vue.createApp({
        template: `
          <my-title />
        `
    
      });
    
      app.component('my-title', {
          inject: ['name'],
        template: `<div>{{name}}<input v-focus /></div>`
      })
    
      app.use(myPlugin, { name: 'dell'});
    

    也可以扩展其他内容:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>lesson 32</title>
      <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
      <div id="root"></div>
    </body>
    <script>
      // plugin 插件, 也是把通用性的功能封装起来
      const myPlugin = {
        //支持2个参数:app,跟实例,有这个可扩展任何想要的实例。
            //options:额外的参数会传到options中
        install(app, options) {
          app.provide('name', 'Dell Lee');
          app.directive('focus', {
            mounted(el) {
              el.focus();
            }
          })
          app.mixin({
            mounted(){
              console.log('mixin')
            }
          })
          app.config.globalProperties.$sayHello = 'hello world';
        }
      }
    
      const app = Vue.createApp({
        template: `
          <my-title />
        `
      });
    
      app.component('my-title', {
        inject: ['name'],
        mounted() {
          console.log(this.$sayHello);
        },
        template: `<div>{{name}}<input v-focus /></div>`
      })
    
      app.use(myPlugin, { name: 'dell'});
    
      const vm = app.mount('#root');
    </script>
    </html>
    

    对数据做校验的插件编写

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>lesson 33</title>
      <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
      <div id="root"></div>
    </body>
    <script>
      // 对数据做校验的插件
      const app = Vue.createApp({
        data() {
          return { name: 'dell', age: 23}
        },
        rules: {
          age: {
            validate: age => age > 25,
            message: 'too young, to simple'
          },
          name: {
            validate: name => name.length >= 4,
            message: 'name too short'
          }
        },
        template: `
          <div>name:{{name}}, age:{{age}}</div>
        `
      });
    
      const validatorPlugin = (app, options) => {
        app.mixin({
          created() {
            for(let key in this.$options.rules) {
              const item = this.$options.rules[key];
              this.$watch(key, (value) => {
                const result = item.validate(value);
                if(!result) console.log(item.message);
              })
            }
          }
        })
      }
    
      app.use(validatorPlugin);
      const vm = app.mount('#root');
    </script>
    </html>
    

    相关文章

      网友评论

        本文标题:【vue】8.0 指令、过滤器、传送门teleport、ren

        本文链接:https://www.haomeiwen.com/subject/fxxesltx.html