整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Nuxt.js从0到1之入门教程

Nuxt.js从0到1之入门教程

外话:近来想把网站做下更新,从框架到内容的更新,但又不想放弃SEO的优势,日常工作用到vue.js在SEO方面劣势较多,果断选择了Nuxt.js,苦于国内文章抄袭的非常严重 如某n 某书,最终在稀土找到一篇像样的文章,以头条为平台记录网站改版全过程。

此文章建议在PC端查看,涉及到代码部分,移动端查看确实不方便

Nuxt.js 概要

简而言之,Nuxt.js是帮助Vue.js轻松完成服务端渲染工作的框架。Nuxt.js预设了服务端渲染所需要的各种配置,如异步数据,中间件,路由。它好比是 Angular Universal 之于 Angular, Next.js 之于 React。

如Nuxt.js文档所说,通过对客户端/服务端基础架构的抽象,Nuxt.js 让开发者专注于页面的UI渲染。

静态文件生成器

Nuxt.js的一个重要功能是,通过 generate 命令,生成静态站点。类似于流行的静态生成工具Jekyll。

Nuxt.js 内部依赖

除了Vue.js 2.0之外,Nuxt.js集成了如下模块: Vue-Router, Vue-Meta 和 Vuex (仅在使用 Vuex 状态树配置项 时引入)。 这样的好处在于,不需要手工配置依赖,不需要同时在客户端和服务端配置相同的库。 Nuxt.js在包含如上依赖的情况下,总大小仍然保持在 28kb min+gzip (如果使用了 Vuex 特性的话为 31kb)。

另外,Nuxt.js 使用 Webpack 和 vue-loader 、 babel-loader 来处理代码的自动化构建工作(如打包、代码分层、压缩等等)。

工作原理

当你访问一个基于Nuxt.js构建的页面时,发生了的事情如下:

  1. 当用户访问应用程序, 如果store中定义了 nuxtServerInit action,Nuxt.js将调用它更新store。
  2. 接下来,将加载即将访问页面所依赖的任何中间件。Nuxt首先从nuxt.config.js这个文件中,加载全局依赖的中间件,之后检测每个相应页面对应的布局文件 ,最后,检测布局文件下子组件依赖的中间件。以上是中间件的加载顺序。
  3. 如果要访问的路由是一个动态路由, 且有一个相应的 validate() 方法路由的validate 方法,将进行路由校验。
  4. 之后, Nuxt.js 调用 asyncData() 和 fetch() 方法,在渲染页面之前加载异步数据。asyncData() 方法用于异步获取数据,并将fetch回来的数据,在服务端渲染到页面。 用fetch() 方法取回的将数据在渲染页面之前填入store。
  5. 最后一步, 将所有数据渲染到页面。

下图阐述了 Nuxt.js 应用一个完整的服务器请求渲染的流程,摘自官网:

使用 Nuxt.js 创建一个静态网站

下面让我们动手创建一个基于Nuxt.js简单的静态博客。我们的发送的请求,返回 mock 的JSON数据。

完成下面的例子,你需要了解基础的 vue.js 知识。如果你是个新手,你可以通过Jack Franklin的getting started guide了解 Vue.js 2.0。同时,我将使用ES6语法,你可以参考www.sitepoint.com/tag/es6/ 重温ES6语法。

我们的 Demo 最终效果如下:

本文中代码可参照 GitHub, demo 地址如下:https://github.com/sitepoint-editors/nuxt-ssr-blog/

基础配置

开始使用 Nuxt.js 最简单的方式就是使用 Nuxt.js 团队自己开发的脚手架。我们可以使用 vue-cli 快速创建我们的项目 (ssr-blog):

`vue init nuxt/starter ssr-blog`
# 提示: 如果你没有安装过vue-cli,请先通过npm install -g vue-cli 命令安装vue-cli。

# 之后,我们将安装项目的依赖
cd ssr-blog
npm install

# 现在我们启动程序:
`npm run dev`

# 如果正确启动, 你能访问 http://localhost:3000 
# 展示的页面是 Nuxt.js 模板的初始页面
# 你也可以通过查看页面源代码,验证页面所展示的一切内容,都是服务端渲染好的。

下面,我们简单配置下 nuxt.config.js,包含以下选项:

// ./nuxt.config.js

module.exports={
  /*
   * Headers of the page
   */
  head: {
    titleTemplate: '%s | Awesome JS SSR Blog',
    // ...
    link: [
      // ...
      { 
        rel: 'stylesheet', 
        href: 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.2/css/bulma.min.css' 
      }
    ]
  },
  // ...
}

在如上配置文件下,我们使用 titleTemplate 字段 title 变量指定文章题目,在渲染之前用title变量值替换掉%s这个占位,填充到titleTemplate

同时,我也使用了 CSS 框架, Bulma, 预设一些样式。通过 link 配置项。

提示: Nuxt.js使用 vue-meta 更新我们的 html headers 信息。所以,我们可以看看 meta 具体的配置项,优化页面 html 信息。

现在,我们可以通过几个步骤,完成博客的页面和功能。

使用 Layouts

首先,我们将为我们所有的页面定义一个通用的基本布局。我们通过修改 layouts/default.vue 文件,更新 main Nuxt.js layout:

<!-- ./layouts/default.vue -->

<template>
  <div>
    <!-- navigation -->
    <nav class="nav has-shadow">
      <div class="container">
        <div class="nav-left">
          <nuxt-link to="/" class="nav-item">
            Awesome JS SSR Blog!
          </nuxt-link>
          <nuxt-link active-class="is-active" to="/" class="nav-item is-tab" exact>Home</nuxt-link>
          <nuxt-link active-class="is-active" to="/about" class="nav-item is-tab" exact>About</nuxt-link>
        </div>
      </div>
    </nav>
    <!-- /navigation -->

    <!-- displays the page component -->
    <nuxt/>

  </div>
</template>

在我们通用的布局里,我们仅仅对页面添加导航栏,我们通过 component进一步完成具体页面模块的定制。你可以查看components-nuxt-link 进一步了解。

在创建布局时component非常重要,它决定具体页面展示的元素。

当然,component也可以做更多事情,比如定义通用组件和错误页面,但是我们的博客很简单,不需要这些功能。强烈建议阅读 Nuxt.js documentation on views ,你可以通过这篇文章了解更多 Nuxt.js 特性。

简单的页面和路由

Nuxt.js 页面是以 单文件组件 形式组织目录结构。 Nuxt.js 自动找到目录下每个 .vue 文件,并添加到页面中。

创建博客主页

我们可以通过修改 index.vue 文件修改主页, 通过 Nuxt.js 创建的文件如下:

<!-- ./pages/index.vue -->
<template>
  <div>
    <section class="hero is-medium is-primary is-bold">
      <div class="hero-body">
        <div class="container">
          <h1 class="title">
            Welcome to the JavaScript SSR Blog.
          </h1>
          <h2 class="subtitle">
            Hope you find something you like.
          </h2>
        </div>
      </div>
    </section>
  </div>
</template>

<script>
  export default {
    head: {
      title: 'Home'
    }
  }
</script>

如前所述,在渲染之前,题目将自动填充至文件。

我们现在可以刷新页面,看看主页的变化。

创建 About 页面

Nuxt.js 还有一个优秀的特性,监听文件夹下文件的更改,所以,在文件更改时,不需要重启应用更新。

来,我们添加一个简单的 about.vue 页面:

<!-- ./pages/about.vue -->
<template>
  <div class="main-content">
    <div class="container">
      <h2 class="title is-2">About this website.</h2>
      <p>Curabitur accumsan turpis pharetra <strong>augue tincidunt</strong> blandit. Quisque condimentum maximus mi, sit amet commodo arcu rutrum id. Proin pretium urna vel cursus venenatis. Suspendisse potenti. Etiam mattis sem rhoncus lacus dapibus facilisis. Donec at dignissim dui. Ut et neque nisl.</p>
      <br>
      <h4 class="title is-4">What we hope to achieve:</h4>
      <ul>
        <li>In fermentum leo eu lectus mollis, quis dictum mi aliquet.</li>
        <li>Morbi eu nulla lobortis, lobortis est in, fringilla felis.</li>
        <li>Aliquam nec felis in sapien venenatis viverra fermentum nec lectus.</li>
        <li>Ut non enim metus.</li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  head: {
    title: 'About'
  }
}
</script>

现在我们访问 http://localhost:3000/about 看看about页面,无需重启,非常方便。

在主页展示文章列表

我们的首页在没有内容的时候展示如上, 所以下一步,我们要在 index.vue 上添加博客列表这个组件。

首先,我们需要把 JSON 格式的文章保存在服务根目录下。文件可以从 这里下载,或者你可以复制下面的 JSON 到根目录文件夹 posts.json 下:

[
    {
        "id": 4,
        "title": "Building universal JS apps with Nuxt.js",
        "summary": "Get introduced to Nuxt.js, and build great SSR Apps with Vue.js.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "08:00 - 07/06/2017"
    },
    {
        "id": 3,
        "title": "Great SSR Use cases",
        "summary": "See simple and rich server rendered JavaScript apps.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "17:00 - 06/06/2017"
    },
    {
        "id": 2,
        "title": "SSR in Vue.js",
        "summary": "Learn about SSR in Vue.js, and where Nuxt.js can make it all faster.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "13:00 - 06/06/2017"
    },
    {
        "id": 1,
        "title": "Introduction to SSR",
        "summary": "Learn about SSR in JavaScript and how it can be super cool.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "John Doe",
        "published": "11:00 - 06/06/2017"
    }
]

提示: 理想情况下,我们应该从通过 API 获取文章数据。

components 存放在 components 文件夹下,我们可以创建如下组件:

<!-- ./components/Posts.vue -->
<template>
  <section class="main-content">
    <div class="container">
      <h1 class="title has-text-centered">
        Recent Posts.
      </h1>
      <div class="columns is-multiline">
        <div class="column is-half" v-for="post in posts">
          <div class="card">
           <header class="card-header">
            <p class="card-header-title">
              {{ post.title }}
            </p>
          </header>
          <div class="card-content">
            <div class="content">
              {{ post.summary }}
              <br>
              <small>
                by <strong>{{ post.author}}</strong> 
                \\ {{ post.published }}
              </small>
            </div>
          </div>
          <footer class="card-footer">
            <nuxt-link :to="`/post/${post.id}`" 
              class="card-footer-item">
              Read More
            </nuxt-link>
          </footer>
        </div>
      </div>
    </div>
  </div>
</section>
</template>

<script>
  import posts from '~/posts.json'

  export default {
    name: 'posts',
    data () {
      return { posts }
    }
  }
</script>

我们引入 JSON 文件充当异步数据,通过 v-for 指令循环列表,取出我们需要的属性填充进组件模板展示。

提示: ~ 符号是 / 的别名。你可以查看 这篇文档 了解更具体的用法。

下面,我们添加 component 到主页:

<!-- ./pages/index.vue -->
<template>
<div>
    <!-- ... -->
    <posts />
</div>
</template>

<script>
import Posts from '~components/Posts.vue'

export default {
  components: {
    Posts
  },
  // ...
}
</script>

添加动态路由

现在,我们为文章页配置动态路由,我们以 /post/1 为例:

为此,我们添加 post 文件夹到 pages 目录下,如下:

pages
└── post
    └── _id
        └── index.vue

我们的程序生成相应的动态路由:

router: {
  routes: [
    // ...
    {
      name: 'post-id',
      path: '/post/:id',
      component: 'pages/post/_id/index.vue'
    }
  ]
}

更新单一发布文件:

<!-- ./pages/post/_id/index.vue -->
<template>
  <div class="main-content">
    <div class="container">
      <h2 class="title is-2">{{ post.title }}</h2>
      <div v-html="post.content"></div>
      <br>
      <h4 class="title is-5 is-marginless">by <strong>{{ post.author }}</strong> at <strong>{{ post.published }}</strong></h4>
    </div>
  </div>
</template>

<script>
  // import posts saved JSON data
  import posts from '~/posts.json'

  export default {
    validate ({ params }) {
      return /^\d+$/.test(params.id)
    },
    asyncData ({ params }, callback) {
      let post=posts.find(post=> post.id===parseInt(params.id))
      if (post) {
        callback(null, { post })
      } else {
        callback({ statusCode: 404, message: 'Post not found' })
      }
    },
    head () {
      return {
        title: this.post.title,
        meta: [
          {
            hid: 'description',
            name: 'description',
            content: this.post.summary
          }
        ]
      }
    }
  }
</script>

Nuxt.js通过添加通用方法,简化开发流程。看看我们应该如何在单文件应用中使用它。

  • 路由校验可以通过路由校验方法 validate 校验路由。如果我们的验证路由参数验证数字,如果验证失败,将自动跳转到404页面。如果它返回“false”,Nuxt。js将自动加载404错误页面。想看更多,请查看Nuxt官网。
  • asyncData 方法用于 fetch 数据,并在服务端渲染页面,返回给浏览器。它可以通过多种方式返回数据。我们可以通过多种方式返回数据。在本文中的例子里,我们使用回调函数返回页面。我们使用一个回调函数来返回相同的帖子“id”属性“id”参数的路线。
  • 正如我们之前看到的,我们使用head 的方法来设置页面 header 。这时,我们改变页面你的 title ,添加页面信息到具体页面。

现在我们可以再次访问我们的博客看到所有路线和页面正常工作,并查看页面源代码生成的HTML。我们有一个服务器端JavaScript应用程序呈现功能。

生成静态文件

接下来,我们要生成程序的 HTML 静态文件。

我们需要对 Nuxt.js 做一个小修改,Nuxt.js 默认忽略动态路由。为了生成动态路由文件,我们需要修改 ./nuxt.config.js

我们使用回调函数,返回以后包含动态路由的列表:

// ./nuxt.config.js

module.exports={
  // ...
  generate: {
    routes(callback) {
      const posts=require('./posts.json')
      let routes=posts.map(post=> `/post/${post.id}`)
      callback(null, routes)
    }
  }
}

如果你想查看全部关于 generate 的配置, 可以参照 这篇文档 。

运行如下命令,生成全部页面:

`npm run generate`

Nuxt 将所有生成的页面放到 dist 文件夹下。

使用 Nginx 部署

最后一步,可以使用 Nginx 进行部署,nginx的安装过程此文不再赘述。

结论

generate 命令来生成我们页面的静态文件,假如,我们需要回复。

下一期讲,改版中的踩坑问题。

气这么冷,大家都多穿点衣服哦,不用只讲风度,不要温度哦!

前言

小程序如何返回到上一个页面,并刷新页面呢?这样的需求很常见,比如: 订单详情页面,订单状态是“已付款”,这时候发起“退款”,跳转到申请退款页面,申请成功后,返回到订单详情,这时候的订单状态 是不是要变为“退款中”的状态?

微信小程序如何返回到上一个页面,并刷新页面呢?

在普通的html页面,很简单,不用操作都可以实现。因为浏览器返回会自动刷新。 但是小程序返回是不会自动刷新上一个页面的。所以需要一点点技巧。

下面还是模拟上面的场景。

申请退款页

发起申请退款后,我们用wx.navigateBack()返回到订单详情页面,小程序API有详情说明。

关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。 参数说明:

微信小程序如何返回到上一个页面,并刷新页面呢?

订单详情页

重点来了,抛开上面的需求,我们就查询订单详情接口

onLoad(options){ 
 let orderId=options.orderId; 
 // 根据orderId查询订单详情数据 
 wx.request({ 
 url: 'xxxxxx', // 接口地址 
 data: { 
 orderId: orderId 
 }, 
 header: { 
 'content-type': 'application/json' // 默认值 
 }, 
 success(res) { 
 console.log(res.data) 
 } 
 }) 
}

如果就这样,那页面返回并不执行onLoad函数,所以就不会获取新的数据,来更新状态。

我们找到了onShow函数(生命周期回调 — 用于监听页面显示)Page(Object) 构造器详细说明

返回时,onShow是会执行的,所以改造上面方法

data: { 
 orderId: '' 
}, 
onShow() { 
 // 获取data里面存的orderId 
 let orderId=this.data.orderId; 
 wx.request({ 
 url: 'xxxxxx', // 接口地址 
 data: { 
 orderId: orderId 
 }, 
 header: { 
 'content-type': 'application/json' // 默认值 
 }, 
 success(res) { 
 console.log(res.data) 
 } 
 }) 
}, 
onLoad(options){ 
 let orderId=options.orderId; 
 // 向data里面set orderId 
 this.setData({ 
 orderId: orderId 
 }) 
}

onLoad把参数存起来,这个参数options是订单列表,或者其他页面带入的。从申请退款页返回,是不用参数的,返回onShow 执行需要的orderId是原来已经缓存的。 然后onShow直接用这个参数,onShow是获取不到url参数的。

小提示

小程序开发中,如果用到倒计时,当退出小程序,或者,按手机home键,倒计时不会继续执行。比如,到时间是30s,你按了home键,过了10s,再进入小程序,倒计时不是是20s,依旧会从30s倒计时。 所以,也需要用到onShow,来刷新这个倒计时。 这也是小程序退出,重新进入不会执行onLoad函数的问题。

公告

喜欢小编的点击关注,了解更多知识!

源码地址请点击下方“了解更多”

人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。

产品设计时细节是产品经理最头疼的问题,一个button,一个链接都要考虑太多的细节问题。作者整理了常见的一些功能设计问题,一篇文章看懂这些功能设计。来学习吧。

定义

链接也称为超链接,所谓的超链接是指从一个网页指向一个目标的连接关系,这个目标可以是另一个网页,也可以是相同网页上的不同位置,还可以是一个图片,一个电子邮件地址,一个文件,甚至是一个应用程序。而在一个网页中用来超链接的对象,可以是一段文本或者是一个图片。当浏览者单击已经链接的文字或图片后,链接目标将显示在浏览器上,并且根据目标的类型来打开或运行。

样式

链接可以是一个字或是一段字这样的文本,也可以是一个按钮,一张图片,当你点击后跳转到另一个目标,当你把鼠标指针移到某个链接时会变成一个小手,当然在手机上没有这一特点。

1. 文本样式的链接

文本样式的链接一般在搜索引擎的网站呈现蓝色字样,大多会在下面加上下划线以便识别,不过现如今考虑到不影响文本的可读性与用户体验,逐渐取消了下划线。而在一些别的网站考虑到界面设计风格各方面的因素而不用蓝色。

谷歌的文本链接是蓝色,没有下划线

百度的文本链接也是蓝色,关键词是红色,有下划线

而京东的文本链接有灰色,有白色,有黑色

2. 按钮样式的链接

按钮样式的链接比文本样式的更容易识别,每一个按钮都是一样链接。

按钮样式链接

3. 图片样式的链接

图片样式的链接可以是单独的一张图片,也可以是文字与按钮一起组成一张图片,只是鼠标指针扫过图片的任何一个部位都会变成小手。

如桌面弹出这种游戏小窗口的图片式链接

由文字/图/按钮样式一起构成的一张图片式按钮,鼠标可以点击图中任何一部位

打开方式

链接打开的方式有三种:第一种是在当前页面刷新跳转,国外的网站大多是这样的打开式;第二种是在新标签页面打开链接,国内大多采用这种;第三种是提示用APP打开。当然现在出现了一种新的打开方式,那就是二维码扫描。

提示用美拍APP打开

类型

按照连接路径的不同,网页中超链接一般分为以下3种类型:内部链接,锚点链接和外部链接。

链接还可以分为动态链接和静态链接。动态超链接指的是可以通过改变HTML代码来实现动态变化的链接,例如我们可以实现将鼠标移动到某个文字链接上,文字就会象动画一样动起来或改变颜色的效果,也可以实现鼠标移到图片上图片就产生反色或朦胧等等的效果。而静态链接,顾名思义,就是没有动态效果的链接。

1. 内部链接

与外部链接(即反向链接)相反,内部链接是指同一网站域名下的内容页面之间互相链接。如频道、栏目、终极内容页之间的链接,乃至站内关键词之间的Tag链接都可以归类为内部链接,因此内部链接我们也可以称之为站内链接,对内部链接的优化其实就是对网站的站内链接的优化。

2. 锚点链接

HTML中的链接,正确的说法应该称作"锚点",它命名锚点链接(也叫书签链接)常常用于那些内容庞大繁琐的网页,通过点击命名锚点,不仅让我们能指向文档,还能指向页面里的特定段落,更能当作"精准链接"的便利工具,让链接对象接近焦点。便于浏览者查看网页内容。类似于我们阅读书籍时的目录页码或章回提示。在需要指定到页面的特定部分时,标记锚点是最佳的方法。

3. 外部链接

外部链接,又常被称为:“反向链接”或“导入链接”,是指通过其他网站链接到你的网站的链接。

外部链接指的是针对搜索引擎,与其它站点所做的友情链接。高质量的外部链接指:和你的网站建立链接的网站知名度高,访问量大,同时相对的外部链接较少,有助于快速提升你的网站知名度和排名的其他网站的友情链接。

如果按照使用对象的不同,网页中的链接又可以分为:文本超链接,图像超链接,E-mail链接,锚点链接,多媒体文件链接,空链接等。

链接是一种对象,它以特殊编码的文本或图形的形式来实现链接,如果单击该链接,则相当于指示浏览器移至同一网页内的某个位置,或打开一个新的网页,或打开某一个新的WWW网站中的网页。

链接状态

链接在交互上一般会呈现4种状态,即默认状态/悬停时状态/点击时状态/点击后状态。比如谷哥网站的交互体验。如下图:

点击前

悬停时,下面浮现半透明线条

点击时,有波纹晕开的动态效果

点击后,下面线条粗

有时候是3种状态,比如百度网和知乎应用:

默认状态

点击时链接变红

点击后链接变成紫色

IOS系统知乎应用的3种状态,而在Android系统没有用力点击这一状态。

默认状态

点击状态

用力点击会弹出预览小窗口

有些时候只有2种状态,如下图谷歌网:

默认和点击后状态一样

鼠标悬停时出现下划线

默认状态

点击时

而有时候比如在APP里有时候就一直只有一种状态,也可以称静态链接,之前的可以称之为动态链接。在不同的使用场景会因为当时的情况选择最合适的交互体验设计。有的情况下还会加上点击的音效,使用户体验更畅快,这在移动端用的使用情况多一些。

总之链接是网页不可缺少的构成部分,每一个链接的呈现都是经过深思熟虑的。

作者:潘瑶琼(简书作者)

本文由 @潘瑶琼 授权发布于人人都是产品经理,未经作者许可,禁止转载。