vue的自定义
自定义组件
组件是可以被复用的页面的零件,其实就是一个插件,只是在vue里叫组件
先看看别人的组件
vant
element
Mint
iView
去试试上面的组件,都是有脚手架版和直接引入使用的版本的
脚手架的使用需要先去main.js入口文件引入,还有css也是,查看官方文档都有的
这些组件让vue的开发容易得飞起,这也是为什么说是个人就能做前端,封装得太好了,以前自己写几百行几千行的功能,在组件里主要一个标签一句代码就行,如何封装一个组件,就能理解如何使用一个组件
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vant@2.2/lib/index.css">
<div id="app">
   <van-count-down :time="tt" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vant@2.2/lib/vant.min.js"></script>
<script type="text/javascript">
var app = new Vue({
  el: '#app',
  data: {
      tt: 30 * 60 * 60 * 1000
  }
})
</script>
上面有个<van-count-down>标签不是vue的内置标签,而是自定义标签,就像路由的<route-view>标签一样,这个标签就是为了在所在位置生成自定义的内容,标签上还能看到一个:time这个自定义的参数
还有就是所有组件都有的弹窗提示功能,这类功能不需要在页面写自定义标签,是怎么实现的
Dialog.alert({
  title: '标题',
  message: '弹窗内容'
}).then(() => {
  // on close
});
除了自定义组件,还有自定义组件的v-model数据双向变化,自定义指令,自定义过滤器,自定义方法,下面会直接上代码,不解释,解释不清楚
标签组件myA
<template>
    <div>
       <div>{{newNum}}</div>
       <div @click="newAdd">点击添加</div>
    </div>
</template>
<script>
export default {
    name: 'myA',
    props: ["num","add"],
    data(){
        return {
            newNum: 0
        }
    },
    watch:{
      num(){
         this.newNum = this.num
      }
    },
    mounted(){
      this.newNum = this.num
      setInterval(()=>{
         this.newNum--;
      },1000)
    },
    methods:{
      newAdd(){
         // 因为子组件不能修改来自外来的数据
         // 所以应该用this.$emit去执行外来的方法
         // 用外来的方法修改外来的数据
         this.$emit("add",this.newNum)
      }
    }
}
</script>
<style scoped>
  div{
    color: red;
  }
</style>
双向绑定数据组件myB
<template>
    <div :value="newVal" @input="Input">{{newVal}}{{aa}}</div>
</template>
<script>
export default {
    name: 'myB',
    props: ["value","aa"],
    data(){
        return {
            newVal: this.value
        }
    },
    mounted(){
        setInterval(()=>{
            this.Input()
        },1000)
    },
    methods:{
        Input(){
            this.newVal--;
            this.$emit('input',this.newVal)
        }
    }
}
</script>
<style scoped>
  div{
    color: blue;
  }
</style>
生成型组件myC
<template>
    <div @click="bb">{{value}}{{aa}}666</div>
</template>
<script>
export default {
   name:'myC'
}
</script>
<style scoped>
  div{
    color: grey;
  }
</style>
封装
import myA from 'myA.vue'
import myB from 'myB.vue'
import myC from 'myC.vue'
export default {
    // 固定写法
    install: function (Vue, options) {
        // 添加的内容写在这个函数里面
        console.log(options);
        // 注册自定义组件
        Vue.component(myA.name,myA)
        // 注册自定义组件
        Vue.component(myB.name,myB)
        // 原型方法生成组件
        Vue.prototype.$myC = function(opt){
            var cc = Vue.extend(myC)
            var component = new cc({
               data:{
                  value:opt.value,
                  aa:opt.aa
               },
               methods:{
                  bb:opt.bb
               }
            }).$mount()
            // 添加到页面上去
            document.querySelector('body').appendChild(component.$el)
        }
        // 自定义过滤器
        Vue.filter('formatTime', function (value) {
            Date.prototype.Format = function (fmt) { //author: meizz
                var o = {
                    "M+": this.getMonth() + 1, //月份
                    "d+": this.getDate(), //日
                    "h+": this.getHours(), //小时
                    "m+": this.getMinutes(), //分
                    "s+": this.getSeconds(), //秒
                    "q+": Math.floor((this.getMonth() + 3) / 3), //季度
                    "S": this.getMilliseconds() //毫秒
                };
                if (/(y+)/.test(fmt))
                    fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
                for (var k in o)
                    if (new RegExp("(" + k + ")").test(fmt))
                        fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
                return fmt;
            }
            return new Date(value).Format("yyyy-MM-dd hh:mm:ss");
        })
        // 添加原型方法
        Vue.prototype.$service = {
            //电话号码合法性检查
            telNumberCheck: function (tel) {
                var pattern = /123/;
                return pattern.test(tel)
            }
        }
        // 自定义指令
        // 第一个参数:指令名称
        // 第二个参数:配置对象,指定指令的钩子函数
        Vue.directive('directiveName', {
        // bind中只能对元素自身进行DOM操作,而无法对父级元素操作
        // 只调用一次 指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
             bind( el,binding, vnode ) {
             // 参数详解
             // el:指令所绑定的元素,可以用来直接操作 DOM 。
             // binding:一个对象,包含以下属性:
             // name:指令名,不包括 v- 前缀。
             // value:指令的绑定值,等号后面的值 。
             // oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
            // expression:字符串形式的指令表达式 等号后面的字符串 形式
            // arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
            // modifiers:指令修饰符。例如:v-directive.foo.bar中,修饰符对象为 { foo: true, bar: true }。
            // vnode:Vue 编译生成的虚拟节点。。
            // oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
            },
            // inserted这个钩子函数调用的时候,当前元素已经插入页面中了,也就是说可以获取到父级节点了
            inserted (  el,binding, vnode ) {},
            //  DOM重新渲染前
            update(el,binding, vnode,oldVnode) {},
            // DOM重新渲染后
            componentUpdated ( el,binding, vnode,oldVnode ) {},
            // 只调用一次,指令与元素解绑时调用
            unbind ( el ) {
               // 指令所在的元素在页面中消失,触发
            }
        })
    }
}
插件引入
在main.js里
import my from 'my'
Vue.use(my)
使用
<template>
  <div>
    <my-a :num="num" @add="add"/>
    <my-b v-model="value"/>
    <div my-directive="{color:'white',text:'hello!'}"></div>
    <div>{{ time | formatTime }}</div>
  </div>
</template>
<script>
    // @ is an alias to /src
    export default {
        name: 'ceshi',
        data(){
          return {
              num:111,
              value:222,
              time:123153123
          }
        },
        mounted(){
            this.$myC({
                value:"1111",
                aa:"aa",
                bb(){
                    this.$service.telNumberCheck(123456789)
                }
            })
        }
    }
</script>
组件的递归,在组件调用自己就行,但是一定要防止死循环
递归组件最常见到就是tree结构
<template>
  <div>
    {{num}}
      <my-num :num="num-1" v-if="num>0"/>
  </div>
</template>
<script>
    export default {
        // name一定要
        name: 'myNum',
        props: ["num"],
    }
</script>
// 使用
<my-num num="3"/>
// 然后会显示
3
2
1
0
组件里的props上面都是用数组去接受,如果写成对象格式,可以做数据校验,能要求必传,还能添加默认值
props:{
    title:String,
    likes: Number,
    isPublished: Boolean,
    commentIds: Array,
    author: Object,
    callback: Function,
    contactsPromise: Promise,
    items: {  // 必须提供字段
       required: true
    },
    unit: {   // 可选字段,有默认值
       default: 3
    }
}
事件修饰符native
用来注册元素的原生事件而不是组件自定义事件的
<vButton @click="clickHandler" @vclick="vClickHandler">按钮</vButton>
export default {
  methods: {
    clickHandler () {
      alert('onclick') // 此处不会执行 因为组件中未定义 `click` 事件
    },
    vClickHandler () {
      alert('onvclick') // 触发 `vclick` 自定义事件
    }
  }
}
//如果将上面模版改成如下方式,那么两个事件都会执行。
<vButton @click.native="clickHandler" @vclick="vClickHandler">按钮</vButton>
有个问题
如果组件的渲染报错说运行时什么什么的
在vue.config.js里加上下面这个配置
module.exports = {
    runtimeCompiler: true
}
补充一个图片懒加载的自定义指令
 // 引入Vue构造函数
 import Vue from 'vue'
 var lazyload = {
	 // Vue.use() 默认加载install,并且将Vue当做第一个参数传递过来
	 install(vue,payload) {
		 // 数组扩展移除元素
		 if(!Array.prototype.remove){
			 Array.prototype.remove = function(item){
				 if(!this.length) return
				 var index = this.indexOf(item);
				 if( index > -1){
					 this.splice(index,1);
					 return this
				 }
			 }
		 }
		 // 默认值图片
		 var defaultImage = payload.defaultImage || 'xxx.png';
		 var errorImage = payload.errorImage || 'xxx.png';
		 // 默认离可视区10px时加载图片
		 var distanece = payload.scrollDistance || 10;
		 // 收集未加载的图片元素和资源
		 var listenList = [];
		 // 收集已加载的图片元素和资源
		 var imageCacheList = [];
		 // 是否已经加载完成的图片
		 const isAlredyLoad = (imageSrc) => {
			 if(imageCacheList.indexOf(imageSrc) > -1){
				 return true;
			 }else{
				 return false;
			 }
		 }
		 //检测图片是否可以加载,如果可以则进行加载
		 const isCanShow = (item) =>{
			 var ele = item.ele;
			 var src = item.src;
			 //图片距离页面顶部的距离
			 var top = ele.getBoundingClientRect().top;
			 //页面可视区域的高度
			 var windowHeight = window.innerHight;
			 // top - distance 距离可视区域还有distance像素
			 if(top - distanece < window.innerHeight){
				 var image = new Image();
				 image.src = src;
				 image.onload = function() {
					 ele.src = src;
					 imageCacheList.push(src);
					 listenList.remove(item);
				 }
				 image.onerror = function() {
					 ele.src = errorImage;
					 imageCacheList.push(src);
					 listenList.remove(item);
				 }
				 return true;
			 }else{
				 return false;
			 }
		 };
		 const onListenScroll = () => {
			 window.addEventListener('scroll',function(){
				 var length = listenList.length;
				 for(let i = 0;i<length;i++ ){
					 isCanShow(listenList[i]);
				 }
			 })
		 }
		 //Vue 指令最终的方法
		 const addListener = (ele,binding) =>{
			 //绑定的图片地址
			 var imageSrc = binding.value;
			 // 防止重复加载。如果已经加载过,则无需重新加载,直接将src赋值
			 if(isAlredyLoad(imageSrc)){
				 ele.src = imageSrc;
				 return false;
			 }
			 var item = {
				 ele: ele,
				 src: imageSrc
			 }
			 //图片显示默认的图片
			 ele.src = defaultImage;
			 //再看看是否可以显示此图片
			 if(isCanShow(item)){
				 return
			 }
			 //否则将图片地址和元素均放入监听的lisenList里
			 listenList.push(item);
			 //然后开始监听页面scroll事件
			 onListenScroll();
		 }
		 Vue.directive('lazyload',{
			 inserted: addListener,
			 updated: addListener
		 })
	 }
 }
 export default lazyload;
// 使用
// 参数均为可选
Vue.use(Lazyload,{
 scrollDistance: 15, // 距离可视区还有15px时开发加载资源
 defaultImage: '', // 资源图片未加载前的默认图片(绝对路径)
 errorImage:'' // 资源图片加载失败时要加载的资源(绝对路径)
})
												
											vue的自定义的更多相关文章
- 最简单的方式理解Vue的自定义指令与混合
		
vue.js 自定义指令 钩子函数:bindinsertedupdatecomponentUpdatedunbind 钩子函数完整实例:html: <div id="hook-argu ...
 - Vue.js自定义指令的用法与实例
		
市面上大多数关于Vue.js自定义指令的文章都在讲语法,很少讲实际的应用场景和用例,以致于即便明白了怎么写,也不知道怎么用.本文不讲语法,就讲自定义指令的用法. 自定义指令是用来操作DOM的.尽管Vu ...
 - vue中自定义组件(插件)
		
vue中自定义组件(插件) 原创 2017年01月04日 22:46:43 标签: 插件 在vue项目中,可以自定义组件像vue-resource一样使用Vue.use()方法来使用,具体实现方法: ...
 - vue 通过自定义指令实现 置顶操作;
		
项目需求:要求当前项目每个页面滑到超出一屏的距离时,出现 backTop 按钮,点击则回到最顶端:俗称置顶操作: 因为涉及到的页面较多,每个页面都加肯定显得重复累赘,最终想到了 Vue 的自定义指令 ...
 - Vue基础-自定义事件的表单输入组件、自定义组件的 v-model
		
Vue 测试版本:Vue.js v2.5.13 学习 Vue 的自定义事件的表单输入组件,觉得文档讲的不太细致,所以这里再细化一下: 如果不用 v-model,代码应该是这样: <myinput ...
 - vue怎么自定义指令??
		
最近看看vue中自定义指令,感觉vue的指令和angular1的指令相差较大 <script> //指令钩子函数: /* bind 只调用一次,指令第一次绑定到元素的时调用 inserte ...
 - Vue directive自定义指令+canvas实现H5图片压缩上传-Base64格式
		
前言 最近优化项目-手机拍照图片太大,回显速度比较慢,使用了vue的自定义指令实现H5压缩上传base64格式的图片 canvas自定义指令 Vue.directive("canvas&qu ...
 - Vue.directive 自定义指令
		
一.什么是全局API? 全局API并不在构造器里,而是先声明全局变量或者直接在Vue上定义一些新功能,Vue内置了一些全局API,比如我们今天要学习的指令Vue.directive.说的简单些就是,在 ...
 - vue-gemini-scrollbar(vue组件-自定义滚动条)
		
vue-gemini-scrollbar(vue组件-自定义滚动条) https://segmentfault.com/a/1190000013338560
 - Vue微信自定义分享时安卓系统config:ok,ios系统config:invalid signature签名错误,或者安卓和ios二次分享时均config:ok但是分享无效的解决办法
		
简述需求:要求指定页面可以进行微信自定义分享(自定义标题,描述,图片,链接),剩下的页面隐藏所有基础接口.二次分享依然可以正常使用,切换至其他页面也可以正常进行自定义分享. 这两天在做微信自定义分享的 ...
 
随机推荐
- 陶陶摘苹果(0)<P2005_1>
			
陶陶摘苹果 (apple.pas/c/cpp) [问题描述] 陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果.苹果成熟的时候,陶陶就会跑去摘苹果.陶陶有个30厘米高的板凳,当她不能直接用 ...
 - Linux下给mysql创建用户并分配权限
			
// fe_group 用户名// fe 数据库名// 123456 密码 1.新建用户 //登录MYSQL @>mysql -u root -p @>密码 //创建用户 mysql> ...
 - centos彻底卸载mysql(不保留数据)
			
1. rpm -qa | grep -i mysql 查找已经安装的mysql. MySQL-server-5.6.43-1.el6.x86_64 MySQL-client-5.6.43-1.el6. ...
 - SpringBoot与Mybatis-plus整合,代码生成mvc层
			
一.添加pom依赖 <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifac ...
 - dmidecode查看硬件信息
			
//check memory,cpu,system,biosroot@dellemc-diag-os:/home# dmidecode -t Memoryroot@dellemc-diag-os:/h ...
 - Send key模块发送按键
			
filename:send_key.py 1 # Author:Bing # Date:07/19/2017 import SendKeys import win32gui import pywin ...
 - 【PAT甲级】1007 Maximum Subsequence Sum (25 分)
			
题意: 给出一个整数K(K<=10000),输入K个整数.输出最大区间和,空格,区间起点的数值,空格,区间终点的数值.如果有相同的最大区间和,输出靠前的.如果K个数全部为负,最大区间和输出0,区 ...
 - flex布局(非常重要)
			
首先明确一点是, flex 是 flex-grow.flex-shrink.flex-basis的缩写.故其取值可以考虑以下情况: flex 的默认值是以上三个属性值的组合.假设以上三个属性同样取默认 ...
 - 利用java反射调用类的的私有方法--转
			
原文:http://blog.csdn.net/woshinia/article/details/11766567 1,今天和一位朋友谈到父类私有方法的调用问题,本来以为利用反射很轻松就可以实现,因为 ...
 - 7.Varnish
			
概述 Varnish处理HTTP请求的过程大致分为如下几个步骤: 1> Receive状态:请求处理入口状态,根据VCL规则判断该请求应该Pass或Pipe,还是进入Lookup ...