阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      meteor 初学的记录

      学习资料:

      中文翻译:http://zh.discovermeteor.com/chapters/getting-started/
      官方教程:https://www.meteor.com/tutorials/blaze/creating-an-app
      官网手册:https://guide.meteor.com/
      Api文档 :https://docs.meteor.com/
      社区讨论:https://forums.meteor.com/
      

      Meteor 不同于传统的 MVC,Meteor 可以做更多很酷的事情,其中一件主要的就是 Metoer 变得数据库无处不在。简单说,Meteor 把你的数据拿出一部分子集复制到客户端。

      这样后两个主要结果:

      • 第一,服务器不再发送 HTML 代码到客户端,而是发送真实的原始数据,让客户端决定如何处理线传数据。
      • 第二,你可以不必等待服务器传回数据,而是立即访问甚至修改数据

      ************************* 初始化项目 **************************

      meteor 初始化项目(下面代码直接自带脚手架)

          meteor create meteor-demo
      

      会在当前目录下,创建一个 meteoe-demo 的文件夹(类似 vue-cli 初始化的项目一样)

      参数有

      meteor create –bare  //空的app
      meteor create –full    //脚手架的app
      

      启动项目

      cd meteoe-demo
      meteor
      

      build 后就可以访问:http://localhost:3000/ 这个域名了;

      当看到:

      Welcome to Meteor!

      表示已经跑起来了;

      image

      ************************** 添加代码包 ************************

      添加 bootstrap 和 underscore

      meteor add twbs:bootstrap
      meteor add underscore
      

      image

      安装完成后,会自动引入 bootstrap 和 underscore(Meteor 支持热更新,安装完成后,页面自动会渲染)

      Meteor 中的代码包有点特殊,分为五种:
      • Meteor 核心代码本身分成多个核心代码包(core package),每个 Meteor 应用中都包含,你基本上不需要花费精力来维护它们
      • 常规 Meteor 代码包称为“isopack”,或同构代码包(isomorphic package,意味着它们既能在客户端也能在服务器端工作)。第一类代码包例如 accounts-ui 或 appcache 由 Meteor 核心团队维护,与 Meteor 捆绑在一起。
      • 第三方代码包就是其他用户开发的 isopack 上传到 Meteor 的代码包服务器上。你可以访问 Atmosphere 或 meteor search 命令来浏览这些代码包。
      • 本地代码包(local package)是自己开发的代码包,保存在 /packages 文件夹中。
      • NPM 代码包(NPM package)是 Node.js 的代码包,虽不能直接用于 Meteor,但可以在上述几种代码包中使用

      *************************** 项目结构和加载顺序 ********************************

          ├── .meteor
          ├── client            //在 /client 文件夹中的代码只会在客户端运行。
          │   ├── main.css
          │   ├── main.html
          │   └── main.js
          ├── server            //在 /server 文件夹中的代码只会在服务器端运行。
          ├── public            //请将所有的静态文件(字体,图片等)放置在 /public 文件夹中。
          ├── lib
          ├── node_modules    //包
          ├── package.json
          └── .gitignore
          //其它代码则将同时运行于服务器端和客户端上。
      

      Meteor 以什么顺序加载文件也很有用

      在 /lib 文件夹中的文件将被优先载入。
      所有以 main.* 命名的文件将在其他文件载入后载入。
      其他文件以文件名的字母顺序载入。
      

      ***************************** 集合 ************************************************

      集合从根本上改变应用程序的数据处理方式。从而不必手动检查数据更改(例如,通过一个 AJAX 调用),再根据这些变化去修改 HTML 页面,Meteor 可以随时检测到数据的更改,并将它无缝地应用到用户界面上。

      不同工具的区别:

      1、终端 (系统自带)
      2、浏览器控制台(浏览器自带)
      3、Meteor shell(终端里用 moteor shell 启动)
      4、Mongo shell(终端里用meteor mongo 启动)
      
      

      Mongodb 的简单语法(用在 Mongo shell 里)

      • db.posts.insert({}); 插入数据
      • db.posts.find(); 查找数据库里的数据信息

      浏览器控制台操作 db;

      • Posts.findOne(); 查看第一条数据
      • Posts.find().count(); 查看数据条数
      • Posts.find().fetch(); 查看所有数据
      • Posts.insert({title: “A second post”}); 插入数据,返回当前的 ID

      清空数据库:停用 meteor 服务,输入 meteor reset , 这样就情况 db 了,重启 meteor 服务即可;

      演示 server 端代码;

      //如果数据库是空的,载入3条帖子,如果没有 meteor reset 则不会插入的;
      if(Posts.find().count() === 0){
          Posts.insert({
              title: 'server插入的db数据 111111',
              url: 'http://sachagreif.com/introducing-telescope/'
          });
      
          Posts.insert({
              title: 'server插入的db数据 22222',
              url: 'http://meteor.com'
          });
      
          Posts.insert({
              title: 'server插入的db数据 33333',
              url: 'http://themeteorbook.com'
          });
      }
      
      

      演示 client 端的代码

      Template.postList.helpers({
          posts:Posts.find()
      });
      
      

      ************************* 订阅和发布 *********************

      上面一直都是使用 autopublish 发布的,这个不是为正是环境准备的(autopublish 的目的是让 Meteor 应用有个简单的起步阶段,它简单地直接把服务器上的全部数据镜像到客户端,因此你就不用管发布和订阅了,但是这样带来了安全隐患和更多的内存消耗。)

      Meteor 里可以理解成数据库无处不在。简单说,Meteor 把你的数据拿出一部分子集复制到客户端。 这样后两个主要结果:

      第一,服务器不再发送 HTML 代码到客户端,而是发送真实的原始数据,让客户端决定如何处理线传数据。
      第二,你可以不必等待服务器传回数据,而是立即访问甚至修改数据(延迟补偿 latency compensation)。
      

      名词解释:

      发布:就是服务器发布的数据;一个 App 的数据库可能用上万条数据,其中一些还可能是私用和保密敏感数据。无论是安全原因还是扩展性原因,我们不能简单地把数据库镜像到客户端去。

      订阅:

      需求:卸载 autopublish ,自己写服务端的发布和客户端的订阅;

      卸载 autopublish :
      meteor remove autopublish
      
      

      服务端发布代码 (puhlication.js)

      Meteor.publish('posts',function () {
          return Posts.find();
      });
      
      

      客户端订阅代码(main.js)

      Meteor.subscribe('posts');
      

      我们可以把发布 / 订阅模式想象成为一个漏斗,从服务器端(数据源)过滤数据传送到客户端(目标)。

      这个漏斗的专属协议叫做 DDP(分布式数据协议 Distributed Data Protocol 的缩写)

      下面是 发布和订阅某个作者 的 / 使用函数传参:

      // 在服务器端
      Meteor.publish('posts', function(author) {
          return Posts.find({flagged: false, author: author});
      });
      // 在客户端
      Meteor.subscribe('posts', 'bob-smith');
      

      另外一种

      //同时使用两种技术,只发布作者是 Tom 的帖子,并且隐藏 date 日期字段:
      Meteor.publish('allPosts', function(){
          return Posts.find({'author': 'Tom'}, {fields: {
              date: false
          }});
      });
      

      **************************** 路由 (iron-router ) ***********************

      Meteor 是使用的是 iron-router 这个路由包;

      DOC:https://iron-meteor.github.io/iron-router/

      名次解释:

      • 路由规则(Route):路由规则是路由的基本元素。它的工作就是当用户访问 App 的某个 URL 的时候,告诉 App 应该做什么,返回什么东西。
      • 路径(Path):路径是访问 App 的 URL。它可以是静态的(/terms_of_service)或者动态的(/posts/xyz),甚至还可以包含查询参数(/search?keyword=meteor)。
      • 目录(Segment):路径的一部分,使用正斜杠(/)进行分隔。
      • Hooks:Hooks 是可以执行在路由之前,之后,甚至是路由正在进行的时候。一个典型的例子是,在显示一个页面之前检测用户是否拥有这个权限。
      • 过滤器(Filter):过滤器类似于 Hooks ,为一个或者多个路由规则定义的全局过滤器。
      • 路由模板(Route Template):每个路由规则指向的 Meteor 模板。如果你不指定,路由器将会默认去寻找一个具有相同名称的模板。
      • 布局(Layout):你可以想象成一个数码相框的布局。它们包含所有的 HTML 代码放置在当前的模板中,即使模板发生改变它们也不会变。
      • 控制器(Controller):有时候,你会发现很多你的模板都在重复使用一些参数。为了不重复你的代码,你可以让这些路由规则继承一个路由控制器(Routing Controller)去包含所有的路由逻辑。

      安装路由

      meteor add iron:router
      

      清空 main.html(main 作为公用的头部)

      <head>
          <title>这是一个测试Title</title>
      </head>
      

      创建 layout 的 template (client/templates/application/layout.html)

      <template name="layout">
          <div class="container">
              <header class="navbar navbar-default" role="navigation">
                  <div class="navbar-header">
                      <a href="/" class="navbar-brand">测试的标题啊</a>
                  </div>
              </header>
              <div id="main" class="row-fluid">
                  {{> yield}}
              </div>
          </div>
      </template>
      

      创建 router(lib/router.js)

      //第一,我们告诉路由器使用我们刚刚创建的 layout 模板作为所有路由的默认布局。
      Router.configure({
          layoutTemplate:"layout"
      });
      
      //定义了一个名为 postList 的路由规则,并映射到 / 路径
      Router.route("/",{name:"postList"});
      

      放在 /lib 文件夹里面的所有文件都会在你的 App 运行的时候确保首先被加载;不过有一点注意的是:因为 /lib 文件夹并不是放在 /client 或 /server 文件夹里面,这意味着它的代码将会同时存在于客户端和服务器。

      问题:现在列表都是空一段时间然后再加载(因为要等到 posts 订阅完成后,即从服务器抓取完帖子的数据,才能有帖子显示在页面上。)

      我们可以改为:把订阅放到 waitOn 的返回上(以前是写在 main.js 中的)。

      修改路由:(lib/router.js)

          //第一,我们告诉路由器使用我们刚刚创建的 layout 模板作为所有路由的默认布局。
          Router.configure({
              layoutTemplate:"layout",
              waitOn:function () {
                  return Meteor.subscribe('allPosts');
              }
          });
      
          //定义了一个名为 postList 的路由规则,并映射到 / 路径
          Router.route("/",{name:"postList"});
      

      注意,因为我们在路由器级别上全局定义了 waitOn 方法,所以这个只会在用户第一次访问你的 App 的时候发生一次。在那之后,数据已经被加载到了浏览器的内存,路由器不需要再次去等待它。

      使用 spin 包去创建 loading 效果 ;

      添加:meteor add sacha:spin
      

      然后在 client/templates/includes 文件夹内创建 loading 模板:

          <template name="loading">
              {{>spinner}}
          </template>
      

      router 中配置 loading 模板;

          //第一,我们告诉路由器使用我们刚刚创建的 layout 模板作为所有路由的默认布局。
          Router.configure({
              layoutTemplate:"layout",
              loadingTemplate:"loading",
              waitOn:function () {
                  return Meteor.subscribe('allPosts');
              }
          });
      
          //定义了一个名为 postList 的路由规则,并映射到 / 路径
          Router.route("/",{name:"postList"});
      

      这样就加载好了;注意 {{> spinner}} 是 spin 包中的一个模板标签。尽管这部分是来自我们的 App 之外,不过我们就像其他模板一样去使用它就可以了。

      动态路由的添加;

      文章的页面,就是动态路由实现的;

      router文件如下:
      
          //定义了一个名为 postList 的路由规则,并映射到 / 路径
          Router.route("/",{name:"postList"});
          Router.route("/posts/:_id",
              {
                  name:"postPage",
                  data:function () {
                      //从 URL 上获取 _id ,并通过它获得正确的数据源(否则就没有数据用了):
                      return Posts.findOne(this.params._id);
                  }
              }
          );
      

      post_page 文件如下:

          <template name="postPage">
            <div class="post-page page">
              {{> postItem}}
            </div>
          </template>
      

      当然这需要在列表里的配置链接地址,post_list 的入口如下

          <a href="{{pathFor 'postPage'}}" class="discuss btn btn-default">Discuss</a>
      

      404 页面的添加:

      404 页面分为 2 种,

      一种是错误的 rul;比如:http://localhost:3000/postsssssssss/

      一种是正确的 url,但是找不到数据,比如文章页路径:http://localhost:3000/posts/11111111;

      首先在 application 添加个模板;

      <template name="notFound">
          <div class="not-found jumbotron">
              <h2>404</h2>
              <p>抱歉,我们无法找到该页面。</p>
          </div>
      </template>
      

      然后修改 router 如下;

      Router.configure({
          layoutTemplate:"layout",
          loadingTemplate:"loading",
          notFoundTemplate:'notFound',
          waitOn:function () {
              return Meteor.subscribe('allPosts');
          }
      });
      Router.onBeforeAction('dataNotFound',{only:"postPage"});//没有找到数据的时候
      

      ******** 消息会话 Meteor session *******************

      首先是需要安装 session 这个包的;

      meteor add session
      

      这样安装好以后就可以正常使用了;否则会报错;Session is not defined;

      注意:Session 对象不在用户之间共享,甚至在浏览器标签之间 。

      Session 的设置和获取如下:

      Session.set('pageTitle', 'A brand new title');
      Session.get('pageTitle');
      

      从中我们应该要学会:

      • 应该在 Session 或者 URL 中存储用户状态。从而在动态代码重载的时候,让用户发生中断的机会降到最低。
      • 尽可能使用 URL 去存储你想要共享在用户之间的状态。

      **************** 添加用户 *********************

      首先要终端安装包文件

      meteor add ian:accounts-ui-bootstrap-3
      meteor add accounts-password
      

      通过 {{loginButtons}}helper 在我们的网站中使用,把 header 从 layout 中分隔开

      <template name="header">
          <nav class="navbar navbar-default" role="navigation">
              <div class="navbar-header">
                  <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navigation">
                      <span class="sr-only">Toggle navigation</span>
                      <span class="icon-bar"></span>
                      <span class="icon-bar"></span>
                      <span class="icon-bar"></span>
                  </button>
                  <a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscope</a>
              </div>
              <div class="collapse navbar-collapse" id="navigation">
                  <ul class="nav navbar-nav navbar-right">
                      {{> loginButtons}}
                  </ul>
              </div>
          </nav>
      </template>
      

      如何告诉我们的账户系统要求用户需要通过用户名密码来登录?只需配置一个 Accounts.ui 模块到一个名叫 config.js 的文件里面,并把文件放在 client/helpers/ 中:

      Accounts.ui.config({
          passwordSignupFields: 'USERNAME_ONLY'
      });
      

      常见的查命令( 浏览器控制台)

      Meteor.users.findOne();
      Meteor.users.find().count();
      

      mongo 命令

      db.users.count()
      db.users.find()
      

      **************** 响应式 ***************

      Meteor 是一个实时性、响应式的框架,但并不是所有的代码在 Meteor App 里面都是响应式的。如果是这样,当有任何数据发生改变时,你的 App 都会自动进行重新运行。相反,响应式只是在特定区域的代码中发生,我们称这些区域为 Computations 。 ~

      目录
      本文目录
      目录