<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>09_form</title>
</head>
<body>
<div id="example"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
/*
需求: 自定义包含表单的组件
1. 界面如下所示
2. 输入用户名密码后, 点击登陆提示输入信息
3. 不提交表单
*/
class FormComp extends React.Component {
constructor (props) {
super(props)
// 初始化状态
this.state = {
username: 'abc',
pwd: '123'
}
}
handleNameChange = (event) => {
const username = event.target.value
// 更新状态(username)
this.setState({
username
})
}
handlePwdChange = (event) => {
const pwd = event.target.value
// 更新状态(pwd)
this.setState({
pwd
})
}
login = (event) => {
// 阻止默认行为
event.preventDefault()
const {username, pwd} = this.state
alert(`发送登陆请求 ${username}--${pwd}`)
// return false
}
render () {
const {username, pwd} = this.state
return (
<form action="/test" onSubmit={this.login}>
用户名: <input type="text" onChange={this.handleNameChange} value={username}/>
密码: <input type="password" onChange={this.handlePwdChange} value={pwd}/> /*事件在输入过程中不断触发*/
<input type="submit" value="登陆"/>
</form>
)
}
}
ReactDOM.render(<FormComp/>,document.getElementById('example'))
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>09_form</title>
</head>
<body>
<div id="example"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
/*
需求: 自定义包含表单的组件
1. 界面如下所示
2. 输入用户名密码后, 点击登陆提示输入信息
3. 不提交表单
*/
class FormComp extends React.Component {
login = (event) => {
// 阻止默认行为
event.preventDefault()
const username = this.refs.username.value
const pwd = this.refs.pwd.value
alert(`发送登陆请求 ${username}--${pwd}`)
// return false
}
render () {
return (
<form action="/test" onSubmit={this.login}>
用户名: <input type="text" ref="username"/>
密码: <input type="password" ref="pwd"/>
<input type="submit" value="登陆"/>
</form>
)
}
}
ReactDOM.render(<FormComp/>,document.getElementById('example'))
</script>
</body>
</html>
// 数字转换位千分位 千分位转换位数字
function commafy(num) {
//1.先去除空格,判断是否空值和非数
num = num + "";
num = num.replace(/[ ]/g, ""); //去除空格
if (num == "") {
return;
}
if (isNaN(num)) {
return num;
}
//2.针对是否有小数点,分情况处理
var index = num.indexOf(".");
if (index == -1) {//无小数点
var reg = /(-?\d+)(\d{3})/;
while (reg.test(num)) {
num = num.replace(reg, "$1,$2");
}
num += ".00";//强制转为含角分 pcj
} else {
var intPart = num.substring(0, index);
var pointPart = num.substring(index + 1, num.length);
//如果输入小数位为1位,追加0
if (pointPart.length == 1) {
pointPart += "0";
}
var reg = /(-?\d+)(\d{3})/;
while (reg.test(intPart)) {
intPart = intPart.replace(reg, "$1,$2");
}
num = intPart + "." + pointPart;
}
return num;
}
console.log(commafy(123456))//123,456.00
console.log(commafy(1233254235456))
/**
* 去除千分位
*@param{Object}num
*/
function delcommafy(num) {
num = num.toString();
num = num.replace(/[ ]/g, "");//去除空格
num = num.replace(/,/gi, '');
return Number(num);
}
console.log(delcommafy(commafy(123456)));
console.log(delcommafy(commafy(1233254235456)));
```js
import Vue from 'vue' Vue.filter('NumFormat', function (value) {
if (!value) return '0.00'
if (value === '0') return '0.00'
// 获取整数部分
// let intPart = Number(value).toString.split('.')
let temp = String(value).split('.')
// let dot = intPart.indexOf('.')
// console.log('测试', intPart)
// console.log('测试', dot)
let intPart = temp[0]
// var intPart = Number(value).toFixed(0)
// 将整数部分逢三一断
var intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
// 预定义小数部分
var floatPart = '.00'
var value2Array = value.split('.')
// =2表示数据有小数位
if (value2Array.length === 2) {
// 拿到小数部分
floatPart = value2Array[1].toString()
// 补0,实际上用不着
if (floatPart.length === 1) {
return intPartFormat + '.' + floatPart
} else {
return intPartFormat + '.' + floatPart
}
} else {
return intPartFormat
} })
```
```js
———— export const status = (state) => {
switch (state) {
case '0':
return '未上传'
case '1':
return '未预估'
case '2':
return '正常'
} }
export const send = (state) => { switch (state) { case ‘10A’: return ‘已下载’ case ‘10B’: return ‘未下载’ } }
export const gradeStatus = (state) => { switch (state) { case ‘10B’: return ‘未处理’ case ‘10A’: return ‘已处理’ } } ———— 1.引入import { status } from ‘../../filter/runGradeState’ 2.使用过滤 filters: { status } 3.写入表达式 ```
import Axios from 'axios'
import router from '../router'
import { Toast } from 'vant'
import store from '../store'
import getuuid from './getUUID'
import { LGet } from './storage'
import { format } from '../filter/date'
import judge from './device'
var logData = ''
var httpUuid = ''
var user = LGet('user') || ''
// 建立请求对象
const service = Axios
/* const service = Axios.create({
// baseURL: process.env.API_HOST, // api的base_url
timeout: 1000 // request timeout
}) */
// 请求拦截器
service.interceptors.request.use(
config => {
httpUuid = getuuid(16, 16) // 生成请求uuid
let account = ''
let userPhone = ''
if (config.url.indexOf('user/userLogin') !== -1) { // 如果为登录接口
account = config.params.account
userPhone = config.params.account
} else {
account = user.userName
userPhone = user.phone
}
logData = {
serverType: 'vue',
logUuid: httpUuid,
userId: user.id,
userName: account,
realIp: '',
reqUrl: config.url,
reqParam: config.params ? JSON.stringify(config.params) : '',
repUrl: '',
repParam: '',
repData: '',
logType: '1', // 1请求,2系统
logLevel: '',
resultCode: '',
resultMsg: '',
logErrInfo: '',
logCreateTime: format(new Date(), 'YYYY-MM-DD HH:mm:ss'),
logUploadTime: '',
mobile: userPhone,
netWork: '',
appUuid: '',
appType: '',
appVersion: '',
phoneType: '',
phoneVersion: '',
phoneWebView: '',
httpStartTime: new Date().getTime(),
httpEndTime: '',
httpDuration: '',
httpServer: 'app-backend'
}
if (config.url.indexOf('upload/json/fileUpload') !== -1) { // 如果为文件上传服务
logData.httpServer = 'lf-files'
}
// const url = config.url
const token = store.state.user.token
/* if (!token) {
store.dispatch('user/getLocalUser')
} */
/* // 判断是否为第三方请求 比如阿里oss直传
if (url.indexOf('http') === 0) {
// console.log(config)
return config
} */
if (config.timeout === 0) {
config.timeout = 20000
}
// 头部请求添加token
if (token !== '') {
config.headers.token = token
}
config.headers.logUuid = httpUuid
// 安全策略配置
// config.withCredentials = true
// 拼接请求主域名
// config.url = DOMAIN + config.url
// config.responseType = 'json'
return config
},
err => {
// 日志上传参数
logData.logLevel = '1'
logData.logErrInfo = JSON.stringify(err)
logData.httpEndTime = new Date().getTime()
logData.httpDuration = logData.httpEndTime - logData.httpStartTime
// console.log(logData) // 调用原生上传日志方法
if (judge !== null) {
judge.uploadLog(logData)
}
// console.log(err)
return Promise.reject(err)
})
// 响应拦截器
service.interceptors.response.use(
response => {
// console.log(response)
// 日志上传参数
logData.repData = JSON.stringify(response.data)
logData.resultCode = response.status
logData.resultMsg = response.data.resultMessage
logData.httpEndTime = new Date().getTime()
logData.httpDuration = logData.httpEndTime - logData.httpStartTime
// console.log(logData) // 调用原生上传日志方法
if (judge !== null) {
judge.uploadLog(logData)
}
// 响应处理 如果响应code码为token失效那么返回至登录页
if (response.status === 200) {
switch (response.data.resultCode) {
case '0001':
router.replace({
path: '/login'
})
Toast(response.data.resultMessage)
return response.data
case '200':
return response.data
default:
if (response.data.resultMessage) {
Toast(response.data.resultMessage)
}
return response.data
}
}
},
error => {
// 日志上传参数
logData.logLevel = '1'
logData.logErrInfo = JSON.stringify(error)
logData.httpEndTime = new Date().getTime()
logData.httpDuration = logData.httpEndTime - logData.httpStartTime
// console.log(logData) // 调用原生上传日志方法
// console.log(JSON.stringify(error))
if (judge !== null) {
judge.uploadLog(logData)
}
if (error && error.response) {
switch (error.response.status) {
case 400: error.message = '请求错误(400)'; break
case 401: error.message = '未授权, 请重新登录(401)'; break
case 403: error.message = '拒绝访问(403)'; break
case 404: error.message = '请求出错(404)'; break
case 408: error.message = '请求超时(408)'; break
case 500: error.message = '服务器错误(500)'; break
case 501: error.message = '服务未实现(501)'; break
case 502: error.message = '网络错误(502)'; break
case 503: error.message = '服务不可用(503)'; break
case 504: error.message = '网络超时(504)'; break
case 505: error.message = 'HTTP版本不受支持(505)'; break
}
} else {
error.message = '网络异常,请稍后重试'
}
Toast(error.message)
// 响应错误拦截
return Promise.reject(error) // 返回接口返回的错误信息
})
export default service
// 判断设备
/**
* @function judge
* @returns {object} object
* @return {function} object.loginData 传登录后的数据
* @return {function} object.phone 打电话
* @return {function} object.clearCache 清除缓存
* @return {function} object.href 跳转到链接
* @return {function} object.dbNumber icon显示未读数
*/
let object = {}
isWeiXin()
if (window.android && !isWeiXin()) {
// 传登录后的数据
object.loginData = (data) => {
window.android.loginData(JSON.stringify(data))
}
// 打电话
object.phone = (phone) => {
// 这么调用的原因是因为 如果赋值给一个新的变量原生就无法监听了
window.android.phone(phone)
}
// 清理缓存
object.clearCache = () => {
window.android.clearCache()
}
// 跳转到链接
object.href = (url) => {
window.android.href(url)
}
// icon显示未读数
object.dbNumber = (number) => {
window.android.dbNumber(number)
}
// 下载图片
object.saveImg = () => {
window.android.saveImg()
}
// 点击立即升级 跳转页面
object.BeginUpgrade = (url) => {
window.android.BeginUpgrade(url)
}
// 无网络时,点击重新加载
object.noData = () => {
window.android.noData()
}
// 分享工单
object.shareGD = url => {
window.android.shareGD(url)
}
// 日志上传
object.uploadLog = (data) => {
window.android.uploadLog(JSON.stringify(data))
}
// 退出登录
object.quitLogin = () => {
window.android.quitLogin()
}
// 获取缓存文件
object.getCacheSize = () => {
window.android.getCacheSize()
}
} else if (window.webkit && !isWeiXin()) {
// 传登录后的数据
object.loginData = (data) => {
window.webkit.messageHandlers.loginData.postMessage(data)
}
// 打电话
object.phone = (phone) => {
// window.webkit.messageHandlers.phone.postMessage(phonephone)
window.webkit.messageHandlers.phone.postMessage(phone)
}
// 清理缓存
object.clearCache = () => {
window.webkit.messageHandlers.clearCache.postMessage(null)
}
// 跳转到链接
object.href = (url) => {
window.webkit.messageHandlers.href.postMessage(url)
}
// icon显示未读数
object.dbNumber = (number) => {
window.webkit.messageHandlers.dbNumber.postMessage(number)
}
// 下载图片
object.saveImg = () => {
window.webkit.messageHandlers.saveImg.postMessage(null)
}
// 点击立即升级 跳转页面
object.BeginUpgrade = (url) => {
window.webkit.messageHandlers.BeginUpgrade.postMessage(url)
}
// 无网络时,点击重新加载
object.noData = () => {
window.webkit.messageHandlers.noData.postMessage(null)
}
// 分享工单
object.shareGD = (url) => {
window.webkit.messageHandlers.shareGD.postMessage(url)
}
// 日志上传
object.uploadLog = (data) => {
window.webkit.messageHandlers.uploadLog.postMessage(data)
}
// 退出登录
object.quitLogin = () => {
window.webkit.messageHandlers.quitLogin.postMessage(null)
}
// 获取缓存
object.getCacheSize = () => {
window.webkit.messageHandlers.getCacheSize.postMessage(null)
}
} else {
// 怀疑android JS 注入有延迟
object = null
}
function isWeiXin () {
var ua = window.navigator.userAgent.toLowerCase()
if (ua.indexOf('micromessenger') !== -1) {
return true
} else {
return false
}
}
export default object
import Vue from 'vue'
//1.引入vue-router
import Router from 'vue-router'
import find from '../components/find'
import mall from '../components/mall'
import microshop from '../components/microshop'
import cloud from '../components/cloud'
import personalcenter from '../components/personalcenter'
//2.使用vue-router
Vue.use(Router)
//3.实例化router这个构造函数
let router = new Router({
//去掉地址中的哈希#
mode:"history",
//5.映射,什么样的地址跳转到什么样的page
routes:[
{
//根目录
path:'/',
name:'首页',
component:mall
},
{
//发现page
path:'/find',
name:'发现',
component:find
},
{
//微店page
path:'/microshop',
name:'购物袋',
component:microshop
},
{
//云仓page
path:'/cloud',
name:'云仓',
component:cloud
},
{
//我的page
path:'/personalcenter',
name:'我的',
component:personalcenter
}
]
});
//page跳转后title改变
router.afterEach(function (to) {
document.title = to.name
})
export default router
// import Msite from '../pages/Msite/Msite.vue'
// import Order from '../pages/Order/Order.vue'
// import Search from '../pages/Search/Search.vue'
// import Profile from '../pages/Profile/Profile.vue'
// 打包时进行代码分割, 只有当需要时才从后台请求获取
const Msite=()=>import('../pages/Msite/Msite.vue')
const Order=()=>import('../pages/Order/Order.vue')
const Search=()=>import('../pages/Search/Search.vue')
const Profile=()=>import('../pages/Profile/Profile.vue')
下载less和less-loader,在build中webpack.base.conf.js的module里配置
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
},
+ {
test: /\.less$/,
loader: ['style-loader','css-loader','less-loader'],
+ },
]
},
}
想控制哪个组件就在哪个组件上加 v-show="$route.meta.isShow"
在router/index中配置
routes: [
{
path: '/',
component: HelloWorld,
+ meta:{
isShow:true//默认为false显示,true为不显示
+ }
},
]
<template>
<footer class="footer_guide border-1px">
<a href="javascript:;" class="guide_item " :class="{on:$route.path==='/msite'}" @click="goTo('/msite')">
<span class="item_icon">
<i class="iconfont icon-waimai"></i>
</span>
<span>外卖</span>
</a>
<a href="javascript:;" class="guide_item" :class="{on:$route.path==='/search'}" @click="goTo('/search')">
<span class="item_icon">
<i class="iconfont icon-search"></i>
</span>
<span>搜索</span>
</a>
<a href="javascript:;" class="guide_item" :class="{on:$route.path==='/order'}" @click="goTo('/order')">
<span class="item_icon">
<i class="iconfont icon-dingdan"></i>
</span>
<span>订单</span>
</a>
<a href="javascript:;" class="guide_item" :class="{on:$route.path==='/profile'}" @click="goTo('/profile')">
<span class="item_icon">
<i class="iconfont icon-geren"></i>
</span>
<span>我的</span>
</a>
</footer>
</template>
1)methods里定义函数
methods:{
goTo(path){
this.$router.replace(path)
}
}
2)动态控制类名
.guide_item
display flex
flex 1
text-align center
flex-direction column
align-items center
margin 5px
color #999999
&.on
color #02a774
1)定义工具函数文件
/*
数据存储的工具模块
问题: 向外暴露一个函数(一个功能)还是一个对象(多个功能)?
*/
const TODOS_KEY='todos_key'
export default {
saveTodos(todos){//保存数据
window.localStorage.setItem(TODOS_KEY,JSON.stringify(todos))
},
readTodos(){
return JSON.parse(window.localStorage.getItem(TODOS_KEY)||'[]')
}
}
2)引入调用使用
App中读取
import storgeUtil from './util/storgeUtil'
export default{
data(){
return{
todos:storgeUtil.readTodos()
}
},
computed: {
completedCount () { // 完成的数量
return this.todos.reduce((preTotal, todo) => preTotal + (todo.completed?1:0), 0)
},