1 vue安装 1.1 直接用 script标签引入 对于制作原型或学习,你可以这样使用最新版本:
1 <script src ="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" > </script >
对于生产环境,我们推荐链接到一个明确的版本号和构建文件,以避免新版本造成的不可预期的破坏:
1 <script src ="https://cdn.jsdelivr.net/npm/vue@2.6.11" > </script >
1.2 NPM创建 1 2 3 4 5 6 7 8 //安装vue npm install vue npm install -g @vue/cli //创建vue项目 vue create project_name //q cd project_namenpm run serve
1.3 使用HbuilderX创建vue项目
1.4 快速启动vue-element-admin 1 2 3 4 5 6 7 8 9 10 11 git clone https://github.com/PanJiaChen/vue-admin-template.git cd vue-admin-templatenpm install npm run dev
2 vue执行顺序
3 vue基础语法 4 vue特性 5 组件 5.1 定义组件的固定写法: 1 2 3 4 5 6 7 8 9 10 11 12 <template> ... //这里写组件中的HTML代码,可复用 </template> <script> ... //这里写一些动态的脚本 </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> ... //这里写一些样式,如果加上scoped则表示当前样式仅限该组件使用,一般组件中的样式都是局部样式 </style>
5.2 vue
官方的helloworld
组件写法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <template> <div class="hello"> //一般会在模板中定义一个大盒子,否则会报一个如图2所示的错误 <h1>{{ msg }}</h1> <p> For a guide and recipes on how to configure / customize this project,<br> check out the <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>. </p> <h3>Installed CLI Plugins</h3> <ul> <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li> <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li> </ul> <h3>Essential Links</h3> <ul> <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li> <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li> <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li> <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li> <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li> </ul> <h3>Ecosystem</h3> <ul> <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li> <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li> <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li> <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li> <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li> </ul> </div> </template> <script> export default { name: 'HelloWorld', props: { //从外部获取参数,组件之间传递参数 msg: String } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
5.3 使用自定义组件 1 2 3 4 5 6 <div id="app"> //写法1,其中的msg是传到到组件中的参数,msg必须与组件中定义的接收变量一致,等于号后面的部分至变量值 <HelloWorld msg="this parma is from props"/> //写法2 <HelloWorld msg="this parma is from props"></HelloWorld> </div>
6 组件间通信 6.1 方式1-props/$emit
父组件A 向 子组件B 传递数据 通过props
的方法
子组件B 向 父组件A 发送数据 通过emit
使用该方式传递参数时,官方提供 了两种写法:
写法1:
为了简化代码,可以使用数组的写法
1 props: ['var1', 'var2', ...]
写法2:
如果你想指定每一个变量的类型,可以使用对象的写法
1 2 3 4 5 6 7 8 props: { var1: String, var2: Number, var3: Boolean, var4: Array, var5: Object, var6: Function }
prop的特性(单向数据流) 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定 :父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不 应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
props 只可以从上一级组件传递到下一级组件,也就是父子组件,即这就是单向数据流
props是只读,不可以被修改,所有被修改都会失效和被警告
注意:
注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会 影响到父组件的状态。
示例1(父组件向子组件传递数据) father.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <template> <div class="father"> in father : {{msg}} <son :msg="[1,2,3,4,5]"></son> </div> </template> <script> import son from "./son.vue" export default { name: 'father', components: { son }, props: { msg: String } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .father { border: #000000 1px solid; } </style>
son.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template> <div class="son"> in son: <h1 v-for="(item,index) in msg" :key="index">{{item}}</h1> </div> </template> <script> export default { name: 'son', props: { msg: Array } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .son { border: red 1px solid; margin: 5px;; } </style>
app.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <template> <div id="app"> <fater msg="this is father"/> </div> </template> <script> import fater from './components/fater.vue' export default { name: 'app', components: { fater } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
main.js
:
1 2 3 4 5 6 7 8 9 import Vue from 'vue' import App from './App.vue' Vue .config .productionTip = false new Vue ({ el : "#app" , render : h => h (App ), });
效果:
示例2(子组件向父组件传递参数) father.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <template> <div class="father"> in father : {{msg}} <son :msg="sonList" @onEmitIndex="onEmitIndex"></son> <p>{{currentIndex}}</p> </div> </template> <script> import son from "./son.vue" export default { name: 'father', components: { son }, props: { msg: String }, data() { return { currentIndex: -1, sonList: ['小白', '小红', '小蓝', '小绿'] } }, methods: { onEmitIndex(idx) { this.currentIndex = idx } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .father { border: #000000 1px solid; } </style>
son.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <template> <div class="son"> <h3 v-for="(item, index) in msg" :key="index" @click="emitIndex(index)">{{index}} {{item}}</h3> </div> </template> <script> export default { name: 'son', props: { msg: Array }, methods: { emitIndex(index) { this.$emit('onEmitIndex', index) } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .son { border: red 1px solid; margin: 5px; } </style>
其他文件与上面的例子保持一致,效果如下:
当你点击子组件中的某一行时,会子组件中的行索引打印在父组件中。
6.2 vuex 6.2.0 搭建vuex环境: 可以直接在命令行输入以下命令安装插件
也可以在项目的package.json
文件中的dependencies
属性下添加一行记录,然后执行npm install
更新项目的依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 { "name" : "default" , "version" : "0.1.0" , "private" : true , "scripts" : { "serve" : "vue-cli-service serve" , "build" : "vue-cli-service build" } , "dependencies" : { "core-js" : "^2.6.5" , "vue" : "^2.6.10" , "vuex" : "^3.1.0" } , "devDependencies" : { "@vue/cli-plugin-babel" : "^3.8.0" , "@vue/cli-service" : "^3.8.0" , "vue-template-compiler" : "^2.6.10" } }
6.2.1 如果不用vuex 如果不用vuex,那么多个组件之间如果需要公用某一个变量,我们称之为state
,那么使用props/emit
是如何通信的呢
6.2.2 示例 目录结构:
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 import Vue from 'vue' import App from './App.vue' import store from './store' Vue.config.productionTip = false new Vue({ el: '#app', store, render: h => h(App), })
main.js
:
1 2 3 4 5 6 7 8 9 10 11 import Vue from 'vue' import App from './App.vue' import store from './store' Vue .config .productionTip = false new Vue ({ el : '#app' , store, render : h => h (App ), })
Father.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <template> <div id="app"> <Father></Father> <Son></Son> <h1> IN FATHER</h1> <h1>num = {{$store.state.num}}</h1><br /> <button @click="selfadd">加1</button><br /> <button @click="selfsub">减1</button><br /> </div> </template> <script> import Father from './components/Father.vue' import Son from './components/Son.vue' export default { name: 'app', components: { Father, Son }, methods: { selfadd() { this.$store.dispatch('selfadd', 1) }, selfsub() { this.$store.dispatch('selfsub', 1) } } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; padding: 5px; border: #002B36 1px solid; } </style>
Son.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <template> <div class="son"> <h1> IN SON</h1> <h1>num = {{$store.state.num}}</h1><br /> </div> </template> <script> export default { name: 'Son' } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .son { border: #0000FF 1px solid; margin: 5px; } </style>
store/index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import Vuex from 'vuex' import Vue from 'vue' Vue .use (Vuex )const actions = { selfadd (context, value ) { console .log ("actions is run" , context, value) context.commit ('SELFADD' , value) }, selfsub (context, value ) { console .log ("actions is run" , context, value) context.commit ('SELFSUB' , value) } } const mutations = { SELFADD (state, value ) { console .log ("mutaions SELFADD is run" , state, value) state.num += value }, SELFSUB (state, value ) { console .log ("mutaions SELFSUB is run" , state, value) state.num -= value } } const state = { num : 0 } export default new Vuex .Store ({ actions, mutations, state })
效果:在App
组件中操作vuex管理的变量num
,则所有使用到该变量的地方都发生了变化
7 路由 通过路由请求后端接口数据,所有这里使用axios
来作为ajax
工具。
7.1 安装vue-router
7.2 示例 目录结构:
About.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <template> <div class="about"> <h1>IN About</h1><br /> </div> </template> <script> export default { name: 'About', } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .about { border: #002B36 1px solid; margin: 5PX;; } </style>
GetUserInfo.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <template> <div class="userinfo"> <h1>IN GetUserInfo</h1><br /> 请求参数:{{this.$route.query.name}} //vue-router插件会给所有组件身上安装一个$route属性,该属性下有一个query用来存放query型参数 <h1> userinfo : <p v-if="hasInfo">{{ userinfo }}</p> <p v-else>null</p> </h1> {{name}} </div> </template> <script> import axios from "axios" export default { name: 'GetUserInfo', data() { return { userinfo: {}, hasInfo: false } }, mounted() { axios.get('http://www.zhgblog.com:84/getUserInfo', { params: {name: this.$route.query.name} }) .then( response => { this.hasInfo = true this.userinfo = response.data.data console.log(response.data) }, error => { this.userinfo = error.message console.log('error :' + error.message) } ) } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .userinfo { border: #000000 1px solid; margin: 5PX; ; } </style>
main.js
:
1 2 3 4 5 6 7 8 9 10 11 import Vue from 'vue' import App from './App.vue' import router from './router/index.js' Vue .config .productionTip = false new Vue ({ el : "#app" , router, render : h => h (App ) })
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <template> <div id="app"> IN APP<br /> <router-link to="/about" class='btn' active-class="active">about</router-link><br /> <router-link to="/get-user-info?name=vuetest" class='btn' active-class="active">getUserInfo</router-link> <router-view></router-view> </div> </template> <script> import GetUserInfo from './components/GetUserInfo.vue' import About from './components/About.vue' export default { name: 'app', components: { GetUserInfo } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; border: #0000FF 2px solid; } .btn { background-color: #F06431; display: block; color: #ffffff; width: 80px; height: 20px; padding: 5px; margin: 10px; border: #0000FF 2px solid; } .active { background-color: #002B36; } </style>
router/index.js
定义路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import Vue from "vue" import VueRouter from "vue-router" import About from '../components/About.vue' import GetUserInfo from '../components/GetUserInfo.vue' Vue .use (VueRouter )export default new VueRouter ({ routes : [ { path : '/about' , component : About }, { path : '/get-user-info' , component : GetUserInfo } ] })
效果:
8 打包部署上线 进入项目目录,然后执行以下命令:
如果执行以上命令,出现以下错误信息:
1 npm ERR! missing script: build
解决方法:
打开项目文件夹中的package.json
文件,查看其中的scripts
参数:
1 2 3 4 5 6 7 8 9 10 "scripts" : { "dev" : "vue-cli-service serve" , "build:prod" : "vue-cli-service build" , "build:stage" : "vue-cli-service build --mode staging" , "preview" : "node build/index.js --preview" , "svgo" : "svgo -f src/icons/svg --config=src/icons/svgo.yml" , "lint" : "eslint --ext .js,.vue src" , "test:unit" : "jest --clearCache && vue-cli-service test:unit" , "test:ci" : "npm run lint && npm run test:unit" } ,
可以看到,配置文件中没有配置build
,所以可以使用npm run build:prod
或npm run build:stage
,
打包完成之后的提示信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 webpack performance recommendations: You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application. For more info visit https://webpack.js.org/guides/code-splitting/ File Size Gzipped dist\static\js\chunk-elementUI.ae962d5 654.28 KiB 160.36 KiB 6.js dist\static\js\chunk-libs.6e57f8be.js 374.55 KiB 130.09 KiB dist\static\js\app.3616c27f.js 52.53 KiB 16.33 KiB dist\static\css\chunk-elementUI.68c70a 227.82 KiB 34.54 KiB d5.css dist\static\css\app.4af63d88.css 16.01 KiB 3.44 KiB dist\static\css\chunk-libs.3dfb7769.cs 3.48 KiB 1.25 KiB s Images and other types of assets omitted. DONE Build complete. The dist directory is ready to be deployed. INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html
然后发现项目目录文件夹中多了一个dist
目录,将该目录中的文件拷贝到nginx
服务器的文件夹中,不要将dist
文件夹拷贝过去,应该将dist
文件夹里面的文件拷贝过去。
Reference
写在最后 欢迎大家关注鄙人的公众号【麦田里的守望者zhg】,让我们一起成长,谢谢。