webpack4 + vue + vue-router + vuex
ps:
- 所有案例使用的 node 及 npm 版本如下
- node版本: v8.4.0
- npm: 5.3.0
- 下一个案例默认是接着上一个继续写的
- 建议先熟悉以下文档
- 建议使用 cnpm 替代 npm
- 案例源码戳这里
一、webpack4 + vue 搭建项目
先搭建一个简单的项目,能够运行起来
新建项目目录如下
[demo]
|-- common
|-- reset.less
|-- src
|-- index.js
|-- index.html
|-- package.json
|-- webpack.config.js
运行 $ npm init 全部回车后结果如下
demo/package.json
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
reset css 的代码大家可以找别的,这里贴的代码也是从网上copy过来的
demo/common/reset.less
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
写一个简单的 html 和 js,如下
demo/src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>demo</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
demo/src/index.js
import './common/reset.less';
console.log(111111)
下面安装依赖
- js相关
$ npm i babel-core babel-loader babel-preset-es2015 babel-preset-stage-0 -D - 样式相关
$ npm i css-loader less less-loader autoprefixer-loader mini-css-extract-plugin -D - html 相关
$ npm i html-webpack-plugin -D - 图片和图标相关
$ npm i file-loader url-loader -D - webpack相关
$ npm i webpack webpack-cli webpack-dev-server -D
然后在 package.json 里的 scripts 字段里增加启动服务(webpack-dev-server)和构建(webpack -p)的命令,如下
demo/package.json
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"dev": "webpack-dev-server",
"build": "webpack -p"
},
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer-loader": "^3.2.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"css-loader": "^1.0.1",
"file-loader": "^2.0.0",
"html-webpack-plugin": "^3.2.0",
"less": "^3.8.1",
"less-loader": "^4.1.0",
"mini-css-extract-plugin": "^0.4.4",
"url-loader": "^1.1.2",
"webpack": "^4.26.0",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.10"
}
}
注意这里 babel-loader 的版本号是 "^7.1.5",否则会有如下报错:
Error: Cannot find module '@babel/core'
babel-loader@8 requires Babel 7.x (the package '@babel/core').If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7'.
下面写 webpack.config.js 先贴下完整的代码
demo/webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'production',
entry: {
index: './src/index.js',
},
output: {
path: __dirname + "/build",
filename: '[name].[hash].js'
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
options: {
presets: ['es2015', 'stage-0'],
}
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
],
},
{
test: /\.(png|jpg|gif|ttf)$/,
loader: 'url-loader',
options: {
name: 'img/[name].[ext]?[hash:7]'
}
},
]
},
devServer: {
contentBase: './build',
inline: true,
hot: true,
port: 7777,
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
chunks: ['index']
}),
new MiniCssExtractPlugin({
filename: '[name].css'
}),
]
}
mode
告知 webpack 使用相应模式的内置优化,值为 production、developmententry
入口文件,值可以是 string、array、object。这里的入口文件就是demo/src/index.js
output
输出,值是 object。- filename:用于输出文件的文件名。
- path:目标输出目录 path 的绝对路径。
module.rules
创建模块时,匹配请求的规则数组。这些规则能够修改模块的创建方式。这些规则能够对模块(module)应用 loader,或者修改解析器(parser)。
上面的数组中依次是对:".js 结尾的文件"、".less 结尾的文件"、"图片和图标" 的处理plugins
插件new webpack.HotModuleReplacementPlugin()
模块热替换插件new HtmlWebpackPlugin()
自动生成html的插件new MiniCssExtractPlugin()
css压缩并单独打包插件
运行 $ npm run dev , 并打开 http://localhost:7777 , 结果如下所示
案例1
新增文件如下
[demo]
|-- src
|-- components
|-- app.vue
先安装 vue 相关的依赖
- $ npm i vue --save
- $ npm i vue-loader vue-hot-reload-api vue-template-compiler --save-dev
安装以后,package.json 里就会多出来以下部分
demo/package.json
{
...
"devDependencies": {
...
"vue-hot-reload-api": "^2.3.1",
"vue-loader": "^15.4.2",
"vue-template-compiler": "^2.5.17"
},
"dependencies": {
"vue": "^2.5.17"
}
}
webpack.config.js 里增加关于 vue 的配置
demo/webpack.config.js
...
var VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
...,
module: {
// 规则
rules: [
...,
// 加载 .vue 结尾的文件
{
test: /\.vue$/,
loader: 'vue-loader',
},
]
},
...
plugins: [
...,
new VueLoaderPlugin(),
]
}
注意这里一定要加上new VueLoaderPlugin()
,否则会报错
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
下面写一个简单的 vue 案例
demo/src/components/app.vue
<template>
<h2>{{msg}}</h2>
</template>
<script>
export default {
name: "app",
data() {
return {
msg: "Welcome to Your Vue.js App"
};
},
};
</script>
demo/src/index.js
import Vue from 'vue';
import App from './components/app.vue';
import './common/reset.less';
Vue.config.debug = true;//开启错误提示
new Vue({
el: '#root',
render: h => h(App)
});
运行 $ npm run dev , 并打开 http://localhost:7777 , 结果如下所示
二、接入 vue-router
案例2
安装依赖 $ npm i vue-router --save
demo/package.json
{
"dependencies": {
"vue": "^2.5.17",
"vue-router": "^3.0.1"
}
}
配置 webpack.config.js 提取公用文件
demo/webpack.config.js
...
module.exports = {
mode: 'production',
entry: { // 入口
index: './src/index.js',
vendors: ['vue', 'vue-router']
},
output: { // 输出
path: __dirname + "/build",
filename: '[name].[hash].js'
},
...,
optimization: {
// 提取入口文件里面的公共模块
splitChunks: {
cacheGroups: {
vendors: {
name: 'vendors',
chunks: "all",
minSize: 1,
priority: 10
},
}
}
},
plugins: [
// 自动生成 html 插件
new HtmlWebpackPlugin({
template: './src/index.html',
chunks: ['vendors', 'index']
}),
...,
]
}
入口文件里,分离了程序(index)和第三方库(vendors: vue、vue-router)
webpack4 废除了 CommonsChunkPlugin ,新增了 optimization.splitChunks
我们将需要在 optimization.splitChunks.cacheGroups 中设置我们需要提取的公用文件
splitChunksPlugin 的配置项说明:
- chunks: 表示显示块的范围,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为all
- minSize:最小尺寸,默认为0;
- misChunks:表示被引用次数,默认为1
- maxAsyncRequests:最大的按需(异步)加载次数,默认为1;
- maxInitialRequests: 最大的初始化加载次数,默认为1;
- name:拆分出来的 chunks 的名字
- automaticNameDelimiter: 如果不指定name,自动生成name的分隔符(‘runtime~[name]’)
- filename: ''
- cacheGroups: 缓存组,主要配置在这里
- priority 表示缓存的优先级,默认是负数,数字越大优先级越高,优先级高的不会被打包进优先级低的里面
- test: 缓存组的规则,表示符合条件的的放入当前缓存组,值可以是function、boolean、string、RegExp,默认为空
- reuseExistingChunk: 表示可以使用已经存在的块,即如果满足条件的块已经存在就使用已有的,不再创建一个新的块
new HtmlWebpackPlugin()
里新增了一个 chunks
,这里是指自动生成的 html 里需要加入的 js 是哪些,这里加入了 vendors.js 和 index.js
新增文件如下
[demo]
|-- src
|-- components
|-- chat.vue
|-- home.vue
|-- routes.js
写一个简单的 home 和 chat 模块
demo/src/components/chat.vue
<template>
<div>Welcome to chat page</div>
</template>
demo/src/components/home.vue
<template>
<div>Welcome to home page</div>
</template>
app.vue 相当于是项目入口文件
demo/src/components/app.vue
<template>
<div>
<header>{{msg}}</header>
<div>
<router-link to="/">home</router-link>
<router-link to="/chat">chat</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: "app",
data() {
return {
msg: "vue demo"
};
},
};
</script>
使用 <router-link>
来导航,通过传入 to
属性指定链接,最终在页面上<router-link>
会被渲染成 <a>
标签,
<router-view>
是路由出口,路由匹配到的组件将渲染在这里
demo/src/routes.js
import Vue from 'vue';
import Router from 'vue-router';
import homePage from './components/home.vue';
import chatPage from './components/chat.vue';
Vue.use(Router);
const routes = [
{
path: '/',
component: homePage
},
{
path: '/chat',
component: chatPage
}
]
export default new Router({
routes,
})
路由组件(homePage、chatPage)是通过 import 进来的
通过 routes 这个数组来定义每个路由映射的组件
通过 new Router()
来创建 router 实例,然后传 routes
配置
demo/src/index.js
import Vue from 'vue';
import App from './components/app.vue';
import router from './routes.js'
import './common/reset.less';
new Vue({
router,
el: '#root',
render: h => h(App)
});
new Vue({ router })
创建和挂载根实例,记得要通过 router 配置参数注入路由,从而让整个应用都有路由功能
运行 $ npm run dev , 并打开 http://localhost:7777 , 结果如下所示
三、接入 vuex
案例3:store
安装依赖 $ npm install vuex --save
demo/package.json
{
...,
"dependencies": {
"vue": "^2.5.17",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"
}
}
将 vuex 加入到 entry.vendors 中去
demo/webpack.config.js
...
module.exports = {
entry: { // 入口
index: './src/index.js',
vendors: ['vue', 'vue-router', 'vuex']
},
...,
}
新建文件如下
[demo]
|-- src
|-- store
|-- index.js
|-- components
|-- showHide.vue
demo/src/store/index.js
import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex);
const defaultState = {
show: true
}
export default new vuex.Store({
state: defaultState
})
确保开头要调用 Vue.use(Vuex)
通过 new vuex.Store()
来创建一个 store
defaultState 是默认的状态
demo/src/index.js
...
import store from './store';
new Vue({
router,
store,
el: '#root',
render: h => h(App)
});
通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到
demo/src/components/showHide.vue
<template>
<div>
<button @click="$store.state.show = false">按钮</button>
结果:{{ $store.state.show ? 'show' : 'hide' }}
</div>
</template>
根据 $store.state.show
返回来判断 res 的值为 show 或者 hide . 默认是 false ,当点击时将 show 的值设置为 false
下面在 home 里引入 showHide
demo/src/components/home.vue
<template>
<div>
Welcome to home page
<show-hide></show-hide>
</div>
</template>
<script>
import ShowHide from './showHide.vue';
export default {
name: "home",
components: {
ShowHide
}
}
</script>
运行 $ npm run dev , 并打开 http://localhost:7777 , 结果如下所示
案例4:mutation
案例3 中,当状态切换到 hide 后,不可以再切换成 show 了。下面我们来改造成可以在 hide 和 show 之间来回切换的,这里就要用到 mutation。
mutation 是用来更改状态的
demo/src/store/index.js
...
// 更新状态
const mutations = {
switchShowHide(state) {
state.show = state.show ? false : true;
}
}
export default new vuex.Store({
state: defaultState,
mutations,
})
每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
这里判断了 state.show 的值,并且设置为相反的值,这样就能实现每次来回切换
demo/src/components/showHide.vue
<template>
<div>
<button @click="$store.commit('switchShowHide')">按钮</button>
结果:{{ $store.state.show ? 'show' : 'hide' }}
</div>
</template>
要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法
使用 $store.commit('switchShowHide') 来触发 mutations 中的 switchShowHide 方法
也可以传入额外的参数,如下所示
store.commit('fn', params)
mutations: {
fn (state, params) {
console.log(state, params)
...
}
}
还可以是对象的方式,如下所示
store.commit({
type: 'fn',
params: 'aaa'
});
mutations: {
increment (state, payload) {
const { params } = payload;
console.log(state, payload)
...
}
}
mutation 必须是同步函数
运行 $ npm run dev , 并打开 http://localhost:7777 , 结果如下所示
案例5:actions
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
demo/src/store/index.js
...
const mutations = {
switchShowHide(state) {
state.show = state.show ? false : true;
}
}
const actions = {
switchShowHide(context){
context.commit('switchShowHide');
},
}
export default new vuex.Store({
state: defaultState,
mutations,
actions,
})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
actions 注册事件处理函数,当这个函数被触发时,可以调用 context.commit,将状态提交到 mutaions中处理
还可以通过 context.state 来获取 state
demo/src/components/showHide.vue
<template>
<div>
<button @click="$store.dispatch('switchShowHide')">按钮</button>
结果:{{ $store.state.show ? 'show' : 'hide' }}
</div>
</template>
Action 通过 store.dispatch 方法触发。这里通过 $store.dispatch('switchShowHide')"
来触发 action 中的 switchShowHide 方法
效果和 案例4 一样
Actions 同样也可以传入额外参数 或者 传入对象,如下所示
store.dispatch('fn', {
params: '123'
})
store.dispatch({
type: 'fn',
params: '123'
})
案例6:Module
当应用变得复杂时,需要将 store 分割成不同的 module。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
这里我们将拆分成 home 和 chat 两个部分
新建文件如下
[demo]
|-- src
|-- store
|-- modules
|-- home.js
这里我们可以先迁移 state 部分,如下将 home 部分的先单独写在一个文件里
demo/src/store/modules/home.js
export default {
state: {
show: true
}
}
然后在 index 里引入下 home 的部分
demo/src/store/index.js
import Vue from 'vue';
import vuex from 'vuex';
import homeStore from './modules/home';
Vue.use(vuex);
const mutations = {
switchShowHide(state) {
state.homeStore.show = state.homeStore.show ? false : true;
}
}
const actions = {
switchShowHide(context){
context.commit('switchShowHide');
},
}
export default new vuex.Store({
modules: {
homeStore,
},
mutations,
actions,
})
这样修改以后,需要将之前的 state.show 修改为 state.homeStore.show
demo/src/components/showHide.vue
<template>
<div>
<button @click="$store.dispatch('switchShowHide')">按钮</button>
结果:{{ $store.state.homeStore.show ? 'show' : 'hide' }}
</div>
</template>
效果和 案例4 一样
案例7:Getter
getters 和 vue 中的 computed 类似 , 都是用来计算 state 然后生成新的数据 ( 状态 ) 的。
demo/src/store/index.js
...
const getters = {
opposite(state) {
return !state.homeStore.show
}
}
export default new vuex.Store({
modules: {
homeStore,
},
mutations,
actions,
getters,
})
getters 的第一个参数是 store,第二个参数是其他的 getters
下面我们在组件里使用它
demo/src/components/showHide.vue
<template>
<div>
<button @click="$store.dispatch('switchShowHide')">按钮</button>
结果:{{ $store.state.homeStore.show ? 'show' : 'hide' }}
<br>
相反:{{ doneOpposite }}
</div>
</template>
<script>
export default {
computed: {
doneOpposite() {
return this.$store.getters.opposite
}
}
}
</script>
Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值
效果如下
案例8:mapState、mapGetters、mapActions
- mapState 替代 $store.state.homeStore.show 的写法
demo/src/components/showHide.vue
<template>
<div>
<button @click="$store.dispatch('switchShowHide')">按钮</button>
结果:{{ show? 'show' : 'hide' }}
<br>
相反:{{ doneOpposite }}
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
computed: mapState({
show(state) {
return state.homeStore.show
},
doneOpposite() {
return this.$store.getters.opposite
}
})
}
</script>
mapGetters、mapActions 和 mapState 类似 , mapGetters 一般也写在 computed 中 , mapActions 一般写在 methods 中。
在上面的例子里,能看到 mapState 里还包含了 this.$store.getters.opposite
, 这时候可以运用对象扩展运算符对其进行改造
demo/src/components/showHide.vue
...
<script>
import { mapState } from "vuex";
export default {
computed: {
doneOpposite() {
return this.$store.getters.opposite;
},
...mapState({
show(state) {
return state.homeStore.show;
}
})
}
};
</script>
- mapGetters 替代 this.$store.getters.opposite 的写法
demo/src/components/showHide.vue
...
<script>
import { mapState, mapGetters } from "vuex";
export default {
computed: mapGetters({
doneOpposite: 'opposite',
...mapState({
show(state) {
return state.homeStore.show;
}
})
})
};
</script>
用对象扩展运算符对其进行改造
demo/src/components/showHide.vue
<template>
<div>
<button @click="$store.dispatch('switchShowHide')">按钮</button>
结果:{{ show? 'show' : 'hide' }}
<br>
相反:{{ opposite }}
</div>
</template>
<script>
import { mapState, mapGetters } from "vuex";
export default {
computed: {
...mapGetters([
'opposite',
]),
...mapState({
show(state) {
return state.homeStore.show;
}
})
}
};
</script>
注意:要给 getter 属性另取一个名字,必须是对象的方式,数组不行。下面的是另取名的写法
computed: {
...mapGetters({
doneOpposite: "opposite"
}),
}
- mapActions 替换 this.$store.dispatch('switchShowHide') 的写法
demo/src/components/showHide.vue
<template>
<div>
<button @click="switchShowHide">按钮</button>
结果:{{ show? 'show' : 'hide' }}
<br>
相反:{{ opposite }}
</div>
</template>
<script>
import { mapState, mapGetters, mapActions } from "vuex";
export default {
methods: {
...mapActions([
'switchShowHide'
])
},
computed: {
...mapGetters([
'opposite',
]),
...mapState({
show(state) {
return state.homeStore.show;
}
})
}
};
</script>
和 getter 也一样,action 也可以另外命名,如果要另外命名必须是对象
methods: {
...mapActions({
xxx:'switchShowHide'
})
}
webpack4 + vue + vue-router + vuex的更多相关文章
- Vue3: 如何以 Vite 创建,以 Vue Router, Vuex, Ant Design 开始应用
本文代码: https://github.com/ikuokuo/start-vue3 在线演示: https://ikuokuo.github.io/start-vue3/ Vite 创建 Vue ...
- webpack4+koa2+vue 实现服务器端渲染(详解)
_ 阅读目录 一:什么是服务器端渲染?什么是客户端渲染?他们的优缺点? 二:了解 vue-server-renderer 的作用及基本语法. 三:与服务器集成 四:服务器渲染搭建 4.1 为每个请求创 ...
- 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十三║Vue实战:Vuex 其实很简单
前言 哈喽大家周五好,马上又是一个周末了,下周就是中秋了,下下周就是国庆啦,这里先祝福大家一个比一个假日嗨皮啦~~转眼我们的专题已经写了第 23 篇了,好几次都坚持不下去想要中断,不过每当看到群里的交 ...
- python 全栈开发,Day93(vue内容补充,VueX)
昨日内容回顾 1. 页面的布局 Vue中使用Bootstrap搭页面 1. 安装 1. npm install bootstrap@3.3.7 -S 2. 使用 1. import 'bootstra ...
- 【实战】Vue全家桶(vue + axios + vue-router + vuex)搭建移动端H5项目
使用Vue全家桶开发移动端页面. 本博文默认已安装node.js. github链接 一.准备工作 安装vue npm install vue 安装脚手架vue-cli npm install -g ...
- webpack4搭建vue多页面环境
总结一下webpack4配置vue开发环境,本文不具体介绍webpack的基本概念和用途,如有不了解的请参见https://www.webpackjs.com/concepts/官网 一.webpac ...
- 简单vue项目脚手架(vue+webpack2.0+vuex+vue-router)
github地址 使用技术栈 webpack(^2.6.1) webpack-dev-server(^2.4.5) vue(^2.3.3) vuex(^2.3.1) vue-router(^2.5.3 ...
- Vue状态管理vuex
前面的话 由于多个状态分散的跨越在许多组件和交互间各个角落,大型应用复杂度也经常逐渐增长.为了解决这个问题,Vue提供了vuex.本文将详细介绍Vue状态管理vuex 引入 当访问数据对象时,一个 V ...
- 三、vue之router
三.vue之router 此时vue的脚手架.创建项目已经完成. ... vue的运行流程 index.html-->main.js-->App.vue-->router/index ...
- Vue 入门之 Vuex 实战
Vue 入门之 Vuex 实战 引言 Vue 组件化做的确实非常彻底,它独有的 vue 单文件组件也是做的非常有特色.组件化的同时带来的是:组件之间的数据共享和通信的难题. 尤其 Vue 组件设计的就 ...
随机推荐
- 28 Data Race Detector 数据种类探测器:数据种类探测器手册
Data Race Detector 数据种类探测器:数据种类探测器手册 Introduction Usage Report Format Options Excluding Tests How To ...
- P1986 元旦晚会
一道可以用各种各样的办法做的(水)题 在这里就介绍两种做法 题意: 自己看看吧,很明显的意思,就是求前i个人最少有多少个话筒. 解法1:差分约束 设\(dis[i]\)表示前\(i\)个人最少有多少个 ...
- (一)问候 Log4j 你好
第一节: Log4j 简介 Log4j -------- log for java(java的日志) 是java主流的日志框架,提供各种类型,各种存储,各种格式,多样化的日志服务: 在爬虫领域,主要用 ...
- MySQL学习笔记:coalesce
函数:coalesce 作用:返回传入的参数中第一个非NULL的值 ); # ); # 如果传入的参数所有都是NULL,则返回NULL,比如: SELECT COALESCE(NULL, NULL, ...
- 我常用的 Python 调试工具 - 博客 - 伯乐在线
.ckrating_highly_rated {background-color:#FFFFCC !important;} .ckrating_poorly_rated {opacity:0.6;fi ...
- java算法小例子
作为一个程序员,有时候我觉得自己都不适合,因为自己数学不好,算法不好,脑子不够灵活.而对于算法,感觉就像是数学题,总觉得很难.以前上学,在班里总有几个什么都不好,但唯独数学很厉害,真气人!面对难题时, ...
- 使用apt install和使用apt-get install的区别是什么
apt-get是老版的命令,apt是新版的命令,apt还包含了apt-get cache等等,用起来更方便.因为apt刚刚出来,所以允许有apt-get和apt共存,以后apt-get就要淘汰了.
- centos安装lspci工具
https://blog.csdn.net/wudiyi815/article/details/38325199
- Django实战(14):让页面联动起来
上一节我们实现了一个”能看不能用“的购物车,现在我们来使用这个购物车. 首先是产品目录界面中的”加入购物车“链接,我们希望点击这个按钮后,在购物车中添加该产品(添加的规则是如果购物车中已经有该产品就增 ...
- 006 ajax验证用户名
1.大纲 2.index.jsp <%@ page language="java" contentType="text/html; charset=UTF-8&qu ...