Vue P05-项目化

快速构建项目

当下潮流的做法一般采用前后端分离的方式进行Web架构,但同时也对前端开发环境的搭建提出了更高的要求。

一个完整的前端开发环境应该具备预编译模板、注入依赖、合并压缩资源、分离开发和生产环境及提供一个模拟的服务端环境等功能

项目快速构建工具–Vue CLI

Vue CLI简介

可用于快速搭建带有热重载(在代码修改后不必刷新页面即可呈现修改后的效果)、lint代码语法检测及构建生产版本等功能的单页面应用

使用Vue CLI构建项目

1、打开控制台,输入:

cnpm install vue-cli -g

安装Vue CLI,尚未安装cnpm的同学可以输入

npm install cnpm -g --registry=https://registry.npm.taobao.org

安装国内淘宝镜像源的cnpm

命令执行结束后,输入

vue --version

输出版本号,安装成功

2、在项目所要放置的文件目录下打开控制台,输入:

vue init webpack my-project

初始化项目(my-project为项目名称)

3、在模板下载完成后,Vue CLI将引导我们进行项目配置,笔者的配置如图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O8WONfkj-1657769007435)(C:\Users\Toreme\AppData\Roaming\Typora\typora-user-images\image-20220322001231673.png)]

其中, “Set up unit tests” 和“Setup e2e tests with Nightwatch”选择“no”,这部分内容与Vue没有直接关系,这里
不予探讨。最后一项也选择“no”是因为npm的镜像源在国外,安装依赖的速度缓慢且容易出错,笔者建议使用cnpm安装依赖。

4、输入

cnpm install

安装项目依赖

5、输入

npm start

构建项目的开发版本,并启动webpack-dev-server

此时,在浏览器地址栏输入http://localhost:8080即可访问项目,项目页面为大V

6、之后,另开一个控制台,输入

npm run build

构建项目的生产版本

项目目录介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-omIQiZlP-1657769007437)(C:\Users\Toreme\AppData\Roaming\Typora\typora-user-images\image-20220322001826167.png)]

main.js是webpack的入口文件

App.vue是Vue CLI为我们默认创建的项目的根组件

  • VueCLI采用关注点分离的开发方式,这种开发方式使得组件的内聚性更强,也更适合于组件化的开发
  • script标签中的内容为Vue组件:template标签中的内容为组件的DOM结构;style标签中的内容为CSS样式表(在被赋予scoped属性之后,样式表的作用域仅限在当前组件中)
  • export和import是ECMAScript6语法中用于模块化管理的两个关键字,这里使用export导出Vue组件以供外部调用

Vue CLI会将所有编译整理好的资源路径注入到以index.html为模板的镜像中,被注入后的镜像即生产版本中项目的入口文件,也就是dist文件目录下的index.html,这里的元素才是实例最终被挂载的地方。

在src文件目录下,还有一个重要的文件–使用Vue Router配置的router/index.js 有关Vue Router的内容,笔者将放到下一节中进行讲述

前端路由

路由这个概念首先出现在后台。传统MVC架构的web开发,由后台设置路由规则,当用户发送请求时,后台根据设定的路由规则将数据渲染到模板中,并将模板返回给用户。每一次请求就要刷新一次页面,十分影响交互体验

AJAX(Asynchronous Javascript And Xml),异步加载数据的方式实现页面局部刷新。异步交互体验

---->SPA——单页面应用,不仅页面交互无刷新,甚至页面跳转也可以无刷新,前端路由随之应运而生

前端路由的简单实现

广义:根据URL来分发视图,核心操作

  • 监听浏览器地址的变化
  • 动态加载视图
const http=require('http')
const fs=require('fs')
const hostName='127.0.0.1'
const port=3000
const server=http.createServer(function(req,res){
    let content=fs.readFileSync('index.html')
    res.writeHead(200,{
        'content-type':'text/html;charset="utf-8"'
    })
    res.write(content)
    res.end()
})
server.listen(port,hostName,function(){
    console.log('Server is running here: http://${hostName}:${port}')
})

node app.js //node + filename

when console show Server is runing here:http://127.0.0.1:3000"

Vue模拟实现

index.html

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<div id="app">
    <ul>
    	<li><router-link to="/">Home</router-link></li>
        <li><router-link to="/about">About</router-link></li>
	</ul>
	<router-view></router-view>
</div>
<script type="text/javascript">
    let Home={
        template:'<h1>This is Hime!</h1>'
    }
	let About={
        template:'<h1>This is About!</h1>'
    }
    let routes=[
        {
        path:'/',
        component:Home
    },
        {
            path:'/about',
            component:About
        }]
    let RouterLink={
        props:['to'],
        template:'<a :href="to"><slot name="default"></slot></a>'
    }
    let RouterView={
        data(){
            return {
                url:window.location.pathname//浏览器地址
            }
        },
        computed:{
            ViewComponent(){
                return routes.find(route=>route.path===this.url).component
            }
        },
        render(h){
            return h(this.ViewComponent)
        }
    }
    /*eslint-disable*/
    let vm=new Vue({
      el:'#app',
      components:{RouterLink,RouterView}
    })
    </script>

JS实现前端路由的代码

<div>
<ul>
<li><a href="#/">Home</a></li>
<li><a href="#/about">About</a></li>
</ul>
<!-- 动态视图被挂载的元素 -->
<div id="view"></div>
</div>
<script type="text/javascript">
let Home = '<h1>This is Home!</h1>' // 视图模板Home
let About = '<h1>This is About!</h1>' // 视图模板About
let Router = function (el) { // 定义路由类
let view = document.getElementById(el)
let routes = [] // 路由规则列表
let load = function (route) { // 加载视图
route && (view.innerHTML = route.template)
}
let redirect = function () { // 分发视图
let url = window.location.hash.slice(1) || '/'
for (let route of routes) {
url === route.url && load(route)
}
}
this.push = function (route) { // 添加路由规则
routes.push(route)
}
window.addEventListener('load', redirect, false) //
页面加载时
window.addEventListener('hashchange', redirect, false)
// URL变化时
}
let router = new Router('view') // 实例化路由
router.push({ // 添加路由规则
url: '/',
template: Home
})
router.push({
url: '/about',
template: About
})
</script>

a标签的href中写入"#"符号,可以阻止页面刷新,(实现了单页面应用),单也会在URL中加入该符号。

在redirect函数中并没有直接取window.location.hash的值,而是先用slice(1)将"#"去掉

Vue中的前端路由

Vue Router是Vue.js官方提供的路由管理器,它与Vue.js的核心深度集成

1、基本路由

RouterLink和RouterView是Vue Router提供的两个内置组件。

RouterLink默认会被渲染成一个标签,它的to属性用于指定跳转链接;

RouterView将负责挂载路由匹配到的视图组件。

2、动态路由

路径参数应用英文冒号“:”标记,但是在使用时应注意设计的规则是否合理

routes:[
    {path:'/:any',component:Home}//可以匹配路径为/about的路由,“about”将作为any的值
]

当动态路径被匹配时,我们可以在组件中使用this.$route.params来获取参数的值

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vuerouter.
js"></script>
<div id="app">
<ul>
<li><router-link to="/">Home</router-link></li>
<li @click="add">
<!-- 2. 参数num由实例传入路由 -->
<router-link :to="'/about/' + num">About</routerlink>
</li>
</ul>
<router-view></router-view>
</div>
<script type="text/javascript">
let Home = { template: '<h1>This is Home!</h1>' } //
Home组件
let About = { // About组件
template: '<div>' +
'<h1>This is About!</h1>' +
'<p>num: {{ $route.params.num }}</p>' + // 3. 在组件中
显示参数 num
'</div>'
}
let routes = [ // 定义路由规则,每一个路由规则应该映射一个视图
组件
{ path: '/', component: Home },
{ path: '/about/:num', component: About } // 1. 定义了
参数 num, 格式如:
/:num
]
let router = new VueRouter({ // 创建Vue Router实例,并传入
routes配置
routes
})
let app = new Vue({
data () {
return { num: 0 }
},
methods: { // 当点击About时,num值自增1
add () { this.num++ }
},
router
}).$mount('#app')
</script>
  • 首先在html部分使用标签并设定to属性(路由规则)
  • 定义组件
  • 设定路由规则,格式 {path:'/xxx',component:Home}
  • 创建Vue Router实例,并传入routes配置 new VueRouter({ routes})

3、嵌套路由

  • 嵌套路由可以实现在动态视图中嵌套动态视图
  • 多层的动态视图可以使用Vue的内置组件component来实现
    • 使用component切换的视图会在页面刷新后回到初始状态,而使用路由分发的视图会在页面刷新后保持当前路径对应的视图,并在浏览器的history中留下记录
let routes = [ // 定义路由规则,每一个路由规则应该映射一个视图
组件
{ path: '/', component: Home },
{
path: '/about',
component: About,
children: [ // 2. 嵌套子路由
{ path: 'author', component: Author },
{ path: 'email', component: Email }
]
}
]

4、编程式路由

  • 可以不使用RouterLink组件,而是在JS中使用router.push方法跳转视图
    • @click=“redirectByPath(‘/xxxx’)”
  • 通过路由的path跳转视图,还可以赋予路由name属性,然后通过name跳转视图
  • 动态参数应该放在params中,当使用path时,param参数不生效,此时应将参数值直接写进path中
<div id="app">
<ul>
<!-- 默认字符串为路径参数 -->
<li @click="redirectByPath('/')">Home</li>
<li>
<!-- 指定参数为路径 -->
<div @click="redirectByPath('/about')">About</div>
    <ul>
    <!-- 嵌套路由-->
    <li @click="redirectByPath('/about/author')">About - Author</li>
    <!-- 嵌套路由,动态路由,当使用path时,params参数不生效
    -->
    <li @click="redirectByPath('/about/email', {email: lonelydawn@sina.com' })">About - Email</li>
    <!-- 嵌套路由,动态路由,可以直接将参数写入path -->
    <li @click="redirectByPath('/about/email/lonelydawn@sina.com')">About - </li>
    <!-- 嵌套路由,动态路由,使用命名路由跳转视图 -->
    <li @click="redirectByName('Email', { email:'singledawn@sina.com' })">About - Email</li>
    </ul>
</li>
</ul>
<router-view></router-view>
</div>

5、使用Vue CLI快速构建的router/index.js

  • 使用Vue.use安装Vue Router插件
  • 使用export返回路由规则。默认只有当路径为“/”时。渲染HelloWorld组件
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
    routes: [
        {
            path: '/',
            name: 'HelloWorld',
            component: HelloWorld
        }
    ]
})

状态管理

小型应用来说,完全没有必要引入状态管理,这会带来更多的开发成本。然而当应用的复杂度逐渐提高,状态管理也越发重要起来

对于组件化开发来说,大型应用的状态往往跨越多个组件。

多层嵌套的父子组件之间传递状态十分复杂,而Vue没有为兄弟组件提供直接共享数据的方法。

基于这个问题,许多框架提供了解决方案——使用全局的状态管理器,将所有分散的共享数据交由状态管理器保存

Vue官网提供的状态管理器名为Vuex

对象引用

js中,对象的赋值,是某一时刻对对象的引用

核心是地址传递

状态管理器Vuex

管理分散在Vue各个组件中的数据

每一个Vuex应用的核心都是一个store(仓库)

store–非凡的全局变量

基于Vue数据与视图绑定的特点,当store中的状态发生变化时,与之绑定的视图也会被重新渲染

单向的过程,store中的状态不允许被直接修改。

唯一途径是 显示地提交(commit)mutation,这可以让我们方便地追踪每一个状态的变化

5个重要的概念

  • State
  • Getter
  • Mutation
  • Action
  • Module

State

用于维护所有应用层的状态,并确保应用只有唯一的数据源

(SSOT,Single Source of Truth)

new Vuex.Store({
	state:{
	count:1
	}
})

​ 组件中,我们可以直接使用$store.state.count

也可以先用mapState辅助函数将其映射下来

import {mapState} from 'vuex'
export default{
	computed:{
		mapState(['count'])
	}
}

Getter

维护由State派生的一些状态,这些状态随着State状态的变化而变化。

与计算属性一样,Getter中的派生状态在被计算之后会被缓存起来,当重复调用时,如果被依赖的状态没有变化,那么Vuex不会重新计算派生状态的值,而是直接采用缓存值

new Vuex.Store({
	state:{
		count:1
	},
	getters:{
		tenTimesCount(state){
			return state.count*10
		}
	}
})

组件中可以直接使用$store.getters.tenTimesCount

mapGetters辅助函数将其映射

import {mapGetters} from 'vuex'
export default{
	computed:{
		mapGetters(['tenTimesCount'])
	}
}

Mutation

提供修改State状态的方法

new Vuex.Store({ // 创建仓库
state: {
count: 0
},
mutations: {
addCount (state, num) {
state.count += num || 1
}
}
})

组件中,可以直接使用store.commit来提交mutation

methods: {
addCount () {
this.$store.commit('addCount') // store被注入到Vue实例中后可使用this.$store
}
}

也可以先用mapMutation辅助函数将其映射下来,代码如下:

import { mapState, mapMutations } from 'vuex'
export default {
computed: {
...mapState(['count']) // ...是ES 6中的对象展开运算符
},
methods: {
...mapMutations(['addCount']),
...mapMutations({ // 为mutation赋别名,注意冲突,此方法不常用
increaseCount: 'addCount'
})
}
}

Action

类似Mutation,不同在于

  • Action不能直接修改状态,只能通过提交mutation来修改
  • Action可以包含异步操作

Module

由于使用单一状态树,当项目的状态非常多时,store对象就会变得十分臃肿

因此,Vuex允许我们将store分割成模块(Module),每个模块拥有独立的State、Getter、Mutation和Action,模块之中还可以嵌套模块,每一级都有着相同的结构

在项目中使用Vuex

打开项目地址cmd

cnpm install vuex --save-dev

安装插件

在src 目录下创建store 、store/index.js 、store/modules、store/modules/counter.js


// …是ES 6中的对象展开运算符
},
methods: {
…mapMutations([‘addCount’]),
…mapMutations({ // 为mutation赋别名,注意冲突,此方法不常用
increaseCount: ‘addCount’
})
}
}


### Action

类似Mutation,不同在于

- Action不能直接修改状态,只能通过提交mutation来修改
- Action可以包含异步操作

### Module

由于使用单一状态树,当项目的状态非常多时,store对象就会变得十分臃肿

因此,Vuex允许我们将store分割成模块(Module),每个模块拥有独立的State、Getter、Mutation和Action,模块之中还可以嵌套模块,每一级都有着相同的结构

## 在项目中使用Vuex

打开项目地址cmd

cnpm install vuex --save-dev

安装插件

在src 目录下创建store 、store/index.js 、store/modules、store/modules/counter.js

​	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Toreme

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值