v1.0.1 飞豺 8416837 Vue 2.6.10
原创内容,转载请注明出处^_^根本知识为什么要学习Vuejs
网友:\"大众到本日这个时期有些人学完了js、html5/dom/bom直接跳过jQ去学vue我以为完备没问题,以是不懂jQ的人会vue当然可以,本来前真个根本便是js而不是jQ。而且vue本身走的便是模块化的开拓办法,便是让项目更好掩护,更好升级,在这些方面绝比拟jQ更精良。jQuery之以是被替代,一是开拓办法守旧、老旧、效率低,二是由于html5出了很多新的api,完备可以代替jQ,就连bootstrap重构都已经申明将剔除jQ。退一万步说,前端最根本的还是js,只要你js技能过关,不管是学jQ还是vue都会很快。\"大众vue.js的作者尤雨溪是中国人,在知乎上有帐号,且非常生动。尤雨溪毕业于上海复旦附中,在美国完成大学学业,本科毕业于Colgate University,后在Parsons设计学院得到Design & Technology艺术硕士学位,现就职于纽约Google Creative Lab。2016年9月3日,南京JSConf,尤雨溪宣告加盟阿里巴巴Weex团队,尤雨溪称他将以技能顾问的身份加入Weex 团队来做 Vue 和 Weex 的 JavaScript runtime 整合,目标是Vue跨三端。前后端分离暨Vuejs的上风变革解耦,视图-网关-做事各司其职。自由组合搭配。后端无状态,不存储用户信息,不掩护session减轻包袱。安全提升;单页模式,相应更快;静态页面支配到nginx,相应更快,且升级时无感知,不需重启;Reactive编程。相应式,数据改变时,页面实时相应。高效,将某些运算迁移到前端,类似边缘打算-分摊中央压力;简化代码,后端API机器式自动天生,前端调用API即可;技能健全,如路由、存储、生命周期管控、监听、打算、调试、测试框架,规范成熟;渐进式,自然融入到已经上线的项目,持续增加需求,扩展性强;数据渲染高效;精良案例;技能改造、推广、传承;开拓上手较快,由于根本还是JS;热支配,代码更新后即时生效而无需构建。传统开拓亦可以通过一定配置进行热支配,但有时会失落效。灵巧与API|MQ交互;兼容技能栈,如WebSocket、MQ等;丰富的组件库,提升效率;调试、测试框架;分开后端,暂无API时,可利用mock.js框架仿照;语法糖有助于实现繁芜功能;专用IDE,如webstorm;文档详尽易懂,社区生动壮大中;开拓体验:规范、生命周期掌握,数据绑定,热支配不需繁芜设置,JS与DOM解耦,不用直接操作DOM,代码复用,MVVM构造,面向工具-后端思维;运维独立支配,减轻后端压力,发布以及做事崩溃互不影响;疏松耦合,定位BUG快捷;代码易读,易掩护,新增需求无压力,如多客户端需求、前后端分离需求;比拟Thymeleaf、JSP与DOM耦合,前者遵照xml规范,模板只办理了渲染,没办理麻烦的DOM问题;什么是MVVM?MVVM是Model-View-ViewModel的缩写要编写可掩护的前端代码绝非易事。我们已经用MVC模式通过koa实现了后端数据、模板页面和掌握器的分离,但是,对付前端来说,还不足。这里有童鞋会问,不是讲Node后端开拓吗?怎么又回到前端开拓了?
对付一个全栈开拓工程师来说,懂前端才会开拓出更好的后端程序(不懂前真个后端工程师会设计出非常难用的API),懂后端才会开拓出更好的前端程序。程序设计的基本思想在前后端都是通用的,两者并无实质的差异。这和“不想当厨子的裁缝不是好司机”是一个道理。
改变JavaScript工具的状态,会导致DOM构做作出对应的变革!
这让我们的关注点从如何操作DOM变成了如何更新JavaScript工具的状态,而操作JavaScript工具比DOM大略多了!
这便是MVVM的设计思想:关注Model的变革,让MVVM框架去自动更新DOM的状态,从而把开拓者从操作DOM的繁琐步骤中解脱出来!
——廖雪峰
ps:jQuery MVVM框架如JSViews
文件
Vue中index.html、main.js、App.vue、index.js之前的关系以及加载过程App.vue中的router-view<template><div id=\"大众app\"大众> <p>便是一张da图片</p> [外链图片转存失落败(img-dlDOl0R2-1562114250786)(https://mp.csdn.net/mdeditor/assets/logo.png)] <!--PS: router-view渲染路由信息于此--> <router-view/></div></template>router/index.js定义了大略的路由信息main.js入口,加载组件到index.html组件
观点
组件类似自定义元素.Web组件规范在一个大型运用中,有必要将全体运用程序划分为组件,以使开拓更易管理。假想例子,以便展示组件的构造↓<div id=\"大众app\"大众><app-nav></app-nav><app-view> <app-sidebar></app-sidebar> <app-content></app-content></app-view></div>const常量export文件通过export暴露接口|变量h => h(App)
// 演化步骤render: function (createElement) { return createElement(App);}render (createElement) { return createElement(App);}render (h){ return h(App);}
It comes from the term “hyperscript”, which is commonly used in many virtual-dom implementations. “Hyperscript” itself stands for “script that generates HTML structures” because HTML is the acronym for “hyper-text markup language”. — by 尤雨溪
export default
ES6的export利用export命令定义了模块的对外接口往后,其他JS文件就可以通过import命令加载这个模块(文件),没错$refs持有所有被ref定义的组件定义组件在不该用.vue 单文件时,我们是通过 Vue 布局函数创建一个 Vue 根实例来启动vuejs 项目,Vue 布局函数接管一个工具,这个工具有一些配置属性 el, data, component, template 等,从而对全体运用供应支持。new Vue()new Vue() 相称于一个布局函数,在入口文件 main.js 布局根组件的同时,如果根组件还包含其它子组件,那么 Vue 会通过引入的选项工具布局其对应的 Vue 实例,终极形成一棵组件树。export default比较new Vue() & export default全局组件Vue.component('todo-item', { template: '<li>这是个待办项</li>' }).vue文件可以把html, css, js 写到一个文件中,从而实现了对一个组件的封装父子关系在一个组件中通过 import 引入另一个组件,这个组件便是父组件,被引入的组件便是子组件.父组件通过props 向子组件通报数据,子组件通过自定义事宜向父组件通报数据.注册组件全局注册
Vue.component('component-a', { / ... / })Vue.component('component-b', { / ... / })Vue.component('component-c', { / ... / })局部注册
new Vue({el: '#app',components: { 'component-a': ComponentA, 'component-b': ComponentB}})生命周期computed打算属性,如将总价在computed里打算,从而实时打算商品购物车里的商品总价对付任何繁芜逻辑,你都应该利用打算属性无变革时,缓存,提高效率;工具构建类yarn可以代替npm的包依赖管理工具VueX在SPA单页面组件的开拓中 Vue的vuex和React的Redux 都统称为同一状态管理,个人的理解是全局状态管理更得当;大略的理解便是你在state中定义了一个数据之后,你可以在所在项目中的任何一个组件里进行获取、进行修正,并且你的修正可以得到全局的相应变更.管理Token、全局个人偏好mutations
const storeLogin = new Vuex.Store({state: { // 存储token Authorization: localStorage.getItem('Authorization') ? localStorage.getItem('Authorization') : ''},mutations: { // 修正token,并将token存入localStorage changeLogin(state,user) { console.log('进入changeLogin') state.Authorization = user.Authorization; localStorage.setItem('Authorization', user.Authorization); }}});又如↓
mutations: {increment (state, payload) { state.count += payload.amount}}mutations下的函数只适宜吸收一个工具参数,state是默认传入,不能把state当做形参rules先在html引入rules
<el-form ref=\"大众loginForm\"大众 :model=\"大众loginForm\公众 :rules=\"大众loginRules\公众 class=\公众login-form\"大众 autocomplete=\公众on\"大众 label-position=\公众left\公众>data里定义rules
data() { loginRules: { // 验证器 validateUsername 是一种分外的函数 username: [{ required: true, trigger: 'blur', validator: validateUsername }], password: [{ required: true, trigger: 'blur', validator: validatePassword }] },},验证器也在data里面
const validateUsername = (rule, value, callback) => { // validUsername 是引入的js函数 if (!validUsername(value)) { callback(new Error('请输入精确的用户名')) } else { callback() } }引入validUsername
import { validUsername } from '@/utils/validate' // 导入jsElement-ui
// 引入uiimport ElementUI from 'element-ui' //element-ui的全部组件import 'element-ui/lib/theme-chalk/index.css'//element-ui的cssVue.use(ElementUI) //利用elementUIcnpm install element-ui@2.0.3 -S穿梭框踩坑效果
在这里插入图片描述<div style=\"大众text-align: left\"大众> <!-- <div style=\"大众text-align: center\公众> --> <el-transfer v-model=\"大众value4\公众 style=\公众text-align: left; display: inline-block\"大众 filterable :render-content=\"大众renderFunc\"大众 :titles=\"大众['用户角色', '已选角色']\公众 :button-texts=\公众['放弃', '选择']\公众 :format=\"大众{ noChecked: '${total}', hasChecked: '${checked}/${total}' }\"大众 :data=\"大众roleData\"大众 :props=\"大众defaultProps\公众 @change=\公众handleChange\"大众 ><!-- ↓等效:render-content--><!-- <span slot-scope=\"大众{ option }\"大众>{{ option.roleId }} - {{ option.roleName }}</span>--> <el-button slot=\"大众left-footer\"大众 class=\公众transfer-footer\"大众 size=\公众small\公众>操作</el-button> <el-button slot=\公众right-footer\"大众 class=\公众transfer-footer\"大众 size=\"大众small\"大众>操作</el-button> </el-transfer> </div>data() { return { // 角色数据 data: [], // 别名 defaultProps: { key: 'roleId', label: 'roleName', disabled: false }, // 不要value4无法移动元素 value4: [1], renderFunc(h, option) { // 天生元素的显示名称 return <span>{ option.roleName }</span> // return <span>{ option.roleId } - { option.roleName }</span> },目标框初始值不出来办理了
在这里插入图片描述踩坑demo如cc.vue# 新建cc组件template> <div> 中国工农红军 <ul> <li v-for=\公众site in sites\"大众 :key=\"大众site.name\"大众> {{site.url}} <a :href=\"大众site.url\公众 target=\"大众_blank\"大众>{{site.name}}</a> </li> </ul> <input type=\"大众button\"大众 value=\"大众点击我\"大众 @click=\"大众printText\"大众/> </div></template><script>// import { METHODS } from 'http'export default { name: 'Cc', methods: { clickTest: function () { alert('你点击了按钮') }, printText: function () { console.log('你点击了按钮') } }, data () { return { msg: '书本是人类进步的阶梯', msg2: 'Apple', sites: [ {url: 'http://router.vuejs.org/', name: 'Jack'}, {url: 'http://vuex.vuejs.org/', name: 'Tom'}, {url: 'https://github.com/vuejs/awesome-vue', name: 'Jimy'} ] } }}</script><!-- Add \公众scoped\公众 attribute to limit CSS to this component only --><style scoped>h1, h2 { font-weight: normal;}ul { list-style-type: none; padding: 0;}li { display: inline-block; margin: 0 10px;}a { color: #42b983;}</style>
index.js
# 注入组件import cc from '@/components/cc'
缺点记录
大略
Error in created hook: “TypeError: _admin.menuTree.then is not a function”
由于导入的函数没加括弧
// 函数须要括弧,↓对的menuTree().then(response => {}
要求头类型不对
// 组件内部增加下述代码 - 局部要求头import Axios from 'axios'Axios.defaults.headers.post['Content-Type'] = 'application/json'# 或者在axios api里加入export function call(data) { return request({ headers: { 'Content-Type': 'application/json' // 设置要求头要求格式为JSON }, url: url, method: 'post', data })}大略单纯功能开拓
ajax
axios# install axioscnpm install axios --save-dev# --save-dev以省却手动修正package.json文件的步骤axios发送ajax要求
<script src=\"大众/js/axios.min.js\公众></script> window.onload=function(){ new Vue({ el:'#app', data:{ users:{ name:'', age:'' } }, methods:{ sendPsot(){ axios.post('post.php', { name: this.users.name, age: this.users.age, }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); } } }); }跨域配置后端亦可配置跨域,前后端不要都配config/index.js,proxyTable里增加内容(老式)
proxyTable: { // 办理跨域 '/tbapi':{ // target: \"大众http://api.douban.com/v2\"大众, target: \"大众https://suggest.taobao.com\"大众, changeOrigin:true, pathRewrite:{ '^/tbapi':'' } } },组件js
// 跨域Axios.defaults.baseURL = '/tbapi'Axios.defaults.headers.post['Content-Type'] = 'application/json'mounted() { //GET this.$ajax({ method: 'get', // tbapi会代替localhost url: '/sug?code=utf-8&q=电冰箱', // url: '/sug?code=utf-8&q=电冰箱&callback=cb', }).then(response => { // response包含config data等 var resData = response.data.result iceBoxes = resData resData.forEach(item => { console.log(item[0]) console.log(item[1]) // console.log('数据序号'+i+'=='+item) }) }).catch(function (err) { console.log(err) }) //POST this.$ajax({ method: 'post', url: '/sug?code=utf-8&q=iPhone', // data: { // code: 'utf-8', // q: 'iPhone' // } }).then(response => { // response包含config data等 var resData = response.data.result resData.forEach(item => { console.log(item[0]) console.log(item[1]) // console.log('数据序号'+i+'=='+item) }) }).catch(function (err) { console.log(err) }); }登录逻辑
handleLogin() { this.$refs.loginForm.validate(valid => { if (valid) { this.loading = true // 也便是说,全局store工具拥有原生的dispatch方法,用于要求API this.$store.dispatch('user/login', this.loginForm).then(() => { this.$router.push({ path: this.redirect || '/' }) this.loading = false }).catch(() => { this.loading = false }) } else { console.log('error submit!!') return false } }) }源码解析上文的$store来自这里@/store/index.js,片段↓
const store = new Vuex.Store({modules,getters})// 导出实例this的store属性export default storestore的dispatch,该单词是发送的意思axios的配置```javascript// request即service-axiosimport request from ‘@/utils/request’
// ↑request含有拦截器,url改为得当的baseUrl
export function login(data) {
console.log(‘axios实例==’,request)
return request({
url: ‘/user/login’,
method: ‘post’,
data
})
}
当index.vue里的store.dispatch实行要求时,即会找到上面的login函数,由login函数发出调用要求,接着,我们看`request.js`里的代码```javascriptimport axios from 'axios'import { MessageBox, Message } from 'element-ui'import store from '@/store'import { getToken } from '@/utils/auth'// global全局配置import { baseUrl } from '@/utils/global'// create an axios instance 没错,service便是axios实例,import@/utils/request即注入service-axios实例const service = axios.create({ baseURL: baseUrl, // url = base url + request url // baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url // withCredentials: true, // send cookies when cross-domain requests timeout: 5000 // request timeout})
↑这是axios的配置,配置了url和超时时间,当实行$store.dispatch时,即会加上baseUrl进行要求。
吸收相应↓,也来自request.js
response => { const res = response.data // if the custom code is not 20000, it is judged as an error. if (res.code !== 20000) { Message({ message: res.message || 'Error', type: 'error', duration: 5 1000 }) // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; if (res.code === 50008 || res.code === 50012 || res.code === 50014) { // to re-login MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { confirmButtonText: 'Re-Login', cancelButtonText: 'Cancel', type: 'warning' }).then(() => { store.dispatch('user/resetToken').then(() => { location.reload() }) }) } return Promise.reject(new Error(res.message || 'Error')) } else { return res } },
后台API切换回Mock需改动
// 1 request.jsconst service = axios.create({ // baseURL: baseUrl, // url = base url + request url baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url // withCredentials: true, // send cookies when cross-domain requests timeout: 5000 // request timeout})// 2 user.js// params: data data// 3 user.js// method: 'post', method: 'get',
Token - 令牌
vuex的…mapMutations([‘前后端属于不同的域,导致每次ajax要求做事器都会当做新的用户访问,导致session丢失。当然也可以通过掩护cookie来让做事端辨识客户端,如axios.defaults.withCredentials=true;每次要求被认为是新客户端,产生新session问题,把稳session的膨胀;全局变量引入模板
弹窗
新建模板Test.vue利用import TestMode from './Test' // 导入相对路径的Test.vue...components: { TestMode }, // 注册组件<test-mode v-if=\"大众testPageVisible\公众 ref=\公众testMode2\公众 @refreshDataList=\公众getList\公众></test-mode><!-- 利用组件.getList是确定后的实行函数-->test(row) { // 这里是父组件 this.testPageVisible = true this.$nextTick(() => { this.$refs.testMode2.test(Object.assign({}, row)) // 调用子组件的函数 }) },methods: { test() { // 这里是Test.vue组件················· this.dialogFormVisible = true }}编辑器Json编辑器原版↓很糟糕
在这里插入图片描述利用json组件办理,待续布局九宫格|十六宫格事态紧急跨域用表格代替九宫格,不过不正规。正规的待续兼容办理IE兼容问题promise# 安装es6-promisenpm install es6-promise --save-devmain.js中引入ES6的polyfill
import Es6Promise from 'es6-promise'Es6Promise.polyfill();上文安装的promise只是针对性的,要彻底兼容IE还须要研究。