vue 组件 not defined_Vue.js从零开始——复用和插件(3)

6522350b19621c0a1a07e609819bcd6a.png

原本想这个部分用两天就搞定了,结果还是剩下一小部分不得不放在今天,插件和过滤器(本来想和复用和插件(1)合并在一起的,但忘记了-_-)。


1 插件

插件通常用来为 Vue 添加全局功能,插件的功能范围没有严格的限制——一般有下面几种:

  1. 添加全局方法或者 DOM 属性,如:vue-custom-element
  2. 添加全局资源:指令/过滤器/过渡等,如 vue-touch
  3. 通过全局混入来添加一些组件选项,如 vue-router
  4. 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现
  5. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能,如vue-router

1.1 使用

通过全局方法 Vue.use() 使用插件,它需要在调用 new Vue() 启动应用之前完成:

// 调用 MyPlugin.install(Vue)
Vue.use(MyPlugin);

new Vue({
  // ...组件选项
});

也可以传入一个可选的选项对象:

Vue.use(MyPlugin, { someOption: true });

Vue.use 会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。

Vue.js 官方提供的一些插件 (例如 vue-router) 在检测到 Vue 是可访问的全局变量时,会自动调用 Vue.use(),然而在像 CommonJS 这样的模块环境中,我们需要始终显式地调用 Vue.use()

// 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
let Vue = require('vue');
let VueRouter = require('vue-router');

// 不要忘了调用此方法
Vue.use(VueRouter);

awesome-vue 集合了大量由社区贡献的插件和库。

1.2 使用范例

下面是一个比较基础的在 Node.js 当中使用 vue-router 的范例:

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const Home = { template: '<router-view></router-view>' };
const Default = { template: '<div>default</div>' };
const Foo = { template: '<div>foo</div>' };
const Bar = { template: '<div>bar</div>' };
const Baz = { template: '<div>baz</div>' };
const WithParams = { template: '<div>{{ $route.params.id }}</div>' };
const Foobar = { template: '<div>foobar</div>' };
const FooBar = { template: '<div>FooBar</div>' };

const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [
    { path: '/', component: Home,
      children: [
        { path: '', component: Default },
        { path: 'foo', component: Foo },
        { path: 'bar', component: Bar },
        { path: 'baz', name: 'baz', component: Baz },
        { path: 'with-params/:id', component: WithParams },
        // relative redirect to a sibling route
        { path: 'relative-redirect', redirect: 'foo' }
      ]
    },
    // absolute redirect
    { path: '/absolute-redirect', redirect: '/bar' },
    // dynamic redirect, note that the target route 'to' is available for the redirect function
    { path: '/dynamic-redirect/:id?',
      redirect: to => {
        const { hash, params, query } = to;
        if (query.to === 'foo') {
          return { path: '/foo', query: null };
        }
        if (hash === '#baz') {
          return { name: 'baz', hash: '' };
        }
        if (params.id) {
          return '/with-params/:id';
        } else {
          return '/bar';
        }
      }
    },
    // named redirect
    { path: '/named-redirect', redirect: { name: 'baz' }},

    // redirect with params
    { path: '/redirect-with-params/:id', redirect: '/with-params/:id' },

    // redirect with caseSensitive
    { path: '/foobar', component: Foobar, caseSensitive: true },

    // redirect with pathToRegexpOptions
    { path: '/FooBar', component: FooBar, pathToRegexpOptions: { sensitive: true }},

    // catch all redirect
    { path: '*', redirect: '/' }
  ]
})

new Vue({
  router,
  template: `
    <div id="app">
      <h1>Redirect</h1>
      <ul>
        <li><router-link to="/relative-redirect">
          /relative-redirect (redirects to /foo)
        </router-link></li>
        <li><router-link to="/relative-redirect?foo=bar">
          /relative-redirect?foo=bar (redirects to /foo?foo=bar)
        </router-link></li>
        <li><router-link to="/absolute-redirect">
          /absolute-redirect (redirects to /bar)
        </router-link></li>
        <li><router-link to="/dynamic-redirect">
          /dynamic-redirect (redirects to /bar)
        </router-link></li>
        <li><router-link to="/dynamic-redirect/123">
          /dynamic-redirect/123 (redirects to /with-params/123)
        </router-link></li>
        <li><router-link to="/dynamic-redirect?to=foo">
          /dynamic-redirect?to=foo (redirects to /foo)
        </router-link></li>
        <li><router-link to="/dynamic-redirect#baz">
          /dynamic-redirect#baz (redirects to /baz)
        </router-link></li>
        <li><router-link to="/named-redirect">
          /named-redirect (redirects to /baz)
        </router-link></li>
        <li><router-link to="/redirect-with-params/123">
          /redirect-with-params/123 (redirects to /with-params/123)
        </router-link></li>
        <li><router-link to="/foobar">
          /foobar
        </router-link></li>
        <li><router-link to="/FooBar">
          /FooBar
        </router-link></li>
        <li><router-link to="/not-found">
          /not-found (redirects to /)
        </router-link></li>
      </ul>
      <router-view class="view"></router-view>
    </div>
  `
}).$mount('#app')

73f8930932bb24ccf387249e86ea9aba.gif

当然,因为 vue-router 是一个很重要的插件,几乎可以说是 Vue.js 密不可分的一部分,所以后面会专门来看看它的,现在就仅仅是个演示。

1.3 开发

Vue.js 的插件应该暴露一个 install 方法,这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}

剩余的部分,靠的就是我们的想象力和对原生 JavaScript 以及 Vue 的熟悉程度了,这方面,可以参考一些简单的 Vue.js 插件源代码来看看。

这里我找到一个非常简单的插件:gocanto/lazy-vue(作者gocanto),用来实现图片懒加载的一个插件,其源代码如下(未做任何改动),分为两个 .js 文件:

image.js

/**
 * Export the directive core code.
 *
 * @type {Object}
 */
module.exports = {

	bind: (el, binding) => {

		let img = new Image();
		img.src = binding.value;

		img.onload = () => {
			el.src = img.src;
			fadeIn(el);
		}
	}

};

/**
 * Apply a fade in effect to a given element.
 *
 * @param  {Object} el
 * @return {Void}
 */
function fadeIn(el)
{
	el.style.opacity = 0;
	el.style.display = "block";

	(function fadeIn() {
		let val = parseFloat(el.style.opacity);
		if (! ((val += .1) > 1)) {
			el.style.opacity = val;
			setTimeout(fadeIn, 40);
		}
	})();
}

lazy.js:

/**
 * The global directive.
 * @author Gustavo Ocanto <gustavoocanto@gmail.com>
 * @license https://github.com/gocanto/lazy-vue/blob/master/LICENSE
 */

import Vue from 'vue';

Vue.directive(
	'lazy',
	require('./image')
);

从上面的代码可以看得出来,如果我们需要开发插件,需要的仅仅是遵循官方的指引 + 足够的技术能力 + 自己的想法。

2 过滤器

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

过滤器可以用在两个地方:双花括号插值和 v-bind 表达式,过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号(|)指示:

<!-- 在双花括号中 -->
{{ message | capitalize }}

<!-- 在 v-bind 中 -->
<div v-bind:id="rawId | formatId"></div>

我们可以在一个组件的选项中定义本地的过滤器,如下:

filters: {
  capitalize: function (value) {
    if (!value) return '';
    value = value.toString();
    return value.charAt(0).toUpperCase() + value.slice(1);
  }
}

或者在创建 Vue 实例之前全局定义过滤器:

Vue.filter('capitalize', function (value) {
  if (!value) return '';
  value = value.toString();
  return value.charAt(0).toUpperCase() + value.slice(1);
});

new Vue({
  // ...
});

局部过滤器的优先级更高,所以当全局过滤器和局部过滤器重名时,会采用局部过滤器。

下面这个例子用到了 capitalize 过滤器:

<!DOCTYPE html>
<html>
  <head>
    <title>hello</title>
    <script src="https://unpkg.com/vue"></script>
  </head>
  <body>
    <div id="app" class="demo">
      <input type="text" v-model="message">
      <p>{{ message | capitalize }}</p>
    </div>
    <script>
      new Vue({
        el: '#app',
        data: function () {
          return {
            message: 'Michael'
          }
        },
        filters: {
          capitalize: function (value) {
            if (!value) return '';
            value = value.toString();
            return value.charAt(0).toUpperCase() + value.slice(1);
          }
        }
      });
    </script>
  </body>
</html>

22dbcfcaa7b0ddeab5e5c033de1e743b.gif

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

过滤器还可以串联:

{{ message | filterA | filterB }}

在这个例子中,filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中;然后继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递到 filterB 中。

过滤器是 JavaScript 函数,因此可以接收参数:

{{ message | filterA('arg1', arg2) }}

这里,filterA 被定义为接收三个参数的过滤器函数,其中 message 的值作为第一个参数,普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。

因为过滤器相对来说更简单,所以就不多做赘述了。

我们可以通过这三个章节看到 Vue 为了实现复用,开放了很多自定义的方法给开发者,这样在确保不丢失掉其易用性的前提下,也给了我们足够的开放性和自由,来对 Vue.js 进行自己理想当中的自定义,从而获得更强的能力,能更好地适应自己的项目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值