材质UI头像图片上传

Posted

技术标签:

【中文标题】材质UI头像图片上传【英文标题】:Material UI Avatar Image Upload 【发布时间】:2021-11-10 12:16:21 【问题描述】:

我设法制作了头像选择器,但我不知道如何在 Firebase 中保存图片,甚至不知道如何将其保存为个人资料图片。

看起来是这样的:

如果我点击按钮就会出现:

我可以选择一张图片,但它不会保存在任何地方,也不会在头像中显示图片。 我的代码:

function Profile(props, navigation) 
  const classes = useStyles();
  const user = useUser(props.route.params.uid);
  const [time, setTime] = useState("7:30");
  const [timing, setTiming] = useState([]);
  const [timeAfternoon, setTimeAfternoon] = useState("7:30");
  const [timingAfternoon, setTimingAfternoon] = useState([]);
  const [sickDaysStart, setSickDaysStart] = useState(Date.now());
  const [sickDaysEnd, setSickDaysEnd] = useState(Date.now());
  const [sickDaysConfirm, setSickDaysConfirm] = useState([]);
  const [donwloadURL, setDownloadURL] = useState([]);

  const onLogout = () => 
    firebase.auth().signOut();
  ;

  function handelSickDaysStart(e) 
    setSickDaysStart(e.target.value);
  
  function handelSickDaysEnd(e) 
    setSickDaysEnd(e.target.value);
  
  function handleTime(e) 
    setTime(e.target.value);
  
  function handleTimeAfternoon(e) 
    setTimeAfternoon(e.target.value);
  
  function delayMorning() 
    db.collection("delayInTheMorning")
      .doc()
      .set(
        time,
        user,
      )
      .then(() => 
        //If you wish to push the written data to your local state, you can do it here
        setTiming([...timing,  time ]);
        console.log("Documents saved succesfully");
      )
      .catch((err) => 
        console.log(err);
      );
  
  function delayAfternoon() 
    db.collection("delayInTheAfternoon")
      .doc()
      .set(
        timeAfternoon,
      )
      .then(() => 
        //If you wish to push the written data to your local state, you can do it here
        setTimingAfternoon([...timingAfternoon,  timeAfternoon ]);
        console.log("Documents saved succesfully");
      )
      .catch((err) => 
        console.log(err);
      );
  

  function sickDaysStartEnd() 
    db.collection("DaysofSickness")
      .doc()
      .set(
        sickDaysStart,
        sickDaysEnd,
        user,
      )
      .then(() => 
        //If you wish to push the written data to your local state, you can do it here
        setSickDaysConfirm([
          ...sickDaysConfirm,
           sickDaysStart, sickDaysEnd ,
        ]);
        console.log("Documents saved succesfully");
      )
      .catch((err) => 
        console.log(err);
      );
  

  function isCurrentUserProfile() 
    if (props.route.params.uid === firebase.auth().currentUser.uid) 
      return true;
     else 
      return false;
    
  
  async function handleFileInputChange(e) 
    const files = e.target.files;
    const file = files[0];

    const storage = firebase.storage();
    const usersImageRef = storage
      .ref()
      .child(`users/$user.uid/profilepicture.jpg`);

    const snap = await usersImageRef.put(file);

    const donwloadURL = await snap.ref.getDownloadURL();
    setDownloadURL(donwloadURL);

    await firebase.auth().currentUser.updateProfile( photoURL: donwloadURL );
  

  if (user === null) 
    return <div className=classes.root />;
  
  return (
    <ScrollView style=styles.root>
      <Container className=classes.div>
        <input
          accept="image/*"
          className=classes.input
          id="contained-button-file"
          multiple
          type="file"
          onChange=handleFileInputChange
        />
        <label>
          <IconButton>
            <Avatar
              src="../assets/ana.png"
              style=
                margin: "10px",
                width: "60px",
                height: "60px",
              
            />
          </IconButton>
        </label>
        <Typography className=classes.text> user.name </Typography>
        <Typography className=classes.text> user.email </Typography>

        isCurrentUserProfile() ? (
          <Button
            className=classes.btn
            size="large"
            variant="outlined"
            onClick=() => onLogout()
          >
            Logout
          </Button>
        ) : null
      </Container>
      <Card className=classes.div>
        /* //Verspätung */
        <CardContent className=classes.cardBackGround>
          <Typography variant="h5" className=classes.cardTyp>
            " "
            Verspätung" "
          </Typography>
          <Container className=classes.cardContainer>
            <TextField
              id="time"
              label="Zeit"
              type="time"
              defaultValue="07:30"
              InputLabelProps=
                shrink: true,
              
              inputProps=
                step: 300, // 5 min
              
              onChange=(value) => 
                handleTime(value);
              
            />
            <Button className=classes.cardBtn onClick=() => delayMorning()>
              Absenden
            </Button>
          </Container>
        </CardContent>

        /* //Krankenmledungen */
        <CardContent className=classes.cardBackGround>
          <Typography variant="h5" className=classes.cardTyp>
            Krankenmledungen
          </Typography>
          <Container className=classes.cardContainer>
            <TextField
              id="date"
              label="Von"
              type="date"
              defaultValue="2021-09-14"
              className=classes.textField
              InputLabelProps=
                shrink: true,
              
              onChange=(value) => 
                handelSickDaysStart(value);
              
            />

            <TextField
              id="date"
              label="bis"
              type="date"
              defaultValue="2021-09-20"
              className=classes.textField
              InputLabelProps=
                shrink: true,
              
              onChange=(value) => 
                handelSickDaysEnd(value);
              
            />
          </Container>
          <Button
            className=classes.cardBtnKM
            onClick=() => sickDaysStartEnd()
          >
            Absenden
          </Button>
        </CardContent>

        /* //Verspätung Abolung*/
        <CardContent className=classes.cardBackGround>
          <Typography variant="h5" className=classes.cardTyp>
            " "
            Verspätung Abholung
          </Typography>
          <Container className=classes.cardContainer>
            <TextField
              id="time"
              label="Zeit"
              type="time"
              defaultValue="07:30"
              InputLabelProps=
                shrink: true,
              
              inputProps=
                step: 300, // 5 min
              
              onChange=(value) => 
                handleTimeAfternoon(value);
              
            />
            <Button
              className=classes.cardBtn
              onClick=() => delayAfternoon()
            >
              Absenden
            </Button>
          </Container>
        </CardContent>
      </Card>

      /* <List> */
      /* Verspätungs Liste */
      timing.map((item) => 
        return (
          <List className=classes.lists>
            <ListItem className=classes.list1>
              <ListItemAvatar>
                <Avatar></Avatar>
              </ListItemAvatar>
              <ListItemText
                primary=user.name
                secondary=`Verspätung in der Früh $item.time`
              />
            </ListItem>
          </List>
        );
      )
      /* Krankmeldung */
      timingAfternoon.map((item) => 
        return (
          <List className=classes.lists>
            <ListItem className=classes.list>
              <ListItemAvatar>
                <Avatar></Avatar>
              </ListItemAvatar>
              <ListItemText
                primary=user.name
                secondary=`Verspätung bei der Abholung $item.timeAfternoon`
              />
            </ListItem>
          </List>
        );
      )
      /* Verspätungs Nachmittag */
      sickDaysConfirm.map((item) => 
        return (
          <List className=classes.lists>
            <ListItem className=classes.list>
              <ListItemAvatar>
                <Avatar></Avatar>
              </ListItemAvatar>
              <ListItemText
                primary=user.name
                secondary=`Krankmeldung von $item.sickDaysStart bis $item.sickDaysEnd`
              />
            </ListItem>
          </List>
        );
      )
    </ScrollView>
  );

还有一个来自 Expo 的 imagePicker,我想尝试一下,但我不确定。

【问题讨论】:

【参考方案1】:

如果您想更改用户的个人资料图片,可以使用此代码:

import  getAuth, updateProfile  from "firebase/auth";
const auth = getAuth();
updateProfile(auth.currentUser, 
  displayName: "User Name", photoURL: "https://example.com/jane-q-user/profile.jpg"
).then(() => 
  // Profile updated!
  // ...
).catch((error) => 
  // An error occurred
  // ...
);

你可以找到更多关于它的信息here。

要获取图片 URL,您需要将其上传到 Firebase 存储并获取 downloadURL

import  getStorage, ref, uploadBytes, getDownloadURL   from "firebase/storage";

const storage = getStorage();
const storageRef = ref(storage, 'some-child');

// 'file' comes from the Blob or File API
uploadBytes(storageRef, file).then((snapshot) => 
  console.log('Uploaded a blob or file!');
      getDownloadURL(snapshot.ref).then((downloadURL) => 
      console.log('File available at', downloadURL);
    );
);

我还将input 更改为没有multiple 文件可供选择。如果您愿意分享更多代码,我可以将这些代码 sn-ps 集成到您的代码中,以防您遇到问题。

更新:

这是整个示例。我看到你使用旧的 SDK,所以例子就是它:

function Profile(props, navigation) 
  const classes = useStyles();
  const user = useUser(props.route.params.uid);
  const delay = DayandTime();
  const [time, setTime] = useState("7:30");
  const [timing, setTiming] = useState([]);
  const [downloadurl, setDU] = useState("/images/example.jpg");
  const [timeAfternoon, setTimeAfternoon] = useState("7:30");
  const [timingAfternoon, setTimingAfternoon] = useState([]);
  const [sickDaysStart, setSickDaysStart] = useState(Date.now());
  const [sickDaysEnd, setSickDaysEnd] = useState(Date.now());
  const [sickDaysConfirm, setSickDaysConfirm] = useState([]);

  const onLogout = () => 
    firebase.auth().signOut();
  ;

  function handelSickDaysStart(e) 
    setSickDaysStart(e.target.value);
  
  function handelSickDaysEnd(e) 
    setSickDaysEnd(e.target.value);
  
  function handleTime(e) 
    setTime(e.target.value);
  
  function handleTimeAfternoon(e) 
    setTimeAfternoon(e.target.value);
  
  function delayMorning() 
    db.collection("delayInTheMorning")
      .doc()
      .set(
        time,
        user,
      )
      .then(() => 
        //If you wish to push the written data to your local state, you can do it here
        setTiming([...timing,  time ]);
        console.log("Documents saved succesfully");
      )
      .catch((err) => 
        console.log(err);
      );
  
  function delayAfternoon() 
    db.collection("delayInTheAfternoon")
      .doc()
      .set(
        timeAfternoon,
      )
      .then(() => 
        //If you wish to push the written data to your local state, you can do it here
        setTimingAfternoon([...timingAfternoon,  timeAfternoon ]);
        console.log("Documents saved succesfully");
      )
      .catch((err) => 
        console.log(err);
      );
  

  function sickDaysStartEnd() 
    db.collection("DaysofSickness")
      .doc()
      .set(
        sickDaysStart,
        sickDaysEnd,
        user,
      )
      .then(() => 
        //If you wish to push the written data to your local state, you can do it here
        setSickDaysConfirm([
          ...sickDaysConfirm,
           sickDaysStart, sickDaysEnd ,
        ]);
        console.log("Documents saved succesfully");
      )
      .catch((err) => 
        console.log(err);
      );
  

  function isCurrentUserProfile() 
    if (props.route.params.uid === firebase.auth().currentUser.uid) 
      return true;
     else 
      return false;
    
  

  if (user === null) 
    return <div className=classes.root />;
  

  async function handleFileInputChange(e) 
    const files = e.target.files;
    const file = files[0];

    const storage = firebase.storage();
    const usersImageRef = storage
      .ref()
      .child(`users/$user.uid/profilepicture.jpg`);

    const snap = await usersImageRef.put(file);

    const downloadURL = await snap.ref.getDownloadURL();
    setDU(downloadURL);

    await firebase.auth().updateProfile( photoURL: downloadURL );
  

  return (
    <ScrollView style=styles.root>
      <Container className=classes.div>
        <input
          accept="image/*"
          className=classes.input
          id="contained-button-file"
          multiple
          type="file"
          onChange=handleFileInputChange
        />
        <label htmlFor="contained-button-file">
          <IconButton>
            <Avatar
              src="/images/example.jpg"
              style=
                margin: "10px",
                width: "60px",
                height: "60px",
              
            />
          </IconButton>
        </label>
        <Typography className=classes.text> user.name </Typography>
        <Typography className=classes.text> user.email </Typography>

        isCurrentUserProfile() ? (
          <Button
            className=classes.btn
            size="large"
            variant="outlined"
            onClick=() => onLogout()
          >
            Logout
          </Button>
        ) : null
      </Container>
      <Card className=classes.div>
        /* //Verspätung */
        <CardContent>
          <Typography variant="h5" className=classes.cardTyp>
            " "
            Verspätung" "
          </Typography>
          <Container className=classes.cardContainer>
            <TextField
              id="time"
              label="Zeit"
              type="time"
              defaultValue="07:30"
              InputLabelProps=
                shrink: true,
              
              inputProps=
                step: 300, // 5 min
              
              onChange=(value) => 
                handleTime(value);
              
            />
            <Button className=classes.cardBtn onClick=() => delayMorning()>
              Absenden
            </Button>
          </Container>
        </CardContent>

        /* //Krankenmledungen */
        <CardContent className=classes.cardKrankmeldung>
          <Typography variant="h5" className=classes.cardTyp>
            " "
            Krankenmledungen" "
          </Typography>
          <Container className=classes.cardContainer>
            <TextField
              id="date"
              label="Von"
              type="date"
              defaultValue="2021-09-14"
              className=classes.textField
              InputLabelProps=
                shrink: true,
              
              onChange=(value) => 
                handelSickDaysStart(value);
              
            />

            <TextField
              id="date"
              label="bis"
              type="date"
              defaultValue="2021-09-20"
              className=classes.textField
              InputLabelProps=
                shrink: true,
              
              onChange=(value) => 
                handelSickDaysEnd(value);
              
            />
          </Container>
          <Button
            className=classes.cardBtnKM
            onClick=() => sickDaysStartEnd()
          >
            Absenden
          </Button>
        </CardContent>

        /* //Verspätung Abolung*/
        <CardContent>
          <Typography variant="h5" className=classes.cardTyp>
            " "
            Verspätung Abholung
          </Typography>
          <Container className=classes.cardContainer>
            <TextField
              id="time"
              label="Zeit"
              type="time"
              defaultValue="07:30"
              InputLabelProps=
                shrink: true,
              
              inputProps=
                step: 300, // 5 min
              
              onChange=(value) => 
                handleTimeAfternoon(value);
              
            />
            <Button
              className=classes.cardBtn
              onClick=() => delayAfternoon()
            >
              Absenden
            </Button>
          </Container>
        </CardContent>
      </Card>

      <List>
        /* Verspätungs Liste */
        <ListItem>
          <ListItemAvatar>
            <Avatar></Avatar>
          </ListItemAvatar>
          <ListItemText
            primary=user.name
            secondary=`Verspätung in der Früh $delay`
          />
        </ListItem>
        /* Verspätungs Krankmeldung */
        <ListItem>
          <ListItemAvatar>
            <Avatar></Avatar>
          </ListItemAvatar>
          <ListItemText
            primary=user.name
            secondary=`Krankmeldung  $delay`
          />
        </ListItem>
        /* Verspätungs Nachmittag */
        <ListItem>
          <ListItemAvatar>
            <Avatar></Avatar>
          </ListItemAvatar>
          <ListItemText
            primary=user.name
            secondary=`Verspätung Nachmittag  $delay`
          />
        </ListItem>
      </List>
    </ScrollView>
  );


const mapStateToProps = (store) => (
  currentUser: store.userState.currentUser,
  posts: store.userState.posts,
  following: store.userState.following,
);

export default connect(mapStateToProps, null)(Profile);

const useStyles = makeStyles(
  root: 
    backgroundColor: "white",
  ,
  div: 
    marginTop: 20,
    marginLeft: 15,
    marginRight: 15,
    backgroundColor: "white",
  ,
  avatar: 
    marginBottom: 10,
  ,
  btn: 
    marginTop: 10,
    width: 250,
    marginBottom: 30,
  ,
  text: 
    fontSize: 25,
    marginTop: 10,
  ,
  cardTyp: 
    textAlign: "left",
    paddingLeft: 13,
  ,
  cardBtn: 
    marginTop: 20,
    marginLeft: 30,
  ,
  cardBtnKM: 
    marginTop: 20,
    marginLeft: 10,
  ,
  cardContainer: 
    display: "flex",
  ,
);

const styles = StyleSheet.create(
  root: 
    backgroundColor: "white",
  ,
);

【讨论】:

嘿@Tarik 谢谢!如果您能提供帮助,我会更新整个代码,因为我想我可以自己实现它,但我太不确定了。 我已经用整个代码更新了答案。 谢谢,但我收到一条错误消息:''Unhandled Rejection (TypeError): snap.getDownloadURL is not a function'' 我已经更新了代码。应该是snap.ref.get... 您好@Tarik,我尝试自己解决,但仍然出现错误:Profile.js:135 Uncaught (in promise) ReferenceError: setDownloadURL is not defined

以上是关于材质UI头像图片上传的主要内容,如果未能解决你的问题,请参考以下文章

完美实现类似QQ的自拍头像上传头像功能!(Demo 源码)

图片上传,头像上传

相册选择头像或者拍照 上传头像以NSData 图片二进制格式 表单上传

微信换头像显示上传失败怎么办

apicloud图片上传

QQ上传不了头像 老是显示上传失败