vue实战项目:项目技巧总结(汇总成一篇了)

1、建立项目及配置

1.1 vue cli2 建立项目

vue init webpack project
复制代码
npm install
复制代码
npm run dev
复制代码

1.2 vue cli3 建立项目

vue create project
复制代码

选择配置,看我的项目需求javascript

TypeScript 支持使用 TypeScript 书写源码
 Progressive Web App (PWA) Support PWA 支持。
 Router 支持 vue-router 。
 Vuex 支持 vuex 。
 CSS Pre-processors 支持 CSS 预处理器。
 Linter / Formatter 支持代码风格检查和格式化。
 Unit Testing 支持单元测试。
 E2E Testing 支持 E2E 测试。
复制代码

进入到项目根目录css

cd  project
复制代码

启动项目html

npm run serve
复制代码

2、安装 element-UI

npm i element-ui -S
复制代码

2.1main.js 引入

2.1.1 全局引入
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(Element)
复制代码
2.1.2 按需引入

首先,安装 babel-plugin-componentvue

npm install babel-plugin-component -D
复制代码

而后,将 .babelrc 修改成:java

{
 "presets": [
  ["es2015", {
   "modules": false
  }]
 ],
 "plugins": [
  [
   "component",
   {
    "libraryName": "element-ui",
    "styleLibraryName": "theme-chalk"
   }
  ]
 ]
}
复制代码

接下来,若是你只但愿引入部分组件,好比 ButtonSelect,那么须要在 main.js 中写入如下内容:node

import Vue from 'vue';
import { Button, Select } from 'element-ui';
import App from './App.vue';
 Vue.component(Button.name, Button); Vue.component(Select.name, Select);  复制代码

或写为webpack

- Vue.use(Button)
- Vue.use(Select)
复制代码

3、安装 vuex

npm i vuex -s
复制代码
3.1 /src/store 下面的 index.js 中
import Vue from 'vue'
import Vuex from 'vuex'
 //挂载 Vuex Vue.use(Vuex)  //建立 VueX 对象 const store = new Vuex.Store({ state:{name: 'helloVueX', }, mutations:{}, actions:{}, modules:{} })  export default store  复制代码
3.2 main.js 引入

store 挂载到当前项目的 Vue 实例当中去ios

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
 Vue.config.productionTip = false  new Vue({ el: '#app', router, store, //store:store 和 router 同样,将咱们建立的 Vuex 实例挂载到这个 vue 实例中 render: h => h(App) }) 复制代码
3.3 在组件中使用 Vuex
<template>
    <div id='app'>
      name:
      <h1>{{ $store.state.name }}</h1>
    </div>
</template>
 methods:{ add(){ console.log(this.\$store.state.name) } }, 复制代码

更具体的学习文档参考个人网站: 学习文档git

4、配置scss环境

4.1.首先安装依赖
npm install node-sass sass-loader --save-dev 
复制代码
4.2.找到 build 中 webpack.base.conf.js,在 rules 中添加 scss 规则
{
  test: /\.scss\$/,
  loaders: ['style', 'css', 'sass']
} 
复制代码
4.3.在 vue 文件中使用

github

<style lang='scss'> 复制代码</style> 复制代码

4.4 在 vue 项目全局中引入 scss

1.全局引用时须要安装 sass-resources-loader
npm install sass-resources-loader --save-dev 
复制代码
2.修改 build 中的 utils.js

scss: generateLoaders('sass')

修改成
scss: generateLoaders('sass').concat({
 loader: 'sass-resources-loader',
 options: {
  //你本身的 scss 全局文件的路径
  resources: path.resolve(\_\ _dirname, '../src/style/common.scss')
 }
})
复制代码

若是上面的不能正常编译

//配置 sass 编译路径
 function generateSassResourceLoader() { let loaders = [ cssLoader, 'sass-loader', { loader: 'sass-resources-loader', options: { // 多个文件时用数组的形式传入,单个文件时能够直接使用 path.resolve(__dirname, '../static/style/common.scss' resources: path.resolve(__dirname, '../src/style/common.scss') } } ]; if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, fallback: 'vue-style-loader' }); } else { return ['vue-style-loader'].concat(loaders); } } 复制代码
在 cssLoaders 里面引入
sass:generateSassResourceLoader(),//新加的
scss:generateSassResourceLoader(),//新加的
复制代码

4.5 引入全局的 sass

npm install --s node-sass sass-loader
复制代码

1.首先你须要

npm install --s sass-resources-loader 
复制代码

2.在 build 目录下找到 utils.js 文件

Module build failed: TypeError: this.getResolve is not a function at Object.loader 复制代码

安装 node-sass 运行报错 vue 安装 node-sass 编译报错 安装node-scss报错 安装 node-scss 报错

在搭建 vue 脚手架 或者是在 vue 项目中,想使用 sass 的功能,

npm install node-sass --save-dev //安装 node-sass
npm install sass-loader --save-dev //安装 sass-loader
npm install style-loader --save-dev //安装 style-loader
复制代码

这是由于当前 sass 的版本过高,webpack 编译时出现了错误,这个时候只须要换成低版本的就行,下面说一下修改方法,很简单,以下,找到 package.json 文件,里面的 "sass-loader"的版本更换掉 就好了。

"sass-loader": "^8.0.0",更换成了 "sass-loader": "^7.3.1",
复制代码

也能够先卸载当前版本,而后安装指定的版本

卸载当前版本
npm uninstall sass-loader
复制代码
安装
npm install sass-loader@7.3.1 --save-dev
复制代码

5、配置less环境

安装 lessless-loader
npm install less less-loader --save
复制代码

修改 webpack.base.config.js 文件,配置 loader 加载依赖,让其支持外部的 less,在原来的代码上添加

// 此种方法在控制台中标签样式显示的是style标签样式
{
 test: /\.less$/,
 loader: "style-loader!css-loader!less-loader",
}
复制代码
// 能够在控制台中看到当前标签样式来自于哪一个less文件
{
 test: /\.less$/,
 loader: "style-loader!css-loader!less-loader",
 options: {
  sourceMap: true
 }
}
复制代码

在 vue 文件中的 style 标签中添加 lang="less"便可在标签中使用 less,或者外部引入 less

参考文档

6、引入font-awesome

npm install font-awesome --save
复制代码

而后在 main.js 引入 font-awesome/css/font-awesome.min.css 便可。

七、vue 配置网站的 ico

7.1方式一:
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
复制代码
7.2 方式二
webpack.dev.conf.js
new HtmlWebpackPlugin({
  filename: 'index.html',
  template: 'index.html',
  favicon: 'favicon.ico', // 新增
  inject: true
 }),
 webpack.prod.conf.js new HtmlWebpackPlugin({ filename: config.build.index, template: 'index.html', inject: true, minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, // necessary to consistently work with multiple chunks via CommonsChunkPlugin chunksSortMode: 'dependency', favicon: 'favicon.ico' // 新增 }), 复制代码

8、引入自定义公共样式

router/index.js 里面引入公共样式

import 'bootstrap/dist/css/bootstrap.css' //引入 bootstrap
import 'bootstrap-vue/dist/bootstrap-vue.css'
import '@/common/common.css'
import '@/common/index.css'
复制代码

9、路由按需加载

const port = () => import('@/pages/port') //入口页面、
复制代码
const router = new Router({
  // mode: 'history',
  routes: [
    {
      path: '/',
      name: 'port',
      component: resolve => require.ensure([], () => resolve(require('@/pages/port')), 'port'),
    }]
})
复制代码

参考文档

10、全局自定义方法

main.js 里面挂载方法到 vue.prototype
Vue.prototype.isMobile = function() {
 let flag = navigator.userAgent.match(
  /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
 )
 return flag;
}
复制代码
组件里面使用
mounted: function() {
  this.isMobile();
}
复制代码

11、引入接口文件暴露到全局

11.1 在 main.js 里面引入接口暴露到全局'
// 接口暴露在全局
import { server } from './config/api'
Vue.prototype.\$server = server;
复制代码
//api.js
 export const server = { getContentMenu: (paramObj)=>fetch('/content/menu',paramObj),//内容详情查询 getContentListPort: (paramObj)=>fetch('/content/list/'+paramObj),//入口页面接口 getContentList:(paramObj)=>fetch('/content/list/'+paramObj),//内容详情查询 getPageviews:(paramObj)=>fetch('/webpage/1/view',paramObj)//流量统计接口 }  组件里面使用: ```js methods: { getPageviews() { var that = this; let params = { pageId: that.pageId, pageUrl: that.pageUrl, }; that.\$server.getPageviews(params).then(response => {}) } } 复制代码
11.2 axios 方法封装,整个 api.js
import axios from 'axios';
 axios.defaults.timeout = 5000; axios.defaults.baseURL =''; //填写域名  //http request 拦截器 axios.interceptors.request.use( config => { config.data = JSON.stringify(config.data); config.headers = { 'Content-Type':'application/x-www-form-urlencoded' } return config; }, error => { return Promise.reject(err); } );  //响应拦截器即异常处理 axios.interceptors.response.use(response => { return response }, err => { if (err && err.response) { switch (err.response.status) { case 400: console.log('错误请求') break; case 401: console.log('未受权,请从新登陆') break; case 403: console.log('拒绝访问') break; case 404: console.log('请求错误,未找到该资源') break; case 405: console.log('请求方法未容许') break; case 408: console.log('请求超时') break; case 500: console.log('服务器端出错') break; case 501: console.log('网络未实现') break; case 502: console.log('网络错误') break; case 503: console.log('服务不可用') break; case 504: console.log('网络超时') break; case 505: console.log('http版本不支持该请求') break; default: console.log(`链接错误${err.response.status}`) } } else { console.log('链接到服务器失败') } return Promise.resolve(err.response) })  /** * 封装get方法 * @param url * @param data * @returns {Promise} */  export function fetch(url,params={}){ return new Promise((resolve,reject) => { axios.get(url,{ params:params }) .then(response => { resolve(response.data); }) .catch(err => { reject(err) }) }) }  /** * 封装post请求 * @param url * @param data * @returns {Promise} */  export function post(url,data = {}){ return new Promise((resolve,reject) => { axios.post(url,data) .then(response => { resolve(response.data); },err => { reject(err) }) }) }  /** * 官网接口请求封装 * @param url * @param data * @returns {Promise} */  export const server = { getContentMenu: (paramObj)=>fetch('/content/menu',paramObj),//内容详情查询 getContentListPort: (paramObj)=>fetch('/content/list/'+paramObj),//入口页面接口 getContentList:(paramObj)=>fetch('/content/list/'+paramObj),//内容详情查询 getPageviews:(paramObj)=>fetch('/webpage/1/view',paramObj)//流量统计接口 }  复制代码

12、provide /inject 完美解决不跳转不闪动页面刷新

原理:此方法使用的是 v-if 来控制 router-view 的显示或隐藏,v-if 从 false 变为 true 时,vue 会从新渲染 router-view 区域,因此当参数变化时,只需让 v-if 从 true => false => true,就能实现页面刷新。

12.1 找到route-view

//App.vue <template> <div id="app"> <router-view v-if="isRouterAlive"/> </div> </template> <script> export default { name: 'App', provide() { return { reload: this.reload//调用reload方法 } }, data() { return { isRouterAlive: true//一开始router-view为true } },
  <span class="hljs-attr" style="line-height: 26px;">methods</span>: {
    reload() {
      <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">this</span>.isRouterAlive = <span class="hljs-literal" style="color: #008080; line-height: 26px;">false</span>
         <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">//在修改数据以后使用 $nextTick,则能够在回调中获取更新后的 DOM</span>
      <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">this</span>.$nextTick(<span class="hljs-function" style="line-height: 26px;"><span class="hljs-params" style="line-height: 26px;">()</span> =&gt;</span> {
        <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">this</span>.isRouterAlive = <span class="hljs-literal" style="color: #008080; line-height: 26px;">true</span>
      })
    }
  }
}
复制代码
复制代码<span class="hljs-attr" style="line-height: 26px;">methods</span>: { reload() { <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">this</span>.isRouterAlive = <span class="hljs-literal" style="color: #008080; line-height: 26px;">false</span> <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">//在修改数据以后使用 $nextTick,则能够在回调中获取更新后的 DOM</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">this</span>.$nextTick(<span class="hljs-function" style="line-height: 26px;"><span class="hljs-params" style="line-height: 26px;">()</span> =&gt;</span> { <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">this</span>.isRouterAlive = <span class="hljs-literal" style="color: #008080; line-height: 26px;">true</span> }) } } } 复制代码</script> 复制代码

12.2在页面操做
export default {
      name: 'newproduct',
      inject:['reload'],//在export default下面加上这一段
      method:{
        //调用App.vue下的this.reload()方法,来改变v-if的状态
        clickDiv(){//刷新按钮调用的方法
          this.reload()
        }
      }
复制代码

参考文档:如何实现 vue 中不跳转不闪动页面刷新?provide /inject 完美解决方案

十3、vue动态绑定 class

13.1 对象方法
:class="{ 'active': isActive }"
复制代码

13.2 判断是否绑定一个active

:class="{'active':isActive==-1}"  
或者
:class="{'active':isActive==index}"
复制代码
13.3绑定并判断多个
第一种(用逗号隔开)
:class="{ 'active': isActive, 'sort': isSort }"
复制代码
第二种(放在 data 里面)
:class="classObject"
data() {
 return {
  classObject: {
   active: true,
   sort: false
  }
 }
}
复制代码
第三种(使用 computed 属性)
:class="classObject"
data() {
  return {
   isActive: true,
   isSort: false
  }
 },
 computed: {
  classObject: function() {
   return {
    active: this.isActive,
    sort: this.isSort
   }
  }
 }
复制代码
13.4数组方法
1.单纯数组
:class="[isActive,isSort]"
复制代码
data() {
 return {
  isActive: 'active',
  isSort: 'sort'
 }
}
复制代码

数组与三元运算符结合判断选择须要的class 三元运算符后面的“:”两边的class须要加上单引号

:class="[isActive?'active':'']"
复制代码

或者

:class="[isActive==1?'active':'']"
复制代码

或者

:class="[isActive==index?'active':'']"
复制代码

或者

:class="[isActive==index?'active':'otherActiveClass']"
复制代码
13.5 数组对象结合动态判断

//前面这个 active 在对象里面能够不加单引号,后面这个 sort 要加单引号

:class="[{ active: isActive }, 'sort']"
复制代码

或者

:class="[{ active: isActive==1 }, 'sort']"
复制代码

或者

:class="[{ active: isActive==index }, 'sort']"
复制代码

应用于组件 若是直接在自定义组件中使用 class 或 :class,那么样式规则就会直接应在这个组件的根元素上。

<div id="app">
    <text-component :class="{'isStrong':isStrong}"></text-component>
</div>
复制代码
<script>
    Vue.component('text-component', {
        template: '<p class="content">不懂基因测序的学霸不是好的人工智能公司 CEO</p>'
    });
    var app = new Vue({
        el: '#app',
        data: {
            isStrong: true
        }
    });
</script>
复制代码

参考文档01 参考文档02

style三元表达式

<span v-bind:style="{'display':config.isHaveSearch ? 'block':'none'}" >动态绑定样式</span> 复制代码

参考文档

也可使用 v-bind:style 或 :style 直接给 HTML 元素绑定样式,它也有对应的对象语法与数组语法。

<div id="app">
    <div :style="border"></div>
</div>
复制代码
<script>
    var app = new Vue({
        el: '#app',
        data: {
            border:{
                border:'1px solid #00F',
                textShadow:'0 0 .3em gray'
            }
        }
    });
</script>
复制代码

由于 JS 属性不支持短横分隔命名,因此咱们这里使用 CSS 也支持的驼峰命名法。

参考文档

计算属性computed

例:反转字符串:
<div id="app">
  <p>原始字符串: {{ message }}</p>
  <p>计算后反转字符串: {{ reversedMessage }}</p>
</div>
复制代码
<script>
var vm = new Vue({
  el: '#app',
  data: {
    message: 'Runoob!'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})
</script> 复制代码

咱们可使用 methods 来替代 computed,效果上两个都是同样的,可是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会从新取值。而使用 methods ,在从新渲染的时候,函数总会从新调用执行。。换句话说,computed 是局部渲染,而 methods 是所有渲染 区别:

  • 1.methods是个方法,好比你点击事件要执行一个方法,这时候就用methods,
  • 2.computed是计算属性,实时响应的,好比你要根据data里一个值随时变化作出一些处理,就用computed。
  • 3.咱们能够将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是彻底相同的。然而,不一样的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会从新求值。这就意味着只要 message 尚未发生改变,屡次访问 reversedMessage 计算属性会当即返回以前的计算结果,而没必要再次执行函数。
  • 4.methods必须须要必定的条件去触发,而computed则不须要.
  • 5.computed依赖缓存,若是不须要常常变更的用computed,须要常常变更的用methods。若是你须要传参数,就用methods。

computed

computed 属性默认只有 getter ,不过在须要时你也能够提供一个 setter :

var vm = new Vue({
 el: '#app',
 data: {
  name: 'Google',
  url: 'http://www.google.com'
 },
 computed: {
  site: {
   // getter
   get: function() {
    return this.name + ' ' + this.url
   },
   // setter
   set: function(newValue) {
    var names = newValue.split(' ')
    this.name = names[0]
    this.url = names[names.length - 1]
   }
  }
 }
})
复制代码
// 调用 setter, vm.name 和 vm.url 也会被对应更新
vm.site = 'http://www.runoob.com';
document.write('name: ' + vm.name);
document.write('<br>');
document.write('url: ' + vm.url);
复制代码

从实例运行结果看在运行 vm.site = 'http://www.runoob.com'; 时,setter 会被调用, vm.name 和 vm.url 也会被对应更新。

十4、style样式绑定

class 与 style 是 HTML 元素的属性,用于设置元素的样式,咱们能够用 v-bind 来设置样式属性。 Vue.js v-bind 在处理 class 和 style 时, 专门加强了它。表达式的结果类型除了字符串以外,还能够是对象或数组。

14.1 class 属性绑定

咱们能够为 v-bind:class 设置一个对象,从而动态的切换 class:

<style>
.active {
    width: 100px;
    height: 100px;
    background: green;
}
</style>
复制代码
<div id="app">
  <div v-bind:class="{ active: isActive }"></div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
    isActive: true
  }
})
</script> 复制代码

例:text-danger 类背景颜色覆盖了 active 类的背景色:

方法一:在对象中传入更多属性用来动态切换多个 class 。
<style>
.active {
    width: 100px;
    height: 100px;
    background: green;
}
.text-danger {
    background: red;
}
</style>
复制代码
<div id="app">
  <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }">
  </div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
    isActive: true,
    hasError: true
  }
})
</script> 复制代码
方法二:直接绑定数据里的一个对象:
<style>
.active {
    width: 100px;
    height: 100px;
    background: green;
}
.text-danger {
    background: red;
}
</style>
复制代码
<div id="app">
  <div v-bind:class="classObject"></div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
    classObject: {
      active: true,
      'text-danger': true
    }
  }
})
</script> 复制代码
方法三:绑定返回对象的计算属性:
<style>
.active {
    width: 100px;
    height: 100px;
    background: green;
}
.text-danger {
    background: red;
}
</style>
复制代码
<div id="app">
  <div v-bind:class="classObject"></div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
  isActive: true,
  error: null
  },
  computed: {
    classObject: function () {
      return {
        active: this.isActive && !this.error,
        'text-danger': this.error && this.error.type === 'fatal',
      }
    }
  }
})
</script> 复制代码
方法四:数组语法
<style>
.active {
    width: 100px;
    height: 100px;
    background: green;
}
.text-danger {
    background: red;
}
</style>
复制代码
<div id="app">
    <div v-bind:class="[activeClass, errorClass]"></div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
    activeClass: 'active',
    errorClass: 'text-danger'
  }
})
</script> 复制代码

还可使用三元表达式来切换列表中的 class : errorClass 是始终存在的,isActive 为 true 时添加 activeClass 类:

<style>
.text-danger {
    width: 100px;
    height: 100px;
    background: red;
}
.active {
    width: 100px;
    height: 100px;
    background: green;
}
</style>
复制代码
<div id="app">
    <div v-bind:class="[errorClass ,isActive ? activeClass : '']"></div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
    isActive: true,
    activeClass: 'active',
    errorClass: 'text-danger'
  }
})
</script> 复制代码

style样式邦定

v-bind:style直接设置样式:

<div id="app">
    <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">菜鸟教程</div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
    activeColor: 'green',
    fontSize: 30
  }
})
</script> 复制代码

也能够直接绑定到一个样式对象:

<div id="app">
  <div v-bind:style="styleObject">菜鸟教程</div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
    styleObject: {
      color: 'green',
      fontSize: '30px'
    }
  }
})
</script> 复制代码

v-bind:style 可使用数组将多个样式对象应用到一个元素上:

<div id="app">
  <div v-bind:style="[baseStyles, overridingStyles]">菜鸟教程</div>
</div>
复制代码
<script>
new Vue({
  el: '#app',
  data: {
    baseStyles: {
      color: 'green',
      fontSize: '30px'
    },
    overridingStyles: {
      'font-weight': 'bold'
    }
  }
})
</script> 复制代码

参考文档

十5、vue组件参数传递:

Vue 组件间通讯包括:父子组件间通讯,兄弟组件间通讯以及模块之间通讯等。Vue 是数据驱动视图更新的框架, 因此对于 Vue 来讲组件间的数据通讯很是重要。Vue 实现组件间通讯有不少方式,今天我来给你们讲解一下父子组件间通讯:props 和$emit。

15.1.子组件向父组件传递参数;

image
image

子组件 A:

<template>
      <div class="childA-wrapper"> 子组件A </div>
    </template>
    <script> export default { data() { return { childA: '我是组件A传过来的值' } }, created: function() {}, mounted() { this.sendDataParent() }, methods: { sendDataParent() { // getChildDataA是在父组件on监听的方法 // 第二个参数this.childA是须要传的值 this.$emit('getChildDataA', this.childA) } } } </script>
 复制代码

子组件 B:

<template>
  <div class="childB-wrapper"> 子组件B </div>
</template>
 <script> export default { data() { return { childB:'我是组件B传过来的值' } }, created:function() { }, mounted(){ this.sendDataParent() }, methods: { sendDataParent() { // getChildDataB是在父组件on监听的方法 // 第二个参数this.childB是须要传的值 this.$emit('getChildDataB', this.childB) } } } </script>  复制代码

父组件:

<template>
        <div> <v-childA v-on:getChildDataA="getChildDataA"></v-childA> <v-childB v-on:getChildDataB="getChildDataB"></v-childB> <div>获取组件A传过来的值:{{childAValue}}</div> <div>获取组件B传过来的值:{{childBValue}}</div> </div>
    </template>
 <script> import childA from '@/components/childA.vue' import childB from '@/components/childB.vue' export default { data() { return { childAValue:'', childBValue:'', } }, methods: { getChildDataA(childA){ console.log(childA) this.childAValue=childA }, getChildDataB(childB){ console.log(childB) this.childBValue=childB } }, components: { 'v-childA': childA, 'v-childB': childB} } </script>  复制代码

15.二、父组件向子组件传递参数

image
image
父组件:
<template>
        <div> <v-childA></v-childA> <v-childB :sendBData="sendB"></v-childB> </div>
    </template>
 <script> import childA from '@/components/childA.vue' import childB from '@/components/childB.vue' export default { data() { return { sendB:'父组件向B组件传递的参数' } }, methods: { }, components: { 'v-childA': childA, 'v-childB': childB} } </script>  复制代码
子组件 B:
<template>
  <div class="childB-wrapper"> 子组件B:{{sendBData}} </div>
</template>
<script> export default { data() { return {} }, created: function() {}, mounted() {}, methods: {}, props: { sendBData: String, required: true } }  </script>  复制代码

15.三、非父子组件进行传值;

image
image
bus.js
import Vue from 'vue'
  export default new Vue()
 复制代码
组件 childB:
<template>
    <div class="childB-wrapper"> </div>
  </template>
  <script> import Bus from '@/common/bus.js' export default { data() { return { childB: '我是组件B的内容' } }, created: function() {}, mounted() { this.elementByValue() }, methods: { elementByValue: function () { Bus.$emit('val', this.childB) } } }  </script> 复制代码
##### 组件 childA:
 <template> <div class="childA-wrapper"> A组件:<span>{{childB}}</span> </div> </template> <script> import Bus from '@/common/bus.js' export default { data() { return { childB: '' } }, created: function() {}, mounted() { var that = this // 用 $on事件来接收参数 Bus.$on('val', (data) => { console.log(data) that.childB = data }) } }  </script> 复制代码

更多请查看:你不知道的vue组件传值方式

16.vue脚手架配置预渲染,prerender-spa-plugin 配置

用到插件:cnpm install prerender-spa-plugin --save 脚手架 2.0:(本身的是 2.0)

16.1 build/webpack.prod.conf.js 配置
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
const webpackConfig = merge(baseWebpackConfig, {
 plugins: [
  // vue-cli 生成的配置就有了
  new HtmlWebpackPlugin({
   filename: config.build.index,
   template: 'index.html',
   inject: true,
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
   },
   chunksSortMode: 'dependency'
  }),
  // 配置 PrerenderSPAPlugin
  new PrerenderSPAPlugin({
   // 生成文件的路径,也能够与 webpakc 打包的一致。
   staticDir: path.join(\_\ _dirname, '../dist'),
 // 对应本身的全部路由文件,好比 index 有参数,就须要写成 /index/param1。这个其实不须要;千万不要加'/'这个 嵌套路由得 commonquestion 直接写便可 routes: ['index', '...', '/commonQuestion', '/commonQuestion/questionList', '/commonQuestion/questionDetailInfo'], // ; renderer: new Renderer({ inject: { // 可选;最好仍是用 foo: 'bar' }, headless: false, // 可选;最好用 renderAfterTime: 5000, // 经过实践是必选 官网说可选有误 必定要必选 renderAfterDocumentEvent: 'render-event' // 可选;最好用 }) }), ] }) 复制代码
16.2.路由得 index.js 添加属性:
​ mode:‘history’,
复制代码
修改config/index.js 中的build的 assetsPublicPath: ‘/’ ;否则会致使刷新页面路径错乱致使样式或者js丢失;
 修改main.js  new Vue({ el: '#app', router, store, // 若是须要了切记引入啊 切记须要挂载的所有挂载上去 render: h => h(App), mounted () { document.dispatchEvent(new Event('render-event')) } }) 复制代码
16.3.build/webpack.prod.conf.js 配置
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
const path = require('path');
module.exports = {
 configureWebpack: config => {
  if (process.env.NODE_ENV !== 'production') return;
  return {
   plugins: [
    new PrerenderSPAPlugin({
     // 生成文件的路径,也能够与 webpakc 打包的一致。
     // 下面这句话很是重要!!!
     // 这个目录只能有一级,若是目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。
     staticDir: path.join(\_\ _dirname, 'dist'),
     // 对应本身的路由文件,好比 a 有参数,就须要写成 /a/param1。
     routes: ['/', '/product', '/about'],
     // 这个很重要,若是没有配置这段,也不会进行预编译
     renderer: new Renderer({
      inject: {
       foo: 'bar'
      },
      headless: false,
      renderAfterTime: 5000, // 必选哈
      // 在 main.js 中 document.dispatchEvent(new Event('render-event')),二者的事件名称要对应上。
      renderAfterDocumentEvent: 'render-event'
     })
    }),
   ],
  };
 }
}
复制代码
16.4 main.js 配置
new Vue({
 router,
 store,
 render: h => h(App),
 mounted() {
  document.dispatchEvent(new Event('render-event'))
 }
}).\$mount('#app')
复制代码

其余修改同 2.0;

参考文档

十6、vue SPA单页面的 SEO 优化

vue-meta-info 
复制代码

官方地址: monkeyWangs/vue-meta-info

1.安装
npm install vue-meta-info --save
复制代码
2.全局引入 vue-meta-info
import Vue from 'vue'
import MetaInfo from 'vue-meta-info'
 Vue.use(MetaInfo) 复制代码
3.组件内静态使用 metaInfo
<template>
  ...
</template> 复制代码
<script>
  export default {
    metaInfo: {
      title: 'My Example App', // set a title
      meta: [{                 // set meta
        name: 'keyWords',
        content: 'My Example App'
      }]
      link: [{                 // set link
        rel: 'asstes',
        href: 'https://assets-cdn.github.com/'
      }]
    }
  }
</script> 复制代码
4.若是你的 title 或者 meta 是异步加载的,那么你可能须要这样使用
<template>
  ...
</template> 复制代码
<script>
  export default {
    name: 'async',
    metaInfo () {
      return {
        title: this.pageName
      }
    },
    data () {
      return {
        pageName: 'loading'
      }
    },
    mounted () {
      setTimeout(() => {
        this.pageName = 'async'
      }, 2000)
    }
  }
</script> 复制代码
<meta name="参数" content="具体的描述">
复制代码
5.meta标签共有两个属性,分别是http-equiv属性和name属性
  1. name 属性 name 属性主要用于描述网页,好比网页的关键词,叙述等。与之对应的属性值为 content,content 中的内容是对 name 填入类型的具体描述,便于搜索引擎抓取。 meta 标签中 name 属性语法格式是:
<meta name="参数" content="具体的描述">
复制代码

其中 name 属性共有如下几种参数。(A-C 为经常使用属性)

A. keywords(关键字)

说明:用于告诉搜索引擎,你网页的关键字。

<meta name="keywords" content="XX网,汽车,车主,评选">
复制代码
B. description(网站内容的描述)
说明:用于告诉搜索引擎,你网站的主要内容。
复制代码
<meta name="description" content="汽车评选,XX网,评选,汽车">
复制代码
C.viewport(移动端的视口)

说明:这个属性经常使用于设计移动端网页。

举例

<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
复制代码
D. robots(定义搜索引擎爬虫的索引方式)
说明:robots 用来告诉爬虫哪些页面须要索引,哪些页面不须要索引。
content 的参数有 all,none,index,noindex,follow,nofollow。默认是 all。
复制代码

举例:

<meta name="robots" content="none">
复制代码

具体参数以下:

1.none : 搜索引擎将忽略此网页,等价于 noindex,nofollow。
2.noindex : 搜索引擎不索引此网页。
3.nofollow: 搜索引擎不继续经过此网页的连接索引搜索其它的网页。
4.all : 搜索引擎将索引此网页与继续经过此网页的连接索引,等价于 index,follow。
5.index : 搜索引擎索引此网页。
6.follow : 搜索引擎继续经过此网页的连接索引搜索其它的网页。
复制代码
E. author(做者)

说明:用于标注网页做者 举例:

<meta name="author" content="Lxxyx,841380530@qq.com">
复制代码
F. generator(网页制做软件)

说明:用于标明网页是什么软件作的 举例: (不知道能不能这样写):

<meta name="generator" content="Sublime Text3">
复制代码
G. copyright(版权)

说明:用于标注版权信息 举例:

<meta name="copyright" content="Lxxyx"> //表明该网站为Lxxyx我的版权全部。
复制代码
H. revisit-after(搜索引擎爬虫重访时间)

说明:若是页面不是常常更新,为了减轻搜索引擎爬虫对服务器带来的压力,能够设置一个爬虫的重访时间。若是重访时间太短,爬虫将按它们定义的默认时间来访问。 举例:

<meta name="revisit-after" content="7 days" >
复制代码
I. renderer(双核浏览器渲染方式)

说明:renderer 是为双核浏览器准备的,用于指定双核浏览器默认以何种方式渲染页面。好比说 360 浏览器。 举例:

<meta name="renderer" content="webkit"> //默认webkit内核
<meta name="renderer" content="ie-comp"> //默认IE兼容模式
<meta name="renderer" content="ie-stand"> //默认IE标准模式
复制代码
6. http-equiv 属性

http-equiv 至关于 HTTP 的做用,好比说定义些 HTTP 参数啥的。 meta 标签中 http-equiv 属性语法格式是:

<meta http-equiv="参数" content="具体的描述">
复制代码

其中 http-equiv 属性主要有如下几种参数:

A. content-Type(设定网页字符集)(推荐使用 HTML5 的方式)

说明:用于设定网页字符集,便于浏览器解析与渲染页面 举例:

<meta http-equiv="content-Type" content="text/html;charset=utf-8">  //旧的HTML,不推荐
<meta charset="utf-8"> //HTML5设定网页字符集的方式,推荐使用UTF-8 复制代码
B. X-UA-Compatible(浏览器采起何种版本渲染当前页面)

说明:用于告知浏览器以何种版原本渲染页面。(通常都设置为最新模式,在各大框架中这个设置也很常见。) 举例:

<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> //指定IE和Chrome使用最新版本渲染当前页面
复制代码
C. cache-control(指定请求和响应遵循的缓存机制)

用法 1.

说明:指导浏览器如何缓存某个响应以及缓存多长时间。这一段内容我在网上找了好久,但都没有找到满意的。 最后终于在 Google Developers 中发现了我想要的答案。

举例:

<meta http-equiv="cache-control" content="no-cache">
复制代码

共有如下几种用法:

  • no-cache: 先发送请求,与服务器确认该资源是否被更改,若是未被更改,则使用缓存。
  • no-store: 不容许缓存,每次都要去服务器上,下载完整的响应。(安全措施)
  • public : 缓存全部响应,但并不是必须。由于 max-age 也能够作到相同效果
  • private : 只为单个用户缓存,所以不容许任何中继进行缓存。(好比说 CDN 就不容许缓存 private 的响应)
  • maxage : 表示当前请求开始,该响应在多久内能被缓存和重用,而不去服务器从新请求。例如:max-age=60 表示响应能够再缓存和重用 60 秒。 参考连接:HTTP 缓存 用法 2.(禁止百度自动转码)

说明:用于禁止当前页面在移动端浏览时,被百度自动转码。虽然百度的本意是好的,可是转码效果不少时候却不尽人意。因此能够在 head 中加入例子中的那句话,就能够避免百度自动转码了。 举例:

<meta http-equiv="Cache-Control" content="no-siteapp" />
复制代码
D. expires(网页到期时间)

说明:用于设定网页的到期时间,过时后网页必须到服务器上从新传输。 举例:

<meta http-equiv="expires" content="Sunday 26 October 2016 01:00 GMT" />
复制代码
E. refresh(自动刷新并指向某页面)

说明:网页将在设定的时间内,自动刷新并调向设定的网址。 举例:

<meta http-equiv="refresh" content="2;URL=http://www.lxxyx.win/"> //意思是2秒后跳转向个人博客
复制代码
F. Set-Cookie(cookie 设定)

说明:若是网页过时。那么这个网页存在本地的 cookies 也会被自动删除。

<meta http-equiv="Set-Cookie" content="name, date"> //格式
<meta http-equiv="Set-Cookie" content="User=Lxxyx; path=/; expires=Sunday, 10-Jan-16 10:00:00 GMT"> //具体范例
复制代码
相关文章
相关标签/搜索