vue- 脚手架和组件

5.脚手架

基于vue+vue-router单文件开发,可以完成小规模的页面的开发,但如果项目大+组件多+依赖多,开发起来就非常不方便。

此时,脚手架 vue cli (vue cli - Vue Command Line Interface )是一个基于 Vue.js 进行快速开发的完整系统。

官方的说法:
Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。
通俗的说法:
他帮助我们构内置了很多组件来帮助我们更便捷的的开发vue.js项目。
 

5.1 安装

  • 第一步:想用脚手架 得安装node.js

    Vue CLI 4.x+ 需要 Node.js v8.9 或更高版本 (推荐 v10 以上)。

    https://nodejs.org/en/download/

    =======如果想要更新node.js的版本=======

    1.先查看本机node.js版本:
    node -v

    2.清除node.js的cache:
    sudo npm cache clean -f

    3.安装 n 工具,这个工具是专门用来管理node.js版本的,别怀疑这个工具的名字,是他是他就是他,他的名字就是 "n"
    sudo npm install -g n

    4.安装最新版本的node.js
    sudo n stable

    5.再次查看本机的node.js版本:
    node -v
  • 第二步:关于npm(node.js是一门变成语言 类似于python)

    安装上node之后,自带了npm包管理工具,类似于Python中的pip。

    如果想要更新npm到最新版,可以执行命令:
    sudo npm install npm@latest -g

  • 第三步:npm淘宝源,以后基于npm安装包就会快了(相当于豆瓣的pip源)

    npm config set registry https://registry.npm.taobao.org
  • 第四步:全局安装脚手架 vue-cli

    # 安装(最新版)
    sudo npm install -g @vue/cli

    # 安装(指定版本)
    sudo npm install -g @vue/cli@4.5.14

    # 卸载
    sudo npm uninstall -g @vue/cli

     

      

5.2 创建vue项目

cd /Users/wupeiqi/WebstormProjects // 打开终端 进入需要存放项目的文件
vue create mysite // 执行命令 项目名mysite

 

 

提示:babel是一个将ES6语法转化成ES5的工具,eslint是做语法检查。

a few moments later...

按照提示执行如下命令,脚手架就会给我们大家一个Web服务去运行编写的vue项目(便于开发测试)。

cd mysite
npm run serve

 

 

5.3 编译部署

项目创建完,脚手架会默认会生成如下文件(包含项目依赖、配置文件、默认代码)。

 

 

如果以后项目开发完毕,想要进行项目部署,是不需要这些文件的,需要npm进行编译 把编译之后的东西放到服务器上

执行命令:

cd 项目目录
npm run build // 编译当前项目

 

 

build会将项目中的依赖和代码自动编译成HTML、CSS、JavaScript代码,后续只需要将此代码上传至服务器部署即可。

5.4 目录结构

 1 脚手架本地开发的文件
 2 
 3 ```
 4 - babel.config.js      babel是ES6转换ES5的组件,这是他所需的配置文件(一般不需要动)。
 5 - package.json         项目所需的包的版本信息。
 6 - package-lock.json    保存项目所需的包细节以及包的依赖等信息。
 7 - node-modules         项目安装依赖包的文件保存的地方。例如:npm install axios 
 8                        axios包会保存在此目录、信息也会写在 package.json、package-lock.json中   
 9 - src
10     - main.js          项目的启动 npm run serve ,用户访问时程序的入门。
11     - App.vue           主组件(老父亲 由他来调用其他组件的 )
12     - components       子组件(以后写的组件都写在这里)
13     - assets           静态文件(自己的静态文件,会被压缩和合并)
14 - public              【此目录下的文件直接被复制到dist/目录下,一般放不动的数据,引入第三方】
15     - index.html       主HTML文件(模板引擎)
16     - favicon.icon     图标
17 - README.md            项目说明文档
18 ```
19 
20 ```
21 cd 项目
22 npm install  // 联合开发时候 只需要下载下来就可以开发别人的代码
23 ```
24 
25 本质上,其实就是将原来的代码做了拆分来进行开发,开发完毕之后再编译整合起来。
26 
27 ```html
28 <!DOCTYPE html>
29 <html lang="en">
30 <head>
31     <meta charset="UTF-8">
32     <title>Title</title>
33     <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
34 </head>
35 <body>
36 
37 <div id="app">
38     <h1>欢迎学习Vue.js</h1>
39     <div>我叫{{name}},微信{{wechat}}</div>
40 </div>
41 
42 <script>
43     
44     
45     var app = new Vue({
46         el: '#app',
47         data: {
48             name: '武沛齐',
49             wechat: 'wupeiqi888'
50         },
51         methods: {
52             clickMe: function () {
53                 this.name = "alex";
54                 this.wechat = "wupeiqi666";
55             }
56         }
57     })
58 </script>
59 </body>
60 </html>
61 ```
View Code

 

5.5 快速上手

需要安装两个组件在脚手架里

5.5.1 axios组件

Axios是一个基于 promise 的 HTTP 库,简单的讲就是可以发送get、post请求。

安装:

```
cd 项目目录
npm install axios
npm install vue-axios
```

导入 (main.js):

```
main.js

import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios) // 这两个东西挂载到vue对象里
```

使用:

```
Vue.axios.get(api).then((response) => {
  console.log(response.data)
})
// 或
this.axios.get(api).then((response) => { // this 就是当前vue对象
  console.log(response.data)
})
// 或
this.$http.get(api).then((response) => {
  console.log(response.data)
})
```

5.5.2 vue-router组件

 1 安装:
 2 
 3 ```
 4 cd 项目目录
 5 npm install vue-router@3 //vue2的项目建议用vue-router@3 
 6 ```
 7 
 8 引入:(components组件都写在这里router路由都写到这里)
 9 
10 ```javascript
11 // router/index.js
12 
13 // 第一步
14 import Vue from 'vue'
15 import VueRouter from 'vue-router'
16 
17 
18 import Home from '../components/Home' // 导入组件
19 
20 
21 Vue.use(VueRouter) // 让VueRouter挂载到vue对象里
22 
23 // 第二步编写路由对象
24 const router = new VueRouter({
25     routes: [
26         {
27             path: '/home',
28             name: "Home",
29             component: Home //组件
30         },
31     ]
32 })
33 // 第三步 导出 外部就可以引入router对象了
34 export default router
35 ```
36 
37 ```javascript
38 // main.js
39 import Vue from 'vue'
40 import axios from 'axios'
41 import VueAxios from 'vue-axios'
42 
43 
44 import App from './App.vue' // 引入App.vue组件
45 
46 // 第四步 导入router文件(加载了router生成了对象)
47 import router from "./router"
48 
49 
50 Vue.use(VueAxios, axios)
51 
52 Vue.config.productionTip = true
53 
54 
55 new Vue({ // 实例化对象
56     // 第五步
57     router: router,// router对象放在这里
58     render: h => h(App), // 用来做渲染的 render里返回的是什么 页面上就是什么 App是个组件
59 }).$mount('#app')//$mount进行挂载 也可以用 el:‘app’
60 ```
61 
62 使用:App.vue(路由的切换 都写这里router-link  router-view)
63 
64 ```
65 // 最后一步router-link  router-view  项目就可以运行起来了
66 
67 <router-link to="/home">点我</router-link>
68 <router-view></router-view>
69 ```
View Code

 

5.5.3 案例:路飞学城

基于vue-cli快速开发:路飞学城(第一版)( 对照着没用脚手架的第一版)

 

 

home组件:

 

 

course组件:

路由:

应用:

 

5.6 线上部署(项目写完了)

  • 第一步:编译

    npm run build
  • 第二步:将编译后的代码dist文件上传到服务器(阿里云、腾讯云)

     

     

  • 第三步:安装nginx + 配置 + 启动

    yum install nginx

 vim /etc/nginx/nginx.conf (修改配置)

 

 1 user nginx;
 2 worker_processes auto;
 3 error_log /var/log/nginx/error.log;
 4 pid /run/nginx.pid;
 5 
 6 # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
 7 include /usr/share/nginx/modules/*.conf;
 8 
 9 events {
10     worker_connections 1024;
11 }
12 
13 http {
14     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
15                       '$status $body_bytes_sent "$http_referer" '
16                       '"$http_user_agent" "$http_x_forwarded_for"';
17 
18     access_log  /var/log/nginx/access.log  main;
19 
20     sendfile            on;
21     tcp_nopush          on;
22     tcp_nodelay         on;
23     keepalive_timeout   65;
24     types_hash_max_size 4096;
25 
26     include             /etc/nginx/mime.types;
27     default_type        application/octet-stream;
28 
29     include /etc/nginx/conf.d/*.conf;
30 
31     server {
32         listen       80;
33         listen       [::]:80;
34         server_name  _;
35         # 项目目录 修改的地方
36         root         /data/mysite;
37 
38         # Load configuration files for the default server block.
39         include /etc/nginx/default.d/*.conf;
40 
41         error_page 404 /404.html;
42         location = /404.html {
43         }
44 
45         error_page 500 502 503 504 /50x.html;
46         location = /50x.html {
47         }
48     }
49 
50 
51 }
View Code

 

服务器上启动命令

>>>systemctl start nginx

第四步:访问

 

6.vuex

https://next.vuex.vuejs.org/zh/index.html

Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式 store。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态,以一种可预测的方式发生变化。

Vuex 的思想
当我们在页面上点击一个按钮,它会处发(dispatch)一个action, action 随后会执行(commit)一个mutation, mutation 立即会改变state, state 改变以后,我们的页面会state 获取数据,页面发生了变化。

Store 对象,包含了我们谈到的所有内容,action, state, mutation,所以是核心了

vuex的使用:

初始化store.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex)
// 实例化一个vuex存储库
const store = new Vuex.Store({
    state: {// 数据存储位置,相当于组件中的data
        test: 'x'
    },
    mutations: {// 操作数据的方法,相当于methods
        changetest(state, xxx) {
            state.test = xxx
        }
    },
    actions: {
        changetest(context, xxx) {
            context.commit('changetest', xxx)
        }
    },
  getters: {
      test2: state => state.test
  }
})
export default store;

 

state:相当于Vue的data state为单一状态树,在state中需要定义我们所需要管理的数组、对象、字符串等等,只有在这里定义了,在vue.js的组件中才能获取你定义的这个对象的状态。

mutations:类似于事件,每个 mutation 都有一个字符串的事件类型 (type)和 一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数

更改store中state状态的唯一方法就是提交mutation,就很类似事件。每个mutation都有一个字符串类型的事件类型和一个回调函数,我们需要改变state的值就要在回调函数中改变。我们要执行这个回调函数,那么我们需要执行一个相应的调用方法:store.commit。

actions: Action 类似于 mutation,不同在于Action 提交的是 mutation,而不是直接变更状态,Action 可以包含任意异步操作

action可以提交mutation,在action中可以执行store.commit,而且action中可以有任何的异步操作。

getters:可以认为是 store 的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,接受 state 作为其第一个参数

好了,就这么简单可以用了

使用Vuex

打开main.js,导入,然后用

import Vue from "vue";
import App from "./App.vue";
import store from "./store";

new Vue({
    store,
    render: h => h(App)
}).$mount("#app");

好了,你可以在所有App所有子组件里面使用Vuex了

如何使用 state

子组件能通过 this.$store 访问到

this.$store.state.test
// x

如何使用 mutations

子组件能通过 this.$store.commit 访问到

this.$store.commit('changetest',xxx)

它会去把 changetest 提交到 mutation 执行 ,第二个是载荷(可以理解为参数),大多数载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读

如何使用 actions

子组件能通过 this.$store.dispatch 访问到

this.$store.dispatch('changetest'xxx)

它会去把 changetest 分发到 actions 在通过 actions 提交到 mutation 执行

如何使用 getters

子组件能通过 this.$store.getters 访问到

this.$store.getters.test2
//x

 

 

 

说人话:将组件中需要共享的数据交给vuex来帮我们进行管理,例如:用户登录状态、加入购物车。

6.1 案例:登录

### 

```
vue create vxdemo  // 创建项目vxdemo
```

```
npm install vue-router@3 // 需要路由 所以装vue-router
```

```
npm install vuex@3 // 状态管理 用户登录成功后 改变登录的状态
```

 

 

  1 - main.js
  2 
  3   ```javascript
  4   import Vue from 'vue'
  5   import App from './App.vue'
  6   import router from "./router"
  7   import store from "./store"
  8   
  9   Vue.config.productionTip = false
 10   
 11   new Vue({
 12       router: router,
 13       store: store,
 14       render: h => h(App),
 15   }).$mount('#app')
 16   ```
 17 
 18 - App.vue
 19 
 20   ```vue
 21   <template>
 22       <div id="app">
 23           <div class="menu">
 24               <div class="container">
 25                   <router-link to="/home">首页</router-link>
 26                   <router-link to="/course">课程</router-link>
 27   
 28                   <div style="float: right">
 29                       <a v-if="this.$store.state.isLogin"> // 如果state状态是True 
 30                           {{this.$store.state.userInfo.username}} //显示用户名
 31                       </a>
 32                       <router-link v-else to="/login">登录</router-link>
 33   
 34                   </div>
 35               </div>
 36           </div>
 37           <div class="container">
 38               <router-view></router-view>
 39           </div>
 40       </div>
 41   </template>
 42   <script>
 43       export default {
 44           name: 'App',
 45           data() {
 46               return {}
 47           },
 48           components: {},
 49       }
 50   </script>
 51   
 52   <style>
 53       body {
 54           margin: 0;
 55       }
 56       .container {
 57           width: 1100px;
 58           margin: 0 auto;
 59       }
 60       .menu {
 61           height: 48px;
 62           background-color: #499ef3;
 63           line-height: 48px;
 64   
 65       }
 66       .menu a {
 67           color: white;
 68           text-decoration: none;
 69           padding: 0 10px;
 70       }
 71   </style>
 72   ```
 73 
 74 - store/index.js(vuex代码相关逻辑)
 75 
 76   ```javascript
 77   import Vue from 'vue'
 78   import Vuex from 'vuex'
 79   
 80   Vue.use(Vuex)
 81   
 82   
 83   export default new Vuex.Store({ // 实例化对象并导出
 84       state: { // 存储的数据 状态 其他页面可以调用state
 85           isLogin: false, //是否登录
 86           userInfo: null //用户信息
 87       },
 88       mutations: { // 改状态  更改Vuex的store中的状态的唯一方法是提交mutation
 89           login: function (state, info) {
 90               state.userInfo = info; // info 是个对象里面有用户名和密码
 91               state.isLogin = true;
 92           },
 93   
 94       },
 95       actions: {}
 96   })
 97   
 98   ```
 99 
100 - router/index.js
101 
102   ```javascript
103   // router/index.js
104   
105   import Vue from 'vue'
106   import VueRouter from 'vue-router'
107   
108   
109   import Home from '../components/Home'
110   import Course from '../components/Course'
111   import Login from '../components/Login'
112   
113   
114   Vue.use(VueRouter)
115   
116   const router = new VueRouter({
117       routes: [
118           {
119               path: '/home',
120               name: "Home",
121               component: Home
122           },
123           {
124               path: '/course',
125               name: "Course",
126               component: Course
127           },
128           {
129               path: '/login',
130               name: "Login",
131               component: Login
132           },
133       ]
134   })
135   
136   export default router
137   ```
138 
139 - components/Login.vue
140 
141   ```html
142   <template>
143       <div>
144           <input type="text" v-model="info.username" placeholder="用户名">
145           <input type="password" v-model="info.password" placeholder="密码">
146           <input type="button" value="登录" @click="doLogin"/>
147       </div>
148   </template>
149   
150   <script>
151       export default {
152           name: "Login",
153           data() {
154               return {
155                   info: {
156                       username: "",
157                       password: ""
158                   }
159               }
160           },
161           methods: {
162               doLogin: function () {
163                   // 1.用户登录
164                   this.$store.commit('login', this.info);
165                   // 2.登录成功修改状态 跳转到home页面
166                   this.$router.push({name: 'Home'});
167               }
168           }
169       }
170   </script>
171   
172   <style scoped>
173   
174   </style>
175   ```
View Code

 

6.2 关于computed属性

在vue的组件中有一个computed属性(计算属性),监听关联的数据,如果发生变化则重新计算并显示。

<template>
    <div>
        <h1>主页 {{v1}} {{ v2}}</h1> // 两个变量
        
        <div>总数:{{totalData}}</div> // 自动执行get方法 得到返回值
        <input type="button" value="点我" @click="addData"/>
    </div>
</template>

<script>
    export default {
        name: "Home",
        data() {
            return {
                v1: 123,// 声明两个变量
                v2: 456
            }
        },
        computed: {
            totalData: { 
                get() { // 读取
                    let data = this.v1 + this.v2;
                    return data + 1000;
                },
                set(value) { // 设置
                    this.v1 = value;
                }
            }
        },
        methods: {
            addData() {
                this.totalData = 999;// totalData是计算属性 先执行set方法 把值放在value里 赋值的时候想怎么写怎么写 get也会相应变化
                // this.v2 = 1000; // 直接修改v2,get返回值肯定发生变化
            }
        }
    }
</script>

<style scoped>

</style>

所以,上述案例也可以用computed属性来实现,例如:App.vue改成:

 1 <template>
 2     <div id="app">
 3         <div class="menu">
 4             <div class="container">
 5                 <router-link to="/home">首页</router-link>
 6                 <router-link to="/course">课程</router-link>
 7 
 8                 <div style="float: right">
 9                     <a v-if="userState"> // 通过计算属性实现
10                         {{userName}} // 通过计算属性实现
11                     </a>
12                     <router-link v-else to="/login">登录</router-link>
13 
14                 </div>
15             </div>
16         </div>
17         <div class="container">
18             <router-view></router-view>
19         </div>
20     </div>
21 </template>
22 
23 <script>
24 
25     export default {
26         name: 'App',
27         data() {
28             return {}
29         },
30         computed: {// 计算属性
31             userState: { // 只读 没有赋值
32                 get() {
33                     return this.$store.state.isLogin;
34                 }
35             },
36             userName() {// 只有只读可以简写
37                 return this.$store.state.userInfo.username;
38             },
39 
40         },
41         components: {},
42     }
43 </script>
44 
45 <style>
46     body {
47         margin: 0;
48     }
49 
50     .container {
51         width: 1100px;
52         margin: 0 auto;
53     }
54 
55     .menu {
56         height: 48px;
57         background-color: #499ef3;
58         line-height: 48px;
59 
60     }
61 
62     .menu a {
63         color: white;
64         text-decoration: none;
65         padding: 0 10px;
66     }
67 
68 
69 </style>
View Code

 

6.3 案例:购物车

 

购物车搞成一个组件

1、创建一个组件car、

 

 

2、组件应用(固定的放在某个位置)

 

 

6.4 关于Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。

  • Action 可以包含任意异步操作。

  •  1 代码示例:
     2 
     3 ```javascript
     4 const store = createStore({
     5   state: {
     6     count: 0
     7   },
     8   mutations: {
     9     increment (state) {
    10       state.count+=1; //更新state状态
    11     }
    12   },
    13   actions: { // 一般没用 有异步操作就有用了
    14      
    15     increment (context) {
    16         // 触发mutations
    17           context.commit('increment')
    18     }
    19   }
    20 })
    21 ```
    22 
    23 在组件中如果要触发action,则应该执行:
    24 
    25 ```javascript
    26 this.$store.dispatch('increment')
    27 ```
    28 
    29 
    30 
    31 这就有点像脱裤子放屁,意义何在呢? 当有异步操作时,应该使用action、而不是mutation,例如:
    32 
    33 ```javascript
    34 import Vue from 'vue'
    35 import Vuex from 'vuex'
    36 
    37 Vue.use(Vuex)
    38 
    39 
    40 export default new Vuex.Store({
    41     state: {
    42         isLogin: false, //是否登录
    43         userInfo: null, //用户信息
    44         carNumber: 0,
    45         xxxxx: 10
    46     },
    47     mutations: {
    48         login: function (state, info) {
    49             state.userInfo = info;
    50             state.isLogin = true;
    51         },
    52         addCar: function (state) {
    53             state.carNumber += 1;
    54         },
    55        
    56         fetchAsync: function (state) {
    57             //  // 异步操作 发送ajax请求
    58             setTimeout(function () {
    59                 state.xxxxx += 1;
    60             }, 1000); // 1秒后 状态改变
    61         }
    62 
    63     },
    64     actions: {}
    65 })
    66 
    67 ```
    68 
    69 ```
    70 // 按钮执行函数
    71 this.$store.commit("fetchAsync");
    72 ```
    73 
    74 从效果上看是没有问题的,但是通过开发者工具就会发现,监测到的state的数据不准确。
    75 
    76 官方图说 如果发送异步请求应该在actions里做  异步做完了回调函数再去做mutations 在去更改state状态  在mutations 安装一个浏览器插件devtools可以监听里面的状态的值(老师给的文件里有)
    View Code

     

 

 

所以,这种情况可以选择用Action。

```javascript
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)


export default new Vuex.Store({
    state: {
        isLogin: false, //是否登录
        userInfo: null, //用户信息
        carNumber: 0,
        xxxxx: 10
    },
    mutations: {
        login: function (state, info) {
            state.userInfo = info;
            state.isLogin = true;
        },
        addCar: function (state) {
            state.carNumber += 1;
        },
        fetchAsync: function (state,data) {
            state.xxxxx += 1;
            console.log(data);
        }

    },
    actions: { // 异步动作写在这 异步动作执行完再去改状态 能够保证mutations 里的状态值和整体是一样的
        fetchAsync: function (context,data) {
            setTimeout(function () {
                context.commit("fetchAsync",data);
            }, 1000);
        }
    }
})

```

再触发时,调用:

```
this.$store.dispatch('fetchAsync',{ amount: 10})
```

7.flex布局

在CSS3中flex可以非常便捷的可以帮助我们实现对页面的布局。

  • 传统的页面布局,基于div+float来实现。

  • flex可以快速实现页面的布局(很方便)。

关于flex布局你必须要了解的有一下几点:

<div class="menu" 样式>// 容器里加样式
    <div class="item" 样式>112</div> // 在元素里加样式
    <div class="item">113</div>
</div>

7.1 容器

7.1.1 flex布局

在容器元素上应用

<div class="menu">
    <div class="item">112</div>
    <div class="item">113</div>
</div>

<style>
    .menu{
        border: 1px solid red;
        width: 500px;
        display: flex;         // 表示flex布局
    }
</style>

7.1.2 元素的方向(主轴和副轴)

<div class="menu">
    <div class="item">112</div>
    <div class="item">113</div>
</div>
<style>
    .menu{
        border: 1px solid red;
        width: 500px;
        
        display: flex;         // 表示flex布局
        flex-direction: row;   // row主轴是横向,副轴是纵向。column是主轴是纵轴
    }
</style>

7.1.3 元素排列方式

justify-content,主轴上的元素的排列方式
align-items,副轴上的元素的排列方式。

 

 

<div class="menu">
    <div class="item">11</div>
    <div class="item">112</div>
    <div class="item">112</div>
</div>
<style>
    .menu {
        width: 500px;
        border: 1px solid red;
        display: flex;

        flex-direction: row; // row主轴是横向,副轴是纵向
        justify-content: flex-start;     /* 主轴=横向,横向从左开始 */
        justify-content: flex-end;       /* 主轴=横向,横向从右开始 */
        justify-content: space-between;   /* 主轴=横向,左右定格,中间元素等分空白 */
        justify-content: space-around;   /* 主轴=横向,所有元素等分空白 */
        justify-content: space-evenly;   /* 主轴=横向,元素间距一样 */
    }

    .item {
        border: 1px solid green;
        padding: 5px 50px;
        height: 50px;
        width: 40px;
    }
</style>

 

 

<div class="menu">
    <div class="item">11</div>
    <div class="item">112</div>
    <div class="item">112</div>
</div>
<style>
    .menu {
        width: 500px;
        height: 300px;
        border: 1px solid red;
        display: flex;

        flex-direction: row;
        justify-content: flex-start;     /* 主轴=横向,横向从左开始 */
        justify-content: flex-end;       /* 主轴=横向,横向从右开始 */
        justify-content: space-between;   /* 主轴=横向,左右定格,中间元素等分空白 */
        justify-content: space-around;   /* 主轴=横向,所有元素等分空白 */
        justify-content: space-evenly;   /* 主轴=横向,元素间距一样 */

        align-items: center;             /* 副轴=纵向,元素居中*/
        align-items: flex-start;         /* 副轴=纵向,元素顶部*/
        align-items: flex-end;           /* 副轴=纵向,元素底部*/
    }

    .item {
        border: 1px solid green;
        padding: 5px 50px;
        height: 50px;
        width: 40px;
    }
</style>

7.1.4 换行

  • flex-wrap: nowrap; 元素超过容器,不换行

  • flex-wrap: wrap; 元素超过容器,换行

示例1:不换行

 

 

<div class="menu">
    <div class="item">11</div>
    <div class="item">112</div>
    <div class="item">112</div>
    <div class="item">112</div>
    <div class="item">112</div>
</div>
<style>
    .menu {
        width: 500px;
        height: 200px;
        border: 1px solid red;
        display: flex;

        flex-direction: row;
        justify-content: space-evenly;   /* 主轴=横向,元素间距一样 */
        align-items: flex-start;         /* 副轴=纵向,元素顶部*/

        flex-wrap: nowrap;

    }

    .item {
        border: 1px solid green;
        padding: 5px 50px;
        height: 50px;
        width: 40px;
    }
</style>

示例2:换行

<div class="menu">
    <div class="item">111</div>
    <div class="item">112</div>
    <div class="item">112</div>
    <div class="item">112</div>
    <div class="item">112</div>

</div>

<style>
    body{ // 清除浏览器中默认的body的内外边距
        margin: 0;
    }
    .menu {
        width: 500px;
        height: 200px;
        border: 1px solid red;
        display: flex;

        flex-direction: row;
        justify-content: space-evenly;   /* 主轴=横向,元素间距一样 */
        align-items: flex-start;         /* 副轴=纵向,元素顶部*/

        flex-wrap: wrap;

    }

    .item {
        border: 1px solid green;
        padding: 5px 50px;
        height: 50px;
        width: 40px;
    }
</style>

7.1.5 多行对齐方式

align-content用于控制多行元素的对齐方式,如果元素只有一行则不会起作用;默认stretch,即在元素没设置高度,或高度为auto情况下让元素填满整个容器。

align-content:flex-start;

flex-start | flex-end | center | space-between | space-around | space-evenly | stretch(默认);

7.2 元素

7.2.1 顺序

order,默认0,用于决定项目排列顺序,数值越小,项目排列越靠前。

 

 

<div class="father">
    <div class="son" style="order: 2">11</div>
    <div class="son" style="order: 0">22</div>
    <div class="son" style="order: 1">33</div>
</div>

<style scoped>
    .father {
        border: 1px solid red;
        width: 500px;
        height: 300px;
        display: flex;
        flex-direction: row;
        justify-content: flex-start;
    }

    .father .son {
        border: 1px solid saddlebrown;
        width: 20px;
        height: 18px;
    }
</style>

7.2.2 剩余空间(是否占满)

flex-grow,默认0,用于决定项目在有剩余空间的情况下是否放大,默认不放大;

<div class="father">
    <div class="son">11</div>
    <div class="son" style="flex-grow: 1">22</div>
    <div class="son" style="flex-grow: 1">33</div>
</div>

案例:flex页面布局(小米商城布局)

 

 

  1 <template>
  2     <div>
  3         <div class="row1">
  4             <div class="company"></div>
  5             <div class="pic"></div>
  6             <div class="pic"></div>
  7             <div class="pic"></div>
  8         </div>
  9         <div class="row2">
 10             <div class="title">
 11                 <div>手机</div>
 12                 <div>查看更多</div>
 13             </div>
 14             <div class="pic-list">
 15                 <div class="big"></div>
 16                 <div class="right-list">
 17                     <div class="group">
 18                         <div class="phone"></div>
 19                         <div class="phone"></div>
 20                         <div class="phone"></div>
 21                         <div class="phone"></div>
 22                     </div>
 23                     <div class="group">
 24                         <div class="phone"></div>
 25                         <div class="phone"></div>
 26                         <div class="phone"></div>
 27                         <div class="phone"></div>
 28                     </div>
 29 
 30                 </div>
 31             </div>
 32         </div>
 33 
 34         <div class="course-list">
 35             <div class="item"></div>
 36             <div class="item"></div>
 37             <div class="item"></div>
 38             <div class="item"></div>
 39             <div class="item"></div>
 40 
 41         </div>
 42     </div>
 43 </template>
 44 
 45 <script>
 46     export default {
 47         name: "Mi"
 48     }
 49 </script>
 50 
 51 <style scoped>
 52     //  .row1 样式
 53     .row1 {
 54         display: flex;
 55         flex-direction: row;
 56         justify-content: space-between;
 57     }
 58 
 59     .row1 .company {
 60         width: 210px;
 61         height: 180px;
 62         background-color: saddlebrown;
 63     }
 64 
 65     .row1 .pic {
 66         width: 266px;
 67         height: 180px;
 68         background-color: cadetblue;
 69     }
 70     //  .row2 样式
 71     .row2 .title {
 72         display: flex;
 73         flex-direction: row;
 74         justify-content: space-between;
 75     }
 76 
 77     .row2 .pic-list {
 78         display: flex;
 79         flex-direction: row;
 80         justify-content: space-between;
 81     }
 82 
 83     .row2 .pic-list .big {
 84         background-color: aquamarine;
 85         height: 610px;
 86         width: 210px;
 87         margin-right: 20px;
 88     }
 89 
 90     .row2 .pic-list .right-list {
 91         /*background-color: antiquewhite;*/
 92         flex-grow: 1;
 93     }
 94 
 95     .row2 .pic-list .right-list .group {
 96 
 97 
 98         display: flex;
 99         flex-direction: row;
100         justify-content: space-between;
101         flex-wrap: wrap;
102     }
103 
104     .row2 .pic-list .right-list .phone {
105         margin-bottom: 10px;
106         border: 1px solid red;
107         width: 200px;
108         height: 300px;
109     }
110 
111     .course-list {
112         display: flex;
113         justify-content: space-between;
114         flex-wrap: wrap;
115     }
116 
117     .course-list .item {
118         width: 24%;
119         height: 100px;
120         background-color: skyblue;
121         margin-top: 15px;
122     }
123     
124     // 如果最后一个元素,是第3个,右边距=一个位置 + 所有空白位置/3(有三个空白位置)
125     .course-list .item:last-child:nth-child(4n - 1) {
126         margin-right: calc(24% + 4% / 3);
127     }
128 
129     // 如果最后一个元素,是第2个,右边距=两个位置 + 所有空白位置/3*2(有三个空白位置)
130     .course-list .item:last-child:nth-child(4n - 2) {
131         margin-right: calc(48% + 8% / 3);
132     }
133 </style>
View Code

 

至此,结合以上的知识点,我们就可以来开发一个项目,但很多的页面按钮、标签、提示框等都需要自己手动,太费劲。

所以,接下来就要给大家的来聊一个UI框架 - ElementUI,他的内部提供了很多方便的样式和组件,可以加速我们开发。

8.ElementUI

Element,是有 饿了吗 团队开发一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的组件库(也支持vue3.x)。

在他的基础上来开发,可以大大提升开发进度。

 

 想要在项目中进行使用element-ui需要提前安装并引入。

8.1 引入

 

方式1:完整引入

- 安装 ``` cd 项目目录 npm install element-ui ``` - 引入 ```javascript import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; // 主题 颜色背景 import App from './App.vue'; Vue.use(ElementUI); // 引入 use一下就可以了 new Vue({ render: h => h(App), }).$mount('#app') ``` - 在组件中使用 ```html <el-button type="success">哈哈哈</el-button> ``` **方式2**:局部引入 - 安装 ``` cd 项目目录 npm install element-ui ``` - 引入 ```javascript import Vue from 'vue'; import { Button, Select } from 'element-ui'; // 引入指定组件 import 'element-ui/lib/theme-chalk/index.css'; import App from './App.vue'; Vue.use(Button) Vue.use(Select) new Vue({ render: h => h(App), }).$mount('#app') ``` - 在组件中使用 ```html <el-button type="success">哈哈哈</el-button> ``` 完整组件名称:https://element.eleme.cn/#/zh-CN/component/quickstart

 

8.2 组件的使用

参见官方文档,在后续的项目开发中来应用并使用。

 

 

 

 

 

 

 

 

 

 

 

posted @ 2022-07-07 15:24  贰号猿  阅读(307)  评论(0)    收藏  举报