⭐️ ? ✨ ⚡️

技术栈

# vue官网http://vuejs.org/

# Vuex中文手册 http://vuex.vuejs.org
#  Vue-Router 手册 http://router.vuejs.org 

# 最全Vue资源大全https://github.com/opendigg/awesome-github-vue
# vue-devtool 调试vue必备chrome工具https://github.com/vuejs/vue-devtools

# vue + typescripthttps://github.com/HerringtonDarkholme/vue-ts-loader

# webpack2 中文文档http://www.css88.com/doc/webpack2/guides/code-splitting-require/

# Vuejs 实用技巧https://zhuanlan.zhihu.com/p/25589193

# Vue.js 实用技巧(二)https://zhuanlan.zhihu.com/p/25623356

# 饿了么基于Vue 2.0的通用组件库开发之路https://mp.weixin.qq.com/s?__biz=MzIwNjQwMzUwMQ==&mid=2247484467&idx=1&sn=8643c5945adb151db9c6fe757cd6adfa&chksm=972366f1a054efe733e01069b2adb81d453a2c30bbc5329c77948e8160090294bf14918381a1&scene=21#wechat_redirect

⭐️ ? ✨ ⚡️ Vue最好的UI库

# PC端http://element.eleme.io/

# 移动端https://github.com/ElemeFE/mint-ui

第三方插件收集:

# vue-lazyload 一个简单易用的 Vue 图片延迟加载插件
https://github.com/hilongjw/vue-lazyload?from=gold
# 表单验证插件https://github.com/QingWei-Li/vuerify

# 前端国际化https://github.com/kazupon/vue-i18n

# swpier强大且令人羡慕的拖拽组件https://github.com/surmon-china/vue-awesome-swiper 

安装

注意 :由于部分模块是需要跨域才能下载,所以这里需要使用cnpm install,cnpm是淘宝版本的npm,需要另外下载:http://www.cnblogs.com/CyLee/p/5719929.html

# 全局安装 vue-cli
$ npm install -g vue-cli# 创建一个基于 "webpack" 模板的新项目,注意,Use ESLint to lint your code? (Y/n) n
$ vue init webpack my-project# 安装依赖,走你
$ cd my-project# 使用cnpm进行安装
$ cnpm install
# 运行,并且自动进入热编译
$ npm run dev

端口可以在config/index.js 中修改

我们启动页看到的文件源代码是:src/App.vue

在build/webpack.base.conf.js 中搜索 jsLint 关键词注释掉相关的代码即可关闭 jsLint 代码严格模式

Vuejs不兼容低版本浏览器,比如IE8、360浏览器兼容模式等


神坑与碎片化知识点记录

86、watch route 无法生效的原因?

可能是因为父子路由的原因吧。建议用以下几个方案代替:

watch: {'$route': {deep: true,handler (newV, oldV) {this.$store.dispatch('Map/reset')}}
},2、如果还是不行的话,用路由钩子:beforeRouteEnter (to, from, next) {next(vm => {if (from.path === '/myBusiness') vm.$router.push('/')next()})
}// 页面离开的时候,初始化一些参数配置
beforeRouteLeave  (to, from, next) {// 还原为全部选择框都显示this.$store.dispatch('list/onlyShowSelect')// 取消问题类型,默认为空this.$store.dispatch('list/eq_problemType')next();
},

85、vue编译插件,可以发布给人使用

$ vue-cli-service build --target lib --name w-basic-layout --dest lib packages/index.js

"scripts": {
  "lib": "vue-cli-service build --target lib --name w-basic-layout --dest lib packages/index.js"
},

84、vuex 如果要dispatch另一个模块的actions时怎么办? 只需要加入 {root: true} 即可

dispatch('Map/fuck', 'shit', {root: true})

83、vue 关于deep watch / computed 监听不到 vuex state 对象变化的的问题

// 超简易拷贝(如果是深拷贝还多此一举把get/set拷贝进去了,所以用简易拷贝即可)
let __VALUE__ = JSON.parse(JSON.stringify(state.problemReply))
// 加入部门回复详情
__VALUE__[orderId] = data.problemReply
// 更新,只能这样一波骚操作才能让computed和watch监听到。具体原因我稍后学习o(╥﹏╥)o。
state.problemReply = __VALUE__

82、 如何在index.html加载本地js文件?

将文件放置在 /static 中 ,编译的时候会一同打包在dist/static/ 中,所以你就可以在index.html中使用

<script src="./static/echarts.min.js"></script>

81、深度作用选择器:https://vue-loader-v14.vuejs.org/zh-cn/features/scoped-css.html

vue组件会为template中的每个html元素加入 [data-v-xxxx] 属性来确保 css 作用本组件而不会污染全局,而如果你引用了第三方组件,默认只会对组件的最外层(div)加入这个属性,但第二层开始就没有效果了。如图所示: 第一层还有 data-v-17bb9a05, 但第二层的 .weui-cells 就没有了。

如果你希望通过如下方式修改 weui-cells。是没有效果的

<style scoped>.fuck .weui-cells {// ...}
</style>

除非你将scoped移出。或者新建一个没有scoped的style(一个.vue文件允许多个style)。这是因为,所有的scoped中的css最终编译出来都会变成这样:

.fuck[data-v-17bb9a05] .weui-cells[data-v-17bb9a05]

解决方法还有另一个,那就是深度作用选择器:

重要的事情说三遍,如果你是scss之类的预编译css的话, >>> 要换成 /deep/

重要的事情说三遍,如果你是scss之类的预编译css的话, >>> 要换成 /deep/

重要的事情说三遍,如果你是scss之类的预编译css的话, >>> 要换成 /deep/

80、mapState的使用。其中 theme 是模块名。当然也可以忽略。

import { mapState } from 'vuex'computed: {...mapState('theme', ['findLastSixMonthAir', 'findLastSixMonthAirTown'])
},

79、computed + watch + vuex的组合,虽然一时爽,但也有问题,就是数据嵌套的太深的时候,没办法更新UI。又不可以用$set方案来解决。

但也有办法,那就是深拷贝赋值,然后在某一层赋值,还是可以更新UI的。

// 超简易拷贝(如果是深拷贝还多此一举把get/set拷贝进去了,所以用简易拷贝即可)
const v = JSON.parse(JSON.stringify(state.list.data))
// 加入回复字段
v[index].problemReply = data.problemReply
// 更新,只能监听到data属性,所以必须这样操作。不能这样:  state.list.data[index].problemReply = data.problemReply
state.list.data = v

78、由于一些嵌套特别深的数据,导致数据更新了。UI没有更新,我捉摸着有没有和react一样的立即更新UI的API呢 this.forceUpdate()呢?结果还真有:

this.$forceUpdate();

77、使用<el-select>时使用它的事件@change,一边我又想拿到组件给我的回调,一边又想自己加入参数,所以就需要这样写了:

@change="(data) => childCheckbox(data,index, item)" 

76、ElementUI 组件在 非.vue文件的使用,譬如router.js 文件中

import { Message  } from 'element-ui';Message('这是一条信息 );

75、props如何双向属性绑定?

74、vue 中使用scoped关键字后样式不能修改第三方组件问题

https://blog.csdn.net/mr_hexs/article/details/80375244

73、vue动画的使用。

https://cn.vuejs.org/v2/guide/transitions.html

.cell-enter-active, .cell-leave-active {transition: all 1s;
}
/* 新成员进入时的动画 */
.cell-enter, .cell-leave-to /* .cell-leave-active below version 2.1.8 */ {/*opacity: 0;*/transform: translateY(300px);
}/* 所有项移动时的动画钩子 */
.cell-move {transition: transform 1s ease;
}<transition-group name="cell" tag="div" class="transition-group"><div v-for='(item, index) in items' :key='item' class="cell">{{ item.title }}</div>
</transition-group>

72、史诗级的神坑:v-for循环中,我习惯这样使用index:v-for='(item, index) in items' :key='index'

当我对items数组的前面插入数据时:

this.items.unshift({title: '重大事件', time: '2018.08.08 10:00', content: '涡领商业西街食物中毒', num: '1'})

由于加入了transition-group 动画,我可以很清楚的看见插入的动画效果,却一直是push的效果。后来查看官方demo,才发现这个:key需要这样设置:

v-for='(item, index) in items' :key='item'

71、v-cloak 用来解决渲染之前的尴尬期

https://segmentfault.com/a/1190000008819667

70、vue v-model 与 组件化的表单组件如何沟通

参考mint-ui的代码:

https://github.com/ElemeFE/mint-ui/blob/master/packages/radio/src/radio.vue

https://github.com/ElemeFE/mint-ui/blob/master/packages/field/src/field.vue

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>Document</title><script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script><style></style><body><div id="app"><div v-for='(item, index) in items' :key='index'><myradio v-model="picked" :text="item"></myradio></div><br><span>Picked: {{ picked }}</span></div></body><script>// 局部注册组件var myradio = Vue.extend({data: function () {return {currentValue: this.value}}, props: {value: '',text: ''},     template: `<label><input type="radio" id="two" :value="text" v-model="currentValue"><label for="two">{{ text }}</label></label>
              `,watch: {value(val) {this.currentValue = val;},currentValue(val) {this.$emit('input', val);}}});Vue.component('myradio', myradio)new Vue({el: '#app',data: {picked: 'Three',items: ['One', 'Two', 'Three']}})</script></html>

69、input 聚焦的时候键盘盖住

function getElementTop(element){try {var actualTop = element.offsetTop;var current = element.offsetParent;while (current !== null){actualTop += current.offsetTop;current = current.offsetParent;}return actualTop;} catch (e) {}}setTimeout(() => {window.scrollTo(0, getElementTop(e.target));
}, 150)

68、注册全局指令

https://cn.vuejs.org/v2/guide/custom-directive.html

// v-auth 全局权限指令,但暂时没有想好怎么处理
Vue.directive('auth', {inserted: function (el, node) {// 从 store 中获取权限信息var auth = store.state.auth.authInfo// 遍历权限列表for (var i = 0; i < auth.length; i++) {// 如果符合条件,那么就把它删除if (auth[i].resContent === node.value) {// 删除元素return el.parentNode.removeChild(el)}}}
})

67、新的错误出现:Module build failed: Error: No parser and no file path given, couldn't infer a parser.

https://segmentfault.com/q/1010000015052538

运行:npm i prettier@~1.12.0

66、Vue自带的错误捕获机制

https://cn.vuejs.org/v2/api/#errorHandler

Vue.js 2.2.0+提供了 errorHandler, (一般在src目录的main.js文件中配置)

Vue.config.errorHandler = function(err, vm, info) {console.log(err, vm, info);
};

65、fetch中response.json()的问题

1、你不能连续使用两次response.json(),否则会报错

2、你不能直接在promise中打印出console.log(response.json()),打印不出的。所以你必须这样

var json = response.json()
json.then(_=>{ console.log(_) })
return json

64、webpack-dev-server 无法通过ip访问的问题

http://www.cnblogs.com/CyLee/p/8376648.html

63、路由的限制和next的问题。

 if (needLoginPage.indexOf(to.fullPath.replace(/\/|\\/g, '').toLocaleLowerCase().trim()) >= 0 && !store.state.token) {// 史诗级神坑,这里必须先next,否则会一直返回不了,// 不要问我为什么,我猜测是,由于你缺少了一次next,一直卡着不给后退。所以这里无论如何也需要next一下.Toast('请先登录')// next()// 设置去路return store.dispatch('set_wantTo', to.path).then(_ => {// 跳转到登录页router.push('/login')// 继续渲染它?return next()})
}

62、分享一个小技巧,如果项目迁移、而node_modules迁移有问题,项目启动不了的时候,可以选择完全删除node_modules。然后重点来了

不要使用window内置的powser shell,而是使用一些高亮的shell工具如cmder。执行cnpm install试试。如果还是不行,继续重复删掉node_modules,反复执行cnpm install。记得要用cmder哦

61、学完局部注册和全局注册的差别后,你再看看main.js的new Vue代码,你应该懂得了

这是因为:你的入口main.js中,仅仅注册了一个全局组件App.vue,

并且渲染在模板上


绑定在html上的一个叫#app的元素上
也就是说,你的所有组件,都是在App.vue下活动的子组件。

而子组件的切换,是通过url来切换的?如何切换呢?是通过路由来监听切换的

基本上就是这样的原理

60、Vue warn]: Do not use built-in or reserved HTML elements as component id: button

将组件的name属性从button改为mybutton即可。

export default {name: 'mybutton',// ...
}   

59、webpack 使用别名(resolve.alias)解决scss @import相对路径导致的问题

58、vue 更新了vue-cli到最新版本后引发的问题: require和import、vue-loader的问题

结局:vue-loader@13.X 降级到 vue-loader@12.X 即可解决

57、手动挂载$mount()

如果没有挂载的话,没有关联的 DOM 元素。是获取不到$el的。

https://vuejs.org/v2/api/#vm-mount

var MyComponent = Vue.extend({template: '<div>Hello!</div>'
})// create and mount to #app (will replace #app)
new MyComponent().$mount('#app')// the above is the same as:
new MyComponent({ el: '#app' })// or, render off-document and append afterwards:
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)

56、销毁组件

// get~ 销毁组件
destroyElement() {this.$destroy(true);this.$el.parentNode.removeChild(this.$el);
},

55、vue.extend 局部注册 的应用2

请注意,extend创建的是一个组件构造器,而不是一个具体的组件实例。所以他不能直接在new Vue中这样使用: new Vue({components: fuck})

最终还是要通过Vue.components注册才可以使用的。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>在Vue中注册组件</title>
</head>
<body>
<div id="app"><todo :todo-data="groceryList"></todo>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue " type="text/javascript"></script>
<script>
/*** 请注意,extend创建的是一个组件构造器,而不是一个具体的组件实例。* 所以他不能直接在new Vue中这样使用: new Vue({components: fuck})* 最终还是要通过Vue.components注册才可以使用的。 */// 构建一个子组件
var todoItem = Vue.extend({template: ` <li> {{ text }} </li> `,
    props: {text: {type: String,default: ''}}
})// 构建一个父组件
var todoWarp = Vue.extend({template: `<ul><todo-item v-for="(item, index) in todoData"v-text="item.text"></todo-item></ul>
    `,props: {todoData: {type: Array,default: []}},// 局部注册子组件
    components: {todoItem: todoItem}
})// 注册到全局
Vue.component('todo', todoWarp)new Vue({el: '#app',data: {groceryList: [{ id: 0, text: '蔬菜' },{ id: 1, text: '奶酪' },{ id: 2, text: '随便其它什么人吃的东西' }]}
})
</script>
</html>

54、vue.extend 局部注册 的应用1

请注意,在实例化extends组件构造器时,传入属性必须是propsData、而不是props哦

另外,无论是Vue.extend还是Vue.component 里面的data定义都必须是函数返回对象,如 Vue.extend({data: function () {return {}}})。除了new Vue可以直接对data设置对象之外吧,如 new Vue({data: {}});

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>在Vue中注册组件</title>
</head>
<body>
<div id="todoItem"></div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue" type="text/javascript"></script>
<script>// 局部注册组件
var todoItem = Vue.extend({data: function () {return {todoData: [{ id: 0, text: '蔬菜' },{ id: 1, text: '奶酪' },{ id: 2, text: '随便其它什么人吃的东西' }]}},template: `<ul><li v-for='(d, i) in todoData' :key="i">{{ d.text }}</li></ul>
  `
});// 请注意,在实例化extends组件构造器时,传入属性必须是propsData、而不是props哦
new todoItem({propsData: {todoData: [{ id: 0, text: '蔬菜' },{ id: 1, text: '奶酪' },{ id: 2, text: '随便其它什么人吃的东西' }]}
}).$mount('#todoItem')</script>
</html>

53、Vue的实例属性

52、从来没使用过 <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script> 的使用方式。

一直都是工程化来开发的。现在也开始使用一下吧。

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title><script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script><script src="./Components/Counter.js"></script>
</head>
<body><div id="app"><p>总数量: {{ total }}</p><counter @add="handleGetTotal" @reduce="handleGetTotal"></counter></div>
</body>
<script>new Vue({el: '#app',data: {total: 0},methods: {handleGetTotal: function (v) {this.total = v;}}})
</script>
</html>

Components/Counter.js

Vue.component('counter', {template: `<div><button type="button" @click="handleAddNum">+</button><button type="button" @click="handleReduceNum">-</button></div>
        `,data: function () {return {counter: 0}},methods: {handleAddNum: function (){this.counter++;this.$emit('add', this.counter);},handleReduceNum: function (){this.counter--;this.$emit('reduce', this.counter);}}
})

51、enter事件,经常用但经常忘记。还是记录一下把

@keyup.enter="enterHandle"

50、简单的知识点,如何调用子组件的函数Methods

答案就是使用ref即可。

<countdown  ref="countdown"></countdown>beforeDestroy () {// 切换页面时消灭计时器this.$refs.countdown.clearTimer()
}

49、使用vue-cli 配置 proxyTable 代理地址,实现跨域问题

路径在/config/index.js 中,找到dev.proxyTable。如下配置示例:

    proxyTable: {'/api': {// 我要请求的地址target: 'http://oatest.bujidele.com:8010/apitest/api/tydproject/doOld/',  //是否跨域 changeOrigin: true, // 重写地址
            pathRewrite: {'^/api': '/'}}}

那么当我们请求 http://localhost:8888/api/ 的时候,就等于请求了 http://oatest.bujidele.com:8010/apitest/api/tydproject/doOld/

请注意上面的【pathRewrite】字段。这是什么意思呢。

我们再来看看下面的例子

 proxyTable: {'/api': {// 我要请求的地址target: 'http://192.168.14.29:31006/xindai/',  //是否跨域 changeOrigin: true, // 重写地址
           pathRewrite: {'^/api': '/api'}}},

如果是这样的话,当我们请求/api的时候,就等于请求了http://192.168.14.29:31006/xindai/api

这要看你要不要了,如果不要的话,直接换为'^/api': '/' 就好了

48、获取组件自己在父组件中的索引。

内置属性即可。this.index 。

随便一提这些内置的属性应该多记一点,譬如this.$parent.xxxx 这些都是很实用的

47、通过js新建组件并且传入props:

import Vue from 'vue';
import product from './index.vue';let productComponent = Vue.extend(product);export default (food, isShow, idx, ratings) => {new productComponent({el: '#goodss',propsData: {food,isShow,idx,ratings}});
}

46、axios 加入header之后,请求出现

Failed to load http://localhost:8080/team.php: Request header field x-jwt-header is not allowed by Access-Control-Allow-Headers in preflight response.

//POST传参序列化(添加请求拦截器)
axios.interceptors.request.use(config => {config.headers['x-jwt-header'] = localStorage.tokenreturn config;
},error =>{alert("错误的传参", 'fail')return Promise.reject(error)
})

原因是后端没有开启对header的允许。php中输入以下代码即可:

header('Access-Control-Allow-Headers:x-jwt-header,content-type'); 

45、webpack 打包压缩 ES6文件报错UglifyJs + Unexpected token punc (();  或者 Unexpected token: operator (>)

解决方案就是将babel配置转义到 .babelrc 文件中。具体做法是在根目录新建 .babel,输入

{"presets": ["es2015"]
}

在webpack加载babel-loader的时候会自动加载.babelrc配置的。

44、如果不能看到源码来修复bug真心累。除非是通过场景重现的bug。否则定位不到错误行很惨。所以需要开启map。

在 /config/index.js 中,修改 productionSourceMap 为 true 即可。

43、尽管加入了babel-polyfill ,依然出现 【ReferenceError: Promise is not define】的问题。目前只在三星、金立手机出现这种问题。没办法,只能强行修复了。

npm install promise --save-devwindow.Promise = require('promise');

记得清除一下手机的缓存。

42、记一起和前端没什么卵关系的后端405问题

问题的关键点在于本来是POST请求,会变成OPTION请求,并且提示405报错,会类似跨域。并且只有某些手机机型才会(如Oppo系列)。

其实跨域的问题,如果在PHP只需要在头设置允许跨域即可。其他语言也类似。

header("Access-Control-Allow-Origin:*");
或者
header("Access-Control-Allow-Origin:url地址");

但.net据说也设置大致如上设置了,却不能轻易跨域,在开发环境中我甚至需要开启代理或浏览器非安全模式才可以跨域。

直到今天这个问题在线上彻底爆发出来。才认真研究。其原因就在于.net web.conf配置中,需要注释或删除这一句配置:

<remove name="OPTIONSVerbHandler" />

于是具体配置大致如下:

<handlers><remove name="ExtensionlessUrlHandler-Integrated-4.0" /><!--<remove name="OPTIONSVerbHandler" />--><remove name="TRACEVerbHandler" /><add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /></handlers><httpProtocol><customHeaders><add name="Access-Control-Allow-Origin" value="*" /><add name="Access-Control-Allow-Methods" value="*" /><add name="Access-Control-Allow-Headers" value="Content-Type" /></customHeaders></httpProtocol>

问题即可解决。无论线上和本地都可以顺利跨域了。其实就是个跨域的问题罢了,记录一下

41、记一次饿了么UI图标加载无效的问题。并且提示错误

Failed to decode downloaded font:

很显然,问题在于webpack的loader中。检查了一下发现有两个相同的file-loader的配置,删除其中一个即可。

40、记一次编译没反应、无进度、没有任何报错的提示,但后台却TM一直消耗内存的BUG:

控制台一直提示“building for production...”,而且spinner停止了动画!

由于没有任何的提示。况且项目的代码、结构、设计完全未知模糊的情况下,我只能按照unix的理念“使之运行、使之正确、使之快速”作为理论依据指导我来调试了。

按照这个理念,我最初设定的目标,就是让他正常的编译,无论结果是如何。所以我将main.js(入口文件)的代码尽可能删掉。只保存纯洁无比的app.vue组件。以及vue的初始化。就这样运行编译,果然可行!!而后我通过按照二分法。一步一步还原并删减一半的代码,运行npm run build。一步一步尝试。直到定位到最小单元的文件(result.vue),在这个文件中只有三个剑客,分别是template、script、css。他们一样没有逃过我的魔爪,一步步的删减,直到最后定位到了是css文件的错误。一个css文件居然能引发这种史诗级的错误?通过继续对css文件中的css代码进行二分法删减,最后发现。怎么会有一个“|”符号?于是把它删除,正常编译!

结果和过程都是美好的。但我觉得我这种调试方式也值得记录。

39、组件 vue-awesome-swiper 的坑

1、在vertical的场景模式下,默认的高度很奇怪,非常非常的大。完全没有规律。后来使用autoHeight好了一点。但依然有问题,问题在于它会根据swiper-slide内元素的高度自动变化叠加。依然会非常非常大。最后才知道。手动设置height即可解决。由于我的场景是fullpage页面,所以只需要设置height : window.innerHeight 即可。完整代码如下:

swiperOption: {direction : 'vertical',height : window.innerHeight,onTransitionStart: function (swiper){this.isHideIcon = swiper.activeIndex <= 3;}.bind(this)
}

2、在拖拽的过程中,我还发现另一个bug。有时候拖拽边缘。会导致没有很好的弹性滚动,而是像普通页面一样滑动导致错误了。后来检查才发现,是因为你手势滑动的区域不是<swiper>元素覆盖的范围导致的。解决方案很简单,整个页面都让swiper覆盖即可。保证用户触碰的是swiper元素本身,而不是body、或者其他div元素

39、默认Vue-cli脚手架的工程,npm run build之后的工程是必须部署在服务器根目录中的,只能用类似localhost:8080/#/来访问。原因是资源的路径读取都是以根目录'/',所以我们只需要修改静态资源的路径即可。打开工程目录中

/config/index.js

找到build属性中的assetsPublicPath,默认是“/” 修改为"./"即可

38、Error: [vuex] vuex requires a Promise polyfill in this browser. 与 babel-polyfill 的问题

事实上之前已经解决了。采用最笨重的解决方案就是npm install babel-polyfill 然后在webpack中如此设置:

entry: {'babel-polyfill': 'babel-polyfill',app: './src/main.js'
},

但在开发环境下,我们在IE11打开的时候依然有问题(但在现代浏览器中浏览居然没问题)。打开源码,可以看到是app.js先加载,然后才加载babel-polyfill. 其实在生产环境下(webpack编译之后)。可以正常运行。这是因为在webpack.prod.conf.js中的HtmlWebpackPlugin加入了 hunksSortMode: 'dependency' 属性。所以我们只要依样画葫芦。在webpack.dev.conf.js中找到HtmlWebpackPlugin加入了 hunksSortMode: 'dependency' 属性即可

37、(深度更新)好吧,其实36的理解是错误的,虽然解决了问题。但对于this.$set的理解是大错特错的。关键在于对vue的双向数据绑定太信赖而导致无视了原理。

https://segmentfault.com/a/1190000007787941?_ea=1459649

事实上,回忆一下我们在使用Vue的双向数据绑定的时候,我们首先需要在Data中配置属性,然后再绑定到template中。然后改变Data时,就会改变template。

但有没有经历过我这种情况,默认的Data的某个属性是空的,如 list: {}  我需要进行异步请求或者延迟操作之后,再给它赋值 list.fuck = 'fuck-Vue' 如果是这样的情况。你觉得template会更新么。

答案是否定的。这其实非常容易猜想到原因。Vue默认只会绑定Data中的数据,而你异步更新的Data。实质上只是更新了,但并没有绑定,所以template自然没有更新。那有没有解决方案呢?

有的。36的this.$set就是解决方案,它的作用是,添加绑定一个状态并且立刻更新template。也就是说,拿我的例子做说明,默认list: {} 当赋值的时候不再是单纯的this.list.fuck = 'fuck-Vue'; 而是 this.$set(this.list, 'fuck', 'fuck-vue');

这样即可解决,但需要注意一个问题: this.$set 不能添加或更新已有的属性,否则无效。什么意思呢?比如我的Data的list中,默认已经写有fuck这个属性了。如果你继续使用 this.$set(this.list, 'fuck', 'fuck-vue'); 则是无效的。

36、史诗级的知识点以及解决方案:一个复杂对象的变化,vue是不能监听到的,所以视图也不会随着改变?怎么办?

比如我有一个状态:

[{toggle: true, rotate: true},{toggle: false, rotate: false},{toggle: false, rotate: false}]

当然这个状态是通过api获取的。通过v-for渲染后,当我改变数组中其中一个对象的一个属性时:

this.Model[index].rotate= !this.Model[index].rotate

对象确实有改变,但视图不会更新。为什么? 详情阅读:https://cn.vuejs.org/v2/guide/reactivity.html

总之你只要知道,默认Vue是不能检测属性更新来刷新视图的。只有this.$set的方法来解决:https://cn.vuejs.org/v2/api/#Vue-set

methods: {slideupList (index) {this.Model[index].rotate= !this.Model[index].rotatethis.Model[index].toggle = !this.Model[index].toggle/*** 由于this.Model是对象数组,当其中一个对象变化的时候,vue不能监听到的,所以视图也不会刷新* this.$set 这个方法主要用于避开  Vue 不能检测属性更新的限制。* 但这个方法的使用需要注意几点:* - 我是对数组中的某个值(这个值是个对象),直接重新赋值的。* 如果我这里直接对数组的某个对象中的某个属性赋值,那是不行的。* https://cn.vuejs.org/v2/api/#Vue-set* http://www.cnblogs.com/zhuzhenwei918/p/6893496.html* */this.$set(this.Model, index, this.Model[index])}
}

35、如何监听Vuex的state?  通过Computed + watch的组合

 computed: {get_translateY() {return this.$store.state.translateY;}},watch: {get_translateY (val) {window.clearTimeout(this.Timer);this.isHeadAdd = true;this.hide = window.setTimeout(() => {this.isHeadAdd = false;}, 1000)}}

34、vue-router的keep-alive缓存策略

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

# 第三方手册http://www.jianshu.com/p/0b0222954483

# 官方手册https://vuejs.org/v2/api/#keep-alive

注意include不能有空格,如

<keep-alive include="carBusiness,houseBusiness">
    <router-view class="view"></router-view>
  </keep-alive>

33、vuex中mapState的概念是什么?有点懵逼???

其实就是重命名而已,为了可以减少你输入的键盘,详细可以看看这篇博客:

http://blog.csdn.net/a641832648/article/details/62233213

32、就凭这个坑,我相信typescript会替换babel

Cannot set property requestCount of #<Object> which has only a getter

场景这样的:使用了多个export + import * as xxx 组合,但属性只读

# state.js
// 异步请求的数量
export let fetchCount = 0
// translateX的监听器
export let translateX = 0
// translateY的监听器
export let translateY = 0
# index.js
import * as state from './state.js'
console.log(state)  // 你会发现这些属性只有getter没有seter。说明是只读的

原因是babel的配置中  .babelrc的presets属性中存在{ "modules": false }。移除就好了。

31、Vuejs的动画API更新换代了N次。不得不说我越来越欣赏和熟悉了。这要归功于完美用户体验的API手册。

下面这个demo是演示 animate.css 与 自定义transition 和 vuejs的API结合

<template><div id="app"><transition name="fuck"><div class="div" v-if='isShow'> </div></transition><button v-on:click="isShow = !isShow"> Toggle </button></div>
</template><script>
export default {name: 'app',data () {return {isShow: true}}
}
</script><style lang="scss" scoped>.div {height: 200px;width: 200px;background: red;}.fuck-enter-active{animation-duration: 1s;animation-fill-mode: both;animation-name: fuck;}.fuck-leave-to {opacity: 0}.fuck-leave-active {transition: opacity .5s}@keyframes fuck{from {opacity: 0;transform: translate3d(0, 100%, 0);}to {opacity: 1;transform: none;}}
</style>

30、可以使用@input 代替 watch

由于@input本身就是用来监听表单控件(input/select/radio等)的值变化,并且在@input事件的回调中,他的执行是比v-model被赋值快的,依赖这个特性可以代替watch的效果

<input v-model="test_model" @input="test" type='text' />

test (e) {// 你会发现不一样v-model此时还没赋值console.log(this.test_model, e.target.value)
}

29、深度监听 deep watch

当使用watch时,如果要监听的是一个对象或者一个数组。默认是监听不了的。需要开启deep

http://cn.vuejs.org/v2/api/#watch

http://www.cnblogs.com/hity-tt/p/6677753.html

data () {return {// 表单数据集
        formModel: {// 借款类型borrow_type: '',// 借款金额borrow_money: '',// 业务状态status: '',// 备注remark: ''}}
},
watch: {formModel: {handler (newValue, oldValue) {console.log(newValue)},deep: true}
}

28、安卓和IOS时间转换和显示的兼容性问题,统一解决

// 时间补0辅助函数
const padNumber = (num, fill) => {//改自:http://blog.csdn.net/aimingoo/article/details/4492592var len = ('' + num).length;return (Array(fill > len ? fill - len + 1 || 0 : 0).join(0) + num);
}// 转化时间格式为年月日
const timeYMD = time => {// 如果传入非法参数,直接返回空if (isNullOrEmpty(time)) return null// 兼容安卓的恶心情况 2017-05-2021:53:13 或 2017-04-1000:00:00 替换为: 2017-05-20 21:53:13if (/(-|\/){1}(\d{4})/.test(time)) {// 获取中点const mid = time.lastIndexOf('-') + 3// 生成正确的时间字符串time = time.substr(0, mid) + ' ' + time.substr(mid)}// 兼容IOS和安卓var d = new Date(Date.parse(time.replace(/-/g, "/")))    // 如果转换成功if (d != 'Invalid Date') {time = d.getFullYear() + "-" + padNumber(d.getMonth() + 1, 2) + "-" + padNumber(d.getDate(), 2) + ' '// 如果时都不为0的时候,才叠加上if (d.getHours()) { time += d.getHours() + ':'// 如果时分秒都不为0的时候,才叠加上time += padNumber(d.getMinutes(), 2) + ':'// 如果时分秒都不为0的时候,才叠加上time += padNumber(d.getSeconds(), 2)}// 返回转换成功后的值return time}// 否则返回转换失败的标记return 'Invalid Date'
}

27、必须掌握的技巧:webpack 与 路由 —— 代码分割

https://router.vuejs.org/zh-cn/advanced/lazy-loading.html

http://www.css88.com/doc/webpack2/guides/code-splitting-require/

# API地址:http://www.css88.com/doc/webpack2/guides/code-splitting-require/
# webpack 在编译时,会静态地解析代码中的 require.ensure(),同时将模块添加到一个分开的 chunk 当中。这个新的 chunk 会被 webpack 通过 jsonp 来按需加载。# router.js
const Home = r => require.ensure([], () => r(require('../views/Home.vue')), 'Home')# vue-cli脚手架中/build/webpack.prod.conf.js,output修改为以下样子:
output: {path: config.build.assetsRoot,filename: utils.assetsPath('js/[name].[chunkhash].js'),chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')}

26、组件单元测试所需要的知识点:

# ./my-component.js
export default { template: '<span>{{ fuck }}</span>',props: ['fuck'],created () {console.log('created')}
}# main.js
// 制作组件
Vue.component('MyComponent', Object.assign(MyComponent, {data () {return {fuck : 'you'}},beforeMount () {console.log("beforeMount")}
}));// 新建组件 使用new Vue({//...}) 或者 Vue.extend({ //... }) 都可以
const HtmlContainer = Vue.extend({data () {return {text: '喵了个咪'}}, template: `<my-component :fuck='text'></my-component>`
})// 组件需要挂载,有两种方式
// 方式1:
const vm = new HtmlContainer({el: document.createElement('div'),
})
// 方式2:
const vm = new HtmlContainer().$mount(document.createElement('div'))// 打印来看看结果吧:
console.log(vm, vm.$el, vm.$el.textContent)

25、路由可选参数的坑:

# 如果该参数是动态的数值,直接加入‘?’即可
/houseBusinessDetails/:id?# 但如果是固定的数值,则需要加入()?才可以
/houseBusinessDetails/(id)?/:id?

# 正则表达式加可选参数/myBusiness/:tag([0-2]?)

24、低端机的es6/7兼容性问题:[vuex] vuex requires a Promise polyfill in this browser.

Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。

举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。

知乎关于babel-runtime的问题:https://www.zhihu.com/question/34854349

阮一峰的babel和es6相关文章:http://www.ruanyifeng.com/blog/2016/01/babel.html

# 安装
npm install --save-dev babel-polyfill# webpack
entry: {'babel-polyfill': 'babel-polyfill',app: './src/main.js'
}

Babel默认不转码的API非常多,详细清单可以查看babel-plugin-transform-runtime模块的definitions.js文件。

这样一来就可以使用所有的es6/7特性了。该方案可以说是对方案【14】的无脑版。无脑引入所有的特性。非常冗余但没办法的时候可以用

23、常用的组件内的路由钩子

beforeRouteEnter (to, from, next) {next(vm => {if (from.path === '/myBusiness') vm.$router.push('/')next()})
}

22、从vuex、store的一个使用细节感受到vuejs的开发哲学:

我一直以为store的依赖vue的。直到有一次,意外的先执行了store中自定义的action,然后再初始化new vue({store})。却依然正常无误后才理解。原因store打从一开始就不需要依赖vue,它之所以需要加入到vue,只是为了可以在vue的生命周期中,方便使用this来调用它仅此而已。store完全可以单独使用。从这点可以看出,vue的插件系统和设计非常的优秀

21、fastclick的bug以及解决方案: 当点击select的时候,浏览器会渲染出源生的列表,这时候,表单很可能向上拖拉。这时候,鼠标会继续渗透,很可能刚好点击到拖拉后的input上。然后会呼出键盘,取消掉select。解决方案如下:

20、史诗毁灭宇宙级别的坑:webpack1 版本的 autoprefixer 无法在build编译后生效,只在开发模式下生效,原因是webpack.optimize.UglifyJsPlugin 插件的影响,注释掉即可

19、使用new Date()的一点兼容性小坑

# 并不是所有的浏览器都支持以下转换语法
let data = new Date('2017-04-30 16:47:09')# 但都支持这种转换方法
let data = new Date('2017/04/30 16:47:09')# 所以尽可能要对 ‘-’ 进行替换
var date = new Date(this.model.Model.claimDate.replace(/-/g, '/'));

18、放置冒泡和鼠标穿透最简单的方法:@click.stop

 <button v-if="_isEditable" class="btn btn-white" @click.stop="goToEdit(data.business_id,data.approve_id,data.flow_business_type,data.after_id)">编 辑</button>

17、过滤器的正确用法和常规用法

无代码演示,直接使用computed即可。聪明的你肯定知道怎么做了。

随便找的一个例子:https://blog.csdn.net/sinat_17775997/article/details/56495373

简单示例:

<input type="text" v-model="search_content">
<ul class='list__items'><li v-for='(item, index) in filterItems' :key='index' @click='handleClick(item.schoolId)'>{{ item.schoolName }}</li>
</ul>

data: {search_content: '',// 学校列表
    items: []
},

computed: {filterItems: function () {var self = this;return self.items.filter(function (item) {return ~item.schoolName.indexOf(self.search_content.trim())})}
},

16、v-html 渲染html的内容

<section class="notice-body" v-html="myData['notice_content']">

15、$nextTick + Mounted 解决对未渲染的dom的进行操作报错的问题

methods: {changeSwiperAction () {this.$nextTick(() => {for (let [index, elem] of this.swpierList.entries()) {if( elem.title === this.swiperAction ) return this.$refs.swiperRef.swiper.slideTo(index, 300, false)}})}},
mounted () {this.changeSwiperAction()
}

-14、es2016/es6/es7以上的js尽管有babel编译,或者什么babel的plugin的transform-runtime也没什么用。当你使用了新特性的时候,依然不会进行转换,依然需要修补匠babel-polyfill

但请按需引入,缺什么就补什么:https://github.com/zloirock/core-js

或者使用npm install --save-dev babel-polyfill安装,然后在node_modules中查找core-js文件夹也可以

// 按需加载Es修补匠
require('./modules/es7.object.entries')
require('./modules/es6.array.iterator');

-13、同一个坑我踩了两次:双向数据绑定

我清空两个数组的数据,为了简洁这样写:

this.messageList = this.businessList = []

但这样一来,根据vuejs的特性,这两个list就绑定上了。数据就会同步了……(mmp),所以改为这样就好了……(cnm)

// 清空数据
this.messageList = []
this.businessList = []

-12、组件 vue-awesome-swiper 的坑

监听切换事件,但如果使用 onSlideChangeStart、onSlideChangeEnd、onSlideNextStart、onSlidePrevStart 等方法。完全不可以监听,应该说监听很困难,经常出错。事实上应该使用onTransitionEndonTransitionStart

当动画完成时触发:

 swiperOption: {pagination: '.swiper-pagination',paginationClickable: true,nextButton: '.swiper-button-next',prevButton: '.swiper-button-prev',spaceBetween: 30,effect: 'coverflow',  onTransitionStart: function (swiper) {this.drawMap.index = swiper.activeIndex}.bind(this)}

-11、主动更新组件上的model

当我们开发了一个子组件,并且给某个地方的父组件调用了。此时,如果父组件在子组件上绑定了一个V-model。父组件希望子组件的某些状态变化时,可以顺便更新一下这个v-model的值。那么问题来了。子组件获取和更新这个未知的v-model呢?

# 获取v-model
console.log(this.value); // 对,就是这么简单

# 更新组件上的v-model值. 只需要调用input事件即可,参数为更新的值
fuckXXOO (v) {this.$emit('input', v);
}

-10、 属性函数传参的尴尬

如果要为组件绑定一个click事件,可以使用@click="fuck($event)"。 这是正常的。

但如果是自定义组件,你的@click可能会无效。这时我们想可以传递一个函数进去,让组件本身@click处理。那好,我传递一个属性:clickMethod="fuck('123')"。那么就不正常了。因为该函数fuck('123')会立即执行。根据这个特性,正确的解决方案是这样的:(返回一个函数)

# template
:clickMethod="MenuListClick(item.title,index,item.path)"# script
MenuListClick (title,index,to) {return function () {console.log(title,index,to)   }
}

-9、双向数据 与 组件,以自定义select组件为例。原理很简单,子组件使用$emit来调用绑定在函数组件上的函数,并且传参。而绑定在组件上的函数是在父组件中运行的。拿到参数后父组件就可以为所欲为了

# 子组件中的模板
<select class="mint-field-core" v-if="type === 'select'" @change="$emit('fuck', currentValue)" v-model="currentValue">
<option v-for="(o,index) in option" :value='o.value'>{{ o.text }}</option>
</select># 子组件中的属性和状态
data() {return {currentValue: this.value};
},
props: {option: {type:Array},value: {}
}# 父组件中使用子组件:# template模板
<mt-field label="业务类型" placeholder="请选择业务类型" type='select' :option="list" :value="currSelect" @fuck="handleChange"></mt-field># data状态
list:[{"value":"1","text":"车易贷1"},{"value":"2","text":"车易贷2"},{"value":"3","text":"车易贷3"},{"value":"4","text":"车易贷4"}
],
currSelect:"1"# methods方法
handleChange (val) {console.log("handleChange",val);this.currSelect = val
}

-8、v-model的新姿势:任何组件都可以使用

以前以为只有表单控件才可以拥有v-model的权利和意义,
事实上任何元素/组件(包括自定义组件),都可以使用v-model。
比如说我定义了一个<lee-select>选择框组件,我希望往该组件中传入一个v-model,并且用它遍历出来的值生产option。那么我可以这样做:

# template
<lee-select v-model="list"># script
data () {return {list:[{"id":"1","text":"车易贷1"},{"id":"2","text":"车易贷2"},{"id":"3","text":"车易贷3"},{"id":"4","text":"车易贷4"}]}}

那么我在lee-select组件的内部如何获取该v-model并且循环呢?事实上,系统内置了一个状态:【value】
代码如下:

<option v-for="v in value" value='v'>{{ v.text }}</option>

这样一来,就正常的获取并且遍历出来拉!!!

-7、$refs的简单使用:获取Dom对象

<div class="mint-loadmore-top" ref="loadImage"></div>// 查看各种各样的dom属性
console.log(this.$refs.loadImage);

-6、watch的简单似乎用

data() {return {translate: 0      }
}
watch: {translate (curVal, oldVal) {this.Remtranslate = curVal / 75}}  

-5、让路由与状态融合的插件:vuex-router-sync

import { sync } from 'vuex-router-sync'
import router from './router'
sync(store, router)

把 vue-router 的狀態放進 vuex 的 state 中,這樣就可以透過改變 state 來進行路由的一些操作

import * as type from './mutation-types.js'const mutations = {[type.IS_LOADING] (state, b) {console.log(state.route)  // 打印出路由的实例,那么我们就可以通过它来改变路由地址,为所欲为了state.is_loading = b;}
}export default mutations;

-4、props 设置默认值和其他配置

  props: {show: {required: false,default: true}}

-3、 v-bind 和 v-model的区别

我们知道两者的作用都是可以实现数据的双向绑定。

v-model只能用于表单控件上,比如inputtextarea、radio比如input、textarea、 select/option等,并且主要是来获取和操作表单控件的Value。

这样区分的话,v-bind的作用就很明显了。它可以用来绑定任何属性。比如class / id / placeholder ,甚至自定义属性:fuck / shit 等。但请不要尝试代替v-model的职能,比如绑定了input控件的value属性。那么显然是无效的。还请用V-model绑定

-2、 npm run build 之后路径的坑:

默认的脚手架,编译之后所有的静态资源路径是相对于/static。 事实上应该是./static  那应该如何改呢?

打开脚手架目录下 /config/index.js 文件。

修改 build -> assetsPublicPath : "./" 即可

-1、神奇的computed,又叫属性计算,其作用等于加强版的$watch。它的神奇之处在于可以自动监听函数中使用的状态。如下demo中,可以自动监听 firstNamelastName,当它们两个变化的时候,自动会执行 fullName 这个函数,然后更新view层

如果你使用$watch的话,还需要同时编写对 firstNamelastName 的回调函数

<div id="demo">{{fullName}}</div>var vm = new Vue({data: {firstName: 'Foo',lastName: 'Bar'},computed: {fullName: function () {return this.firstName + ' ' + this.lastName}}
})

0、webpack编译vue不通过的情况(比如Cannot find modulee test.vue,但是可以找到js文件,很明显就是vue文件编译失败):

# 检查.babelrc 或 babel-loader 的配置,确保使用了stage-0以上的版本
npm install babel-preset-stage-2 --save-dev

1、<style>标签中如果要使用sass,需要指定scss而不是sass,如下:<style lang="scss" scoped>,并且需要先安装两个模块:

npm install node-sass sass-loader --save

这里有个天坑。明明安装了上述两个插件,在编译运行的时候依然会报类似的错误:

ERROR in ENOENT: no such file or directory, scandir 'C:\Users\Lee\Desktop\xindaiApp3\node_modules\node-sass\vendor'

解决方案是:打开node_modules,找到node_sass 和 sass-loader 两个文件夹删掉。然后使用cnpm install 重新安装即可。如果还是不行,直接删除整个node_modules,然后执行cnpm install重新安装

如果依然不行。那么直接使用必杀技:安装windows-build-tools.

# github地址
https://github.com/felixrieseberg/windows-build-tools# 安装命令(使用管理员运行powershell / cmd运行以下代码)
npm install --global --production windows-build-tools

解决了我多年 node-sass 安装失败的问题.也包括以后的各种npm环境依赖问题

安装完成之后,可以通过 npm rebuild node-sass 来测试是否编译正常。如果还是不正常。那可能需要你手动安装一下buildTool_Full.exe

大概目录位置在 C:\Users\用户名\.windows-build-tools\BuildTools_Full.exe. 如果你电脑上已经有VS系列,那可能需要先删除,才可以安装了。具体自己想办法解决

2、<style>标签中如果要使用less,如下:<style lang="less" scoped> ,并且需要先安装两个模块:

npm install less less-loader --save

3、Vue中的watch 非常容易使用,所以我没有书写任何的demo,但有一个点要注意,VueJs并不是非常精准的监听。比如说

我定义了一个data为items = [];如果我对这个items直接赋值一个数据,watch就会监听到,但如果items本身是一个复杂的object结构,比如说数组对象中的数组,当最内层的数组发生变化时,watch是不会监听到的。

4、在 Vue 2.0 中,为自定义组件绑定原生事件必须使用 .native 修饰符:

<my-component @click.native="handleClick">Click Me</my-component> 

5、属性赋值,通常是动态的model,但为了方便也可以直接赋值bool或者string如下:

:_left="false"     //布尔值

:_rightText="'货币转换'"   //字符串

6、V-bind 三元表达式的问题 ,不可以使用双引号

其他属性表达式请查看手册:http://vuejs.org/v2/api/#v-bind

:class="item.name == '我' ? 'odd' : 'even' "

7、Vuejs 变量拼接的问题。

# 方式1 字符串 + 变量
:href=" '#content' +  index"# 方式2 变量 + 变量
<img :src="baseUrl + imgUrl">

8、vue.js+webpack 为 img src 赋值的路径问题

如果静态的写上地址如:'./images/abc.png'。就会被webpack编译为loader 插件编译成base64风格的地址。

但是某些情况下我们需要动态写上src地址,但动态的地址又不会被编译。怎么办呢?解决方案如下:

astroImage:require(`./images/${this.$route.params.consName}.png`)

9、vue的template,如果html的属性如src、class 想赋值一个data的话,就必须加上: 将其变成属性如 :class="xxx"   :src="xxx"

11、宇宙级深坑:

我新建了一个变量。把items赋值给他,然后我修改这个变量。items居然也跟着修改了

解决方案是这样修改:

var arr = this.items.slice(0); // 利用slice函数克隆一个数组
arr.push(10);  // 进行一些操作
console.log(this.items); // 不会被影响到

接下来是对数组进行克隆,使用es6的语法

let new_obj = Object.assign({}, [your obj]);  // 利用Object.assign克隆一个对象

12、组件生命周期钩子的使用,必须是这种写法:

常用的是mountedcreated

// beforeCreate、created、beforeDestroy、destroyed、beforeMount、mounted、beforeUpdate、updated、activated、deactivated

beforeDestroy () {
    this.$parent.route_pipe(false);
  }

13、组件名不可以为html内置的譬如说<footer><header>

14、<tamplate>中的html最好在最外层包裹着一个<div>. 这很重要。并且直接影响路由的使用transition的使用

16、路由使用

  // 路由超链接   ,注意这个to,如果是纯字符串的时候直接to="xxxx",如果是变量的时候再使用:to<router-link :to=backPath :class=backPath ></router-link> //加入全局变量,这样才能在其他地方调用
window.router = router//跳转
router.push("bar")//可以使用afterEach + vuex 来实现动态获取后退页面的地址
router.afterEach((to, from) => {console.log(to, from)
})//可以使用beforeEach 来拦截页面  并且进行一些操作之后再放行next()
router.beforeEach((to,from,next) => {console.log(to,from);next(); //放行
})//children子路由,当我们在order页面中加入 <router-view> 时,orderDetails 页面 会从该 <router-view> 中进出
 {path:'/order',component:require('./views/order'),children:[{path:':id',component:require('./views/orderDetails')}] }  /*  再来一个子路由的demo: 上面的demo中,不知为何?如果直接写上:id ,会直接将子路由配置的页面显示在父页面中。所以我换成这个demo的就可以了。只有等我点击才出现在父页面. */{path:'/astro',component:require('./views/astro/index'),children:[{path:'/astro/:consName',component:require('./views/astro/info')}]}// 监听路由页面进入事件
beforeRouteEnter:(to, from, next) => {// 在渲染该组件的对应路由被 confirm 前调用// 不!能!获取组件实例 `this`// 因为当钩子执行前,组件实例还没被创建next( vm => {vm.$parent.route_pipe(true);});},// 监听路由页面的退出事件
beforeRouteLeave (to, from, next) {console.log(this); next(); },//如果两个页面都是通过同一个 <router-view> 进出,那么他们的动画事件(enter/leave)会同时触发,尽管某些场景下能实现华丽的效果。
//但某些场景你不想被混淆,譬如层层嵌套的界面:index->order->orderDetails.类似这种页面结构,应该使用嵌套路由 + chilren路由配置,参考上面的子路由demo 

View Code

 

20、css中的转义符号 “\”  在编译【npm run build】的时候可能不通过。需要删修掉。这种情况可能会出现在svg中,如图

demo2: 循环

补充:在循环中可以使用{{ $index }} 来获取索引

vue2.0 在V-for中这样书写格式:v-for="(item,index) in items"  然后就可以这样使用了  :data-index="index"

<template><div id="app"><h1>{{title}}</h1> <!-- <h1 v-text='title'></h1> --><ul><li v-for='item in items' v-bind:class="{finished: item.isFinished}">{{item.label}}</li></ul></div>
</template><script>
export default {data () {return {title: 'Hello World!',items: [{label: 'coding',isFinished: false},{label: 'walking',isFinished: true}]}}
}
</script><style>
.finished{text-decoration: underline;}
html {height: 100%; }
body {display: flex; align-items: center; justify-content: center; height: 100%; }
#app {color: #2c3e50; margin-top: -100px; max-width: 600px; font-family: Source Sans Pro, Helvetica, sans-serif; text-align: center; }
#app a {color: #42b983; text-decoration: none; }
.logo {width: 100px; height: 100px }
</style>


demo2-1  bind属性

v-bind指令可以在其名称后面带一个参数,中间放一个冒号隔开,这个参数通常是HTML元素的特性(attribute),例如:v-bind:class

该指令通常绑定的是一个表达式、model、(也可以是纯字符串但没什么意义)

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><link rel="stylesheet" href="styles/demo.css" /></head><body><div id="app"><ul class="pagination"><li v-for="n in pageCount"><a href="javascripit:void(0)" v-bind:class="activeNumber === n + 1 ? 'active' : ''">{{ n + 1 }}</a></li></ul></div></body><script src="js/vue.js"></script><script>var vm = new Vue({el: '#app',data: {activeNumber: 1,pageCount: 10}})</script>
</html>


demo3: 事件与双向数据绑定

1、$event  访问原来的 DOM event,你可以传递一个 $event 参数进去: @click="change_title($event)"

然后可以这样调用

change_title (e) {
  console.log(e.target.innerText)

//利用zepto/jquery访问源生对象 

  console.log($(e.target).html())

}

2、如果在手机模式下@click是无效的,需要使用@touchend或者@touchstart

<template><div id="app"><h1>{{title}}</h1> <!-- <h1 v-text='title'></h1> --><input type="text" v-model='newItem' @keyup.enter='addItem'><ul><li v-for='item in items' v-bind:class="{finished: item.isFinished}" v-on:click='toggleFinish(item)'>{{item.label}}</li></ul></div>
</template><script>
export default {data () {return {title: 'Hello World!',items: [{label: 'coding',isFinished: false},{label: 'walking',isFinished: true}],newItem: ''}},methods: {toggleFinish (item) {item.isFinished = !item.isFinished},addItem () {console.log(this.newItem)this.items.push({label: this.newItem,isFinished: false})this.newItem = ''}}
}
</script><style>
.finished{text-decoration: underline;}
html {height: 100%; }
body {display: flex; align-items: center; justify-content: center; height: 100%; }
#app {color: #2c3e50; margin-top: -100px; max-width: 600px; font-family: Source Sans Pro, Helvetica, sans-serif; text-align: center; }
#app a {color: #42b983; text-decoration: none; }
.logo {width: 100px; height: 100px }
</style>


demo5-1 微实战

知识点:事件、数据绑定、循环

<template><div id="app"><fieldset><legend>Create New Person</legend>    <div class="form-group"><label>Name:</label><input type="text" v-model="newPerson.name" /></div><div class="form-group"><label>Age:</label><input type="text" v-model="newPerson.age" />        </div><div class="form-group"><label>Sex:</label><select v-model="newPerson.sex"><option>男</option><option>女</option></select></div><div class="form-group"><label></label><button @click="createPerson">Create</button></div></fieldset><table><thead><tr><th>Name</th> <th>Age</th> <th>Sex</th> <th>Delete</th></tr></thead><tbody>        <tr v-for="p in people"><td>{{ p.name }}</td><td>{{ p.age }}</td><td>{{ p.sex }}</td><td><button @click="deletePerson($index)">Delete</button></td></tr></tbody></table></div>
</template>
<script type="text/javascript">export  default {data () {return {newPerson : {name : '', age : 0, sex : '男'},people : [{name: 'Jack', age: 30, sex: 'Male'}, {name: 'Bill', age: 26, sex: 'Male'}, {name: 'Tracy', age: 22, sex: 'Female'}, {name: 'Chris', age: 36, sex: 'Male'} ]}},methods : {createPerson () {//添加到数组this.people.push(this.newPerson)//重置this.newPerson = {name : '', age : 0, sex: '男'}},deletePerson (index) {// 删一个数组元素this.people.splice(index,1)}}}
</script>
<style>
* {margin: 0; padding: 0; box-sizing: border-box } html {font-size: 12px; font-family: Ubuntu, simHei, sans-serif; font-weight: 400 } body {font-size: 1rem } table, td, th {border-collapse: collapse; border-spacing: 0 } table {width: 100% } td, th {border: 1px solid #bcbcbc; padding: 5px 10px } th {background: #42b983; font-size: 1.2rem; font-weight: 400; color: #fff; cursor: pointer } tr:nth-of-type(odd) {background: #fff } tr:nth-of-type(even) {background: #eee } fieldset {border: 1px solid #BCBCBC; padding: 15px; } input {outline: none } input[type=text] {border: 1px solid #ccc; padding: .5rem .3rem; } input[type=text]:focus {border-color: #42b983; } button {outline: none; padding: 5px 8px; color: #fff; border: 1px solid #BCBCBC; border-radius: 3px; background-color: #009A61; cursor: pointer; } button:hover{opacity: 0.8; } #app {margin: 0 auto; max-width: 640px } .form-group {margin: 10px; } .form-group > label {display: inline-block; width: 10rem; text-align: right; } .form-group > input, .form-group > select {display: inline-block; height: 2.5rem; line-height: 2.5rem; } .text-center{text-align: center; } .pagination {display: inline-block; padding-left: 0; margin: 21px 0; border-radius: 3px; } .pagination > li {display: inline; } .pagination > li > a {position: relative; float: left; padding: 6px 12px; line-height: 1.5; text-decoration: none; color: #009a61; background-color: #fff; border: 1px solid #ddd; margin-left: -1px; list-style: none; } .pagination > li > a:hover {background-color: #eee; } .pagination .active {color: #fff; background-color: #009a61; border-left: none; border-right: none; } .pagination .active:hover {background: #009a61; cursor: default; } .pagination > li:first-child > a .p {border-bottom-left-radius: 3px; border-top-left-radius: 3px; } .pagination > li:last-child > a {border-bottom-right-radius: 3px; border-top-right-radius: 3px; }
</style>



demo5-3: 封装常见的后台左侧菜单

<template><div><input type="text" v-model='keyword' placeholder="全文搜索(未实现)" /><div v-for="(item,index) in items"><h1 @click="myfunc($event,index)">{{item.title}}</h1>    <!-- 随便弄了一个动画,不喜欢直接删除transition标签 --><transition name="slide"><!-- 当数组中不存在当前索引时才出现 --><ul v-if = "closeIndex.indexOf(index) === -1">            <li  v-for=" l in item.list " >{{ l }} </li></ul>                </transition></div></div>
</template><script>export default {data () {return {keyword : "",closeIndex : [],items:[{title:"合同管理",list:["合同录入","合同审核"]},{title:"结算单管理",list:["结算单录入","结算单审核","渠道异常管理"]},{title:"基础数据管理",list:["渠道信息管理","渠道折扣信息管理","用户角色管理","管理配置页面"]}]}},methods:{myfunc (el,index) {var _index = this.closeIndex.indexOf(index);if(_index > -1)            this.closeIndex.splice(_index,1);            elsethis.closeIndex.push(index);                }}}
</script><style scoped>.slide-enter-active,.slide-leave-active {transition: all .35s ease;}.slide-enter,.slide-leave-active {opacity: 0;transform: translate3d(-100%,0,0);}   ul li{list-style: none}h1{font-size:16px;font-weight: normal;font-family: "微软雅黑"}
</style>


 demo5-4:超级炫酷的洗牌

<template><div><button @click="shuffle"> Shuffle </button><transition-group name="cell" tag="div" class="container"><div v-for="cell in cells" :key="cell.id" class="cell">{{ cell.number }}</div></transition-group></div>
</template><script>export default {data () {            return {cells: Array.apply(null, { length: 81 }).map(function (_, index) { return {id: index,number: index % 9 + 1}})}},methods:{shuffle: function () {var arr = this.cells.slice(0);     // 利用slice函数克隆一个数组.不要问我为什么要克隆this.cells = this.myshuffle(arr);},/* ES6版本的洗牌函数 */myshuffle (arr) {let n = arr.length, random;while(0!=n){random =  (Math.random() * n--) >>> 0; // 无符号右移位运算符向下取整
                        [arr[n], arr[random]] = [arr[random], arr[n]] // ES6的结构赋值实现变量互换
                    }return arr;}}}
</script><style scoped>/* 动画钩子 */
.cell-move {transition: transform 1s ease;
}.container {display: flex;flex-wrap: wrap;  /* #当宽度不够时换行 */width: 238px;
}.cell {text-align: center;width: 25px;height: 25px;border: 1px solid #aaa;
}</style>

Demo10 : vue-socket

如果要在vue中使用socket,则需要第三方模块:Vue-Socket.io

https://github.com/MetinSeylan/Vue-Socket.io

server服务端,神坑:必须让sendClientData中的代码单独抽离为一个函数,不然只有发起server_menu事件的客户端才能收到。很奇怪

let socket = sio.listen(server);
socket.on('connection',function(socket){console.log("socket start!");socket.on("server_menu",function(menu_data){fs.writeFile('../data/desk.json',menu_data,function(err){if(err) console.error("文件写入失败");else console.log("文件写入成功");});sendClientData(menu_data);})
})
let sendClientData = (data) => {socket.emit('client_menu',data);
}

client客户端:

import VueSocketio from 'vue-socket.io';
Vue.use(VueSocketio, 'http://localhost:8090');sockets : {connect : function(){console.log('socket connected')},client_menu : function(data){console.log("client_menu",data)}    }created () {this.$socket.emit("server_menu",{name:"test"});}

demo 11 : 全局插件 install

# global.js
export default {install ( Vue ) {Vue.prototype.functions = {getVersion () { return "1.0"}};}
}

# main.js
import plugins from './../plugins/global.js';
Vue.use(plugins);# navbar.vue
created () {alert(this.functions.getVersion());
}

demo12 : 插槽作为组件使用

1、如果插槽没有定义name属性,那么传递进来的所有【内容】都会插入其中;
2、如果插槽定义了name属性,但外部的【内容】没有指定solt的name,那么无法插入该插槽;
3、如果插槽定义了name属性,并且外部的【内容】分别指定了solot的name属性,那么会对号入座插入对应的插槽中;

这里的【内容】指的是文本、HTML元素、vue组件等等... 事实上并没有很难理解。只需要试试以下的demo,并且尝试更改solt相关的内容即可学会

# 子组件 tabbar.vue ——————————————————————————————————————————————————
<template><div class="m-tabbar"><slot></slot></div>
</template>
<style lang="less">
.m-tabbar{display: flex;flex-direction: row;position: fixed;bottom: 0;left: 0;right: 0;width: 100%;overflow: hidden;height: 50px;background: #fff;border-top: 1px solid #e4e4e4;
}
</style># 子组件 tabbar-item.vue ———————————————————————————————————————
<template><a class="m-tabbar-item" ><span class="m-tabbar-item-icon"><slot name="icon-normal"></slot></span><span class="m-tabbar-item-text"><slot></slot></span></a>
</template><style lang="less">
.m-tabbar-item{flex: 1;text-align: center;.m-tabbar-item-icon{display: block;padding-top: 2px;img{width: 28px;height: 28px;}}.m-tabbar-item-text{display: block;font-size: 10px;color:#949494;}&.is-active{.m-tabbar-item-text{color: #42bd56;}}
}
</style># 父组件 index.vue ————————————————————————————————————————————
<template><div><m-tabbar><m-tabbar-item id='tab1'><img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal"> 首页</m-tabbar-item><m-tabbar-item id='tab2'><img src="../assets/images/ic_tab_subject_normal.png" alt="" slot="icon-normal"> 书影音</m-tabbar-item><m-tabbar-item id='tab3'><img src="../assets/images/ic_tab_status_normal.png" alt="" slot="icon-normal" /> 广播</m-tabbar-item><m-tabbar-item id='tab4'><img src="../assets/images/ic_tab_status_normal.png" alt="" slot="icon-normal" /> 小组</m-tabbar-item><m-tabbar-item id='tab5'><img src="../assets/images/ic_tab_profile_normal.png" alt="" slot="icon-normal"> 我的</m-tabbar-item></m-tabbar></div>
</template><script>import mTabbar from '../components/tabbar'import mTabbarItem from '../components/tabbar-item'export default {name: 'index',components: {mTabbar,mTabbarItem}}
</script>

HTTP  [,eitʃti:ti:'pi:]  详细X
基本翻译
abbr. 超文本传输协议(Hyper Text Transport Protocol)

网络释义
HTTP: 超文本传输协议(Hyper Text Transfer Protocol)
HTTP referer: HTTP参照位址
http Proxy: 代理服务器

转载于:https://www.cnblogs.com/CyLee/p/5813721.html

vue.js 的学习相关推荐

  1. laravel+vue.js的学习以及为什么浏览器中要有井号“#”

    一.前言 一直想找机会学一下vue,但是go还没来得及学,laravel的源码还没看完,学习vue更是遥遥无期.幸好新公司的项目是用laravel+vue编写的,这才有幸接触到vue. 但是我在观看项 ...

  2. 三十、开始前端Vue.js的学习之路

    @Author:Runsen @Date:2019/08/07 @modified Date:2019/08/07 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼 ...

  3. vue.js的学习中的简单案例

    今天学习了近年来挺火的一门JS技术,叫vue.js下面是它的一个简单案例: <html> <head> <title>$Title$</title> / ...

  4. Vue.js(学习Vue3之前必须要掌握的知识)

    文章目录 第一个Vue程序 el挂载点 data数据对象 v-text v-html v-on 计数器 v-show v-if v-bind 图片切换 v-for v-on自定义参数 v-model双 ...

  5. 我的Vue.js的学习之旅记录(1)

    学习途径:vue官网, 慕课网 一. 所需知识储备:js,es6,webpack,npm 1.nuxt框架围绕vue推出 2.weex可以用vue写app Vue.js 是什么 Vue (读音 /vj ...

  6. vue.js 基础学习 11天 -- 转载 某培训机构 学习资料 (转载链接未找到-暂定原创 - 非原创)

    Vue.js - Day1 课程介绍 前5天: 都在学习Vue基本的语法和概念:打包工具 Webpack , Gulp 后5天: 以项目驱动教学: 什么是Vue.js Vue.js 是目前最火的一个前 ...

  7. Vue.js教程学习笔记

    官方视频简易教程:https://learning.dcloud.io/ 1. 安装与部署 第一阶段(初学)可以通过在html文件中引入脚本来完成安装 <script src="vue ...

  8. vue.js组件学习(上)

    组件是vue.js中非常重要的一部分,打个比方,会用组件得人喝着茶就写完的页面,不会用的代码打到手抽筋也未必完的成. 首先何为组件 组件可以封装重用的代码,扩展HTML元素,更高的说组件是自定义元素. ...

  9. Vue.js组件学习

    组件可以扩展HTML元素,封装可重用的HTML代码,我们可以将组件看作自定义的HTML元素.组件系统提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用. 一个简单组件例子(全局注册) &l ...

最新文章

  1. 【Android】Activity生命周期(亲测)
  2. 最新!2020中国高校毕业生薪资报告出炉
  3. linux应用日志类型,linux日志分析
  4. (五)DTD验证XML文档
  5. Linus 在圣诞节想提前放假做了这些解释,哈哈哈
  6. 17 MM配置-BP业务伙伴-定义业务伙伴角色
  7. 疑问:当流量被封禁之后(论资本之力):防流量被恶意盗挖(抛砖篇)
  8. python-容器数据类型-知识小结
  9. 10 SystemVerilog语言编写SPI发送
  10. iOS开发--Runtime知识点整理
  11. webstorm中代码添加单引号、双引号快捷键
  12. JDK 11JAVA11下载分享
  13. python100份教材/教程分享学习,初中高级总有适合你的
  14. 各大搜索引擎蜘蛛名称大全
  15. 评救市后中国股市新乱象泛起谣言
  16. mysql 备份数据库结账_年度结转问题综合解答(转)
  17. 深入理解WKWebView白屏
  18. 带你手摸手搭建vuepress站点
  19. 常见的java面试题
  20. 你所不知清楚的3D建模师的现状

热门文章

  1. JAVA 接口签名sign生成 工具类
  2. 服务器生成微信sign,签名生成方法
  3. echart 折线从左到右动画效果_echarts多条折线图动态分层的实现方法
  4. 开源项目之freepy自由输入法
  5. Android 折叠屏适配最全的攻略在这里
  6. 《Unity2018AR与VR开发快速上手》随书内容资源相关说明
  7. Java使用Jsoup爬虫获取网站内容(三)获取元素内容属性的方法
  8. c++nullptr(空指针常量)、constexpr(常量表达式)
  9. JavaScript ES6 特性
  10. 图形学中变换用到的数学知识