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 ...